1b4d9ac8bSUtkarsh Saxena // RUN: %check_clang_tidy -std=c++17-or-later %s bugprone-easily-swappable-parameters %t \
2*e8a3ddafSNathan James // RUN: -config='{CheckOptions: { \
3*e8a3ddafSNathan James // RUN: bugprone-easily-swappable-parameters.MinimumLength: 2, \
4*e8a3ddafSNathan James // RUN: bugprone-easily-swappable-parameters.IgnoredParameterNames: "", \
5*e8a3ddafSNathan James // RUN: bugprone-easily-swappable-parameters.IgnoredParameterTypeSuffixes: "", \
6*e8a3ddafSNathan James // RUN: bugprone-easily-swappable-parameters.QualifiersMix: 0, \
7*e8a3ddafSNathan James // RUN: bugprone-easily-swappable-parameters.ModelImplicitConversions: 1, \
8*e8a3ddafSNathan James // RUN: bugprone-easily-swappable-parameters.SuppressParametersUsedTogether: 0, \
9*e8a3ddafSNathan James // RUN: bugprone-easily-swappable-parameters.NamePrefixSuffixSilenceDissimilarityTreshold: 0 \
10*e8a3ddafSNathan James // RUN: }}' --
1189a1d03eSRichard
implicitDoesntBreakOtherStuff(int A,int B)1289a1d03eSRichard void implicitDoesntBreakOtherStuff(int A, int B) {}
1389a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:36: warning: 2 adjacent parameters of 'implicitDoesntBreakOtherStuff' of similar type ('int') are easily swapped by mistake [bugprone-easily-swappable-parameters]
1489a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-2]]:40: note: the first parameter in the range is 'A'
1589a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-3]]:47: note: the last parameter in the range is 'B'
1689a1d03eSRichard
arrayAndPtr1(int * IP,int IA[])1789a1d03eSRichard void arrayAndPtr1(int *IP, int IA[]) { arrayAndPtr1(IA, IP); }
1889a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: 2 adjacent parameters of 'arrayAndPtr1' of similar type ('int *')
1989a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-2]]:24: note: the first parameter in the range is 'IP'
2089a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-3]]:32: note: the last parameter in the range is 'IA'
2189a1d03eSRichard
arrayAndPtr2(int * IP,int IA[8])2289a1d03eSRichard void arrayAndPtr2(int *IP, int IA[8]) { arrayAndPtr2(IA, IP); }
2389a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: 2 adjacent parameters of 'arrayAndPtr2' of similar type ('int *')
2489a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-2]]:24: note: the first parameter in the range is 'IP'
2589a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-3]]:32: note: the last parameter in the range is 'IA'
2689a1d03eSRichard
arrayAndElement(int I,int IA[])2789a1d03eSRichard void arrayAndElement(int I, int IA[]) {} // NO-WARN.
2889a1d03eSRichard
2989a1d03eSRichard typedef int Point2D[2];
3089a1d03eSRichard typedef int Point3D[3];
3189a1d03eSRichard
arrays1(Point2D P2D,Point3D P3D)3289a1d03eSRichard void arrays1(Point2D P2D, Point3D P3D) {} // In reality this is (int*, int*).
3389a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: 2 adjacent parameters of 'arrays1' of similar type ('int *') are
3489a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-2]]:22: note: the first parameter in the range is 'P2D'
3589a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-3]]:35: note: the last parameter in the range is 'P3D'
3689a1d03eSRichard
crefToArrayTypedef1(int I,const Point2D & P)3789a1d03eSRichard void crefToArrayTypedef1(int I, const Point2D &P) {}
3889a1d03eSRichard // NO-WARN.
3989a1d03eSRichard
crefToArrayTypedef2(int * IA,const Point2D & P)4089a1d03eSRichard void crefToArrayTypedef2(int *IA, const Point2D &P) {}
4189a1d03eSRichard // NO-WARN.
4289a1d03eSRichard
crefToArrayTypedef3(int P1[2],const Point2D & P)4389a1d03eSRichard void crefToArrayTypedef3(int P1[2], const Point2D &P) {}
4489a1d03eSRichard // NO-WARN.
4589a1d03eSRichard
crefToArrayTypedefBoth1(const Point2D & VecDescartes,const Point3D & VecThreeD)4689a1d03eSRichard void crefToArrayTypedefBoth1(const Point2D &VecDescartes, const Point3D &VecThreeD) {}
4789a1d03eSRichard // NO-WARN: Distinct types.
4889a1d03eSRichard
4989a1d03eSRichard template <int N, int M>
templatedArrayRef(int (& Array1)[N],int (& Array2)[M])5089a1d03eSRichard void templatedArrayRef(int (&Array1)[N], int (&Array2)[M]) {}
5189a1d03eSRichard // NO-WARN: Distinct template types in the primary template.
5289a1d03eSRichard
templatedArrayRefTest()5389a1d03eSRichard void templatedArrayRefTest() {
5489a1d03eSRichard int Foo[12], Bar[12];
5589a1d03eSRichard templatedArrayRef(Foo, Bar);
5689a1d03eSRichard
5789a1d03eSRichard int Baz[12], Quux[42];
5889a1d03eSRichard templatedArrayRef(Baz, Quux);
5989a1d03eSRichard
6089a1d03eSRichard // NO-WARN: Implicit instantiations are not checked.
6189a1d03eSRichard }
6289a1d03eSRichard
6389a1d03eSRichard template <>
templatedArrayRef(int (& Array1)[8],int (& Array2)[8])6489a1d03eSRichard void templatedArrayRef(int (&Array1)[8], int (&Array2)[8]) { templatedArrayRef(Array2, Array1); }
6589a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: 2 adjacent parameters of 'templatedArrayRef<8, 8>' of similar type ('int (&)[8]') are
6689a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-2]]:30: note: the first parameter in the range is 'Array1'
6789a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-3]]:48: note: the last parameter in the range is 'Array2'
6889a1d03eSRichard
6989a1d03eSRichard template <>
templatedArrayRef(int (& Array1)[16],int (& Array2)[24])7089a1d03eSRichard void templatedArrayRef(int (&Array1)[16], int (&Array2)[24]) {}
7189a1d03eSRichard // NO-WARN: Not the same type.
7289a1d03eSRichard
numericConversion1(int I,double D)7389a1d03eSRichard void numericConversion1(int I, double D) { numericConversion1(D, I); }
7489a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: 2 adjacent parameters of 'numericConversion1' of convertible types are easily swapped by mistake [bugprone-easily-swappable-parameters]
7589a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-2]]:29: note: the first parameter in the range is 'I'
7689a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-3]]:39: note: the last parameter in the range is 'D'
7789a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-4]]:32: note: 'int' and 'double' may be implicitly converted{{$}}
7889a1d03eSRichard
numericConversion2(int I,short S)7989a1d03eSRichard void numericConversion2(int I, short S) { numericConversion2(S, I); }
8089a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: 2 adjacent parameters of 'numericConversion2' of convertible types
8189a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-2]]:29: note: the first parameter in the range is 'I'
8289a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-3]]:38: note: the last parameter in the range is 'S'
8389a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-4]]:32: note: 'int' and 'short' may be implicitly converted{{$}}
8489a1d03eSRichard
numericConversion3(float F,unsigned long long ULL)8589a1d03eSRichard void numericConversion3(float F, unsigned long long ULL) { numericConversion3(ULL, F); }
8689a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: 2 adjacent parameters of 'numericConversion3' of convertible types
8789a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-2]]:31: note: the first parameter in the range is 'F'
8889a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-3]]:53: note: the last parameter in the range is 'ULL'
8989a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-4]]:34: note: 'float' and 'unsigned long long' may be implicitly converted{{$}}
9089a1d03eSRichard
9189a1d03eSRichard enum Unscoped { U_A,
9289a1d03eSRichard U_B };
9389a1d03eSRichard enum UnscopedFixed : char { UF_A,
9489a1d03eSRichard UF_B };
9589a1d03eSRichard enum struct Scoped { A,
9689a1d03eSRichard B };
9789a1d03eSRichard
numericConversion4(int I,Unscoped U)9889a1d03eSRichard void numericConversion4(int I, Unscoped U) {} // NO-WARN.
9989a1d03eSRichard
numericConversion5(int I,UnscopedFixed UF)10089a1d03eSRichard void numericConversion5(int I, UnscopedFixed UF) {} // NO-WARN.
10189a1d03eSRichard
numericConversion6(int I,Scoped S)10289a1d03eSRichard void numericConversion6(int I, Scoped S) {} // NO-WARN.
10389a1d03eSRichard
numericConversion7(double D,Unscoped U)10489a1d03eSRichard void numericConversion7(double D, Unscoped U) {} // NO-WARN.
10589a1d03eSRichard
numericConversion8(double D,UnscopedFixed UF)10689a1d03eSRichard void numericConversion8(double D, UnscopedFixed UF) {} // NO-WARN.
10789a1d03eSRichard
numericConversion9(double D,Scoped S)10889a1d03eSRichard void numericConversion9(double D, Scoped S) {} // NO-WARN.
10989a1d03eSRichard
numericConversionMultiUnique(int I,double D1,double D2)11089a1d03eSRichard void numericConversionMultiUnique(int I, double D1, double D2) {}
11189a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: 3 adjacent parameters of 'numericConversionMultiUnique' of convertible types
11289a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-2]]:39: note: the first parameter in the range is 'I'
11389a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-3]]:60: note: the last parameter in the range is 'D2'
11489a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-4]]:42: note: 'int' and 'double' may be implicitly converted{{$}}
11589a1d03eSRichard // (Note: int<->double conversion for I<->D2 not diagnosed again.)
11689a1d03eSRichard
11789a1d03eSRichard typedef int MyInt;
11889a1d03eSRichard using MyDouble = double;
11989a1d03eSRichard
numericConversion10(MyInt MI,MyDouble MD)12089a1d03eSRichard void numericConversion10(MyInt MI, MyDouble MD) { numericConversion10(MD, MI); }
12189a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: 2 adjacent parameters of 'numericConversion10' of convertible types
12289a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-2]]:32: note: the first parameter in the range is 'MI'
12389a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-3]]:45: note: the last parameter in the range is 'MD'
12489a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-4]]:36: note: 'MyInt' and 'MyDouble' may be implicitly converted: 'MyInt' (as 'int') -> 'MyDouble' (as 'double'), 'MyDouble' (as 'double') -> 'MyInt' (as 'int')
12589a1d03eSRichard
numericAndQualifierConversion(int I,const double CD)12689a1d03eSRichard void numericAndQualifierConversion(int I, const double CD) { numericAndQualifierConversion(CD, I); }
12789a1d03eSRichard // NO-WARN: Qualifier mixing is handled by a different check option.
12889a1d03eSRichard
12989a1d03eSRichard struct FromInt {
13089a1d03eSRichard FromInt(int);
13189a1d03eSRichard };
13289a1d03eSRichard
oneWayConversion1(int I,FromInt FI)13389a1d03eSRichard void oneWayConversion1(int I, FromInt FI) {} // NO-WARN: One-way.
13489a1d03eSRichard
13589a1d03eSRichard struct AmbiguousConvCtor {
13689a1d03eSRichard AmbiguousConvCtor(int);
13789a1d03eSRichard AmbiguousConvCtor(double);
13889a1d03eSRichard };
13989a1d03eSRichard
ambiguous1(long L,AmbiguousConvCtor ACC)14089a1d03eSRichard void ambiguous1(long L, AmbiguousConvCtor ACC) {} // NO-WARN: Ambiguous, one-way.
14189a1d03eSRichard
14289a1d03eSRichard struct ToInt {
14389a1d03eSRichard operator int() const;
14489a1d03eSRichard };
14589a1d03eSRichard
oneWayConversion2(ToInt TI,int I)14689a1d03eSRichard void oneWayConversion2(ToInt TI, int I) {} // NO-WARN: One-way.
14789a1d03eSRichard
14889a1d03eSRichard struct AmbiguousConvOp {
14989a1d03eSRichard operator int() const;
15089a1d03eSRichard operator double() const;
15189a1d03eSRichard };
15289a1d03eSRichard
ambiguous2(AmbiguousConvOp ACO,long L)15389a1d03eSRichard void ambiguous2(AmbiguousConvOp ACO, long L) {} // NO-WARN: Ambiguous, one-way.
15489a1d03eSRichard
15589a1d03eSRichard struct AmbiguousEverything1;
15689a1d03eSRichard struct AmbiguousEverything2;
15789a1d03eSRichard struct AmbiguousEverything1 {
15889a1d03eSRichard AmbiguousEverything1();
15989a1d03eSRichard AmbiguousEverything1(AmbiguousEverything2);
16089a1d03eSRichard operator AmbiguousEverything2() const;
16189a1d03eSRichard };
16289a1d03eSRichard struct AmbiguousEverything2 {
16389a1d03eSRichard AmbiguousEverything2();
16489a1d03eSRichard AmbiguousEverything2(AmbiguousEverything1);
16589a1d03eSRichard operator AmbiguousEverything1() const;
16689a1d03eSRichard };
16789a1d03eSRichard
ambiguous3(AmbiguousEverything1 AE1,AmbiguousEverything2 AE2)16889a1d03eSRichard void ambiguous3(AmbiguousEverything1 AE1, AmbiguousEverything2 AE2) {} // NO-WARN: Ambiguous.
16989a1d03eSRichard
17089a1d03eSRichard struct Integer {
17189a1d03eSRichard Integer(int);
17289a1d03eSRichard operator int() const;
17389a1d03eSRichard };
17489a1d03eSRichard
userDefinedConversion1(int I1,Integer I2)17589a1d03eSRichard void userDefinedConversion1(int I1, Integer I2) { userDefinedConversion1(I2, I1); }
17689a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: 2 adjacent parameters of 'userDefinedConversion1' of convertible types
17789a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-2]]:33: note: the first parameter in the range is 'I1'
17889a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-3]]:45: note: the last parameter in the range is 'I2'
17989a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-4]]:37: note: 'int' and 'Integer' may be implicitly converted{{$}}
18089a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-9]]:3: note: the implicit conversion involves the converting constructor declared here
18189a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-9]]:3: note: the implicit conversion involves the conversion operator declared here
18289a1d03eSRichard
18389a1d03eSRichard struct Ambiguous {
18489a1d03eSRichard Ambiguous(int);
18589a1d03eSRichard Ambiguous(double);
18689a1d03eSRichard operator long() const;
18789a1d03eSRichard operator float() const;
18889a1d03eSRichard };
18989a1d03eSRichard
ambiguous3(char C,Ambiguous A)19089a1d03eSRichard void ambiguous3(char C, Ambiguous A) {} // NO-WARN: Ambiguous.
19189a1d03eSRichard
19289a1d03eSRichard struct CDouble {
19389a1d03eSRichard CDouble(const double &);
19489a1d03eSRichard operator const double &() const;
19589a1d03eSRichard };
19689a1d03eSRichard
userDefinedConversion2(double D,CDouble CD)19789a1d03eSRichard void userDefinedConversion2(double D, CDouble CD) { userDefinedConversion2(CD, D); }
19889a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: 2 adjacent parameters of 'userDefinedConversion2' of convertible types
19989a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-2]]:36: note: the first parameter in the range is 'D'
20089a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-3]]:47: note: the last parameter in the range is 'CD'
20189a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-4]]:39: note: 'double' and 'CDouble' may be implicitly converted: 'double' -> 'const double &' -> 'CDouble', 'CDouble' -> 'const double &' -> 'double'
20289a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-9]]:3: note: the implicit conversion involves the converting constructor declared here
20389a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-9]]:3: note: the implicit conversion involves the conversion operator declared here
20489a1d03eSRichard
userDefinedConversion3(int I,CDouble CD)20589a1d03eSRichard void userDefinedConversion3(int I, CDouble CD) { userDefinedConversion3(CD, I); }
20689a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: 2 adjacent parameters of 'userDefinedConversion3' of convertible types
20789a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-2]]:33: note: the first parameter in the range is 'I'
20889a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-3]]:44: note: the last parameter in the range is 'CD'
20989a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-4]]:36: note: 'int' and 'CDouble' may be implicitly converted: 'int' -> 'double' -> 'const double &' -> 'CDouble', 'CDouble' -> 'const double &' -> 'int'
21089a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-17]]:3: note: the implicit conversion involves the converting constructor declared here
21189a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-17]]:3: note: the implicit conversion involves the conversion operator declared here
21289a1d03eSRichard
21389a1d03eSRichard struct TDInt {
21489a1d03eSRichard TDInt(const MyInt &);
21589a1d03eSRichard operator MyInt() const;
21689a1d03eSRichard };
21789a1d03eSRichard
userDefinedConversion4(int I,TDInt TDI)21889a1d03eSRichard void userDefinedConversion4(int I, TDInt TDI) { userDefinedConversion4(TDI, I); }
21989a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: 2 adjacent parameters of 'userDefinedConversion4' of convertible types
22089a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-2]]:33: note: the first parameter in the range is 'I'
22189a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-3]]:42: note: the last parameter in the range is 'TDI'
22289a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-4]]:36: note: 'int' and 'TDInt' may be implicitly converted: 'int' -> 'const MyInt &' -> 'TDInt', 'TDInt' -> 'MyInt' -> 'int'
22389a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-9]]:3: note: the implicit conversion involves the converting constructor declared here
22489a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-9]]:3: note: the implicit conversion involves the conversion operator declared here
22589a1d03eSRichard
22689a1d03eSRichard struct TDIntDouble {
22789a1d03eSRichard TDIntDouble(const MyInt &);
22889a1d03eSRichard TDIntDouble(const MyDouble &);
22989a1d03eSRichard operator MyInt() const;
23089a1d03eSRichard operator MyDouble() const;
23189a1d03eSRichard };
23289a1d03eSRichard
userDefinedConversion5(int I,TDIntDouble TDID)23389a1d03eSRichard void userDefinedConversion5(int I, TDIntDouble TDID) { userDefinedConversion5(TDID, I); }
23489a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: 2 adjacent parameters of 'userDefinedConversion5' of convertible types
23589a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-2]]:33: note: the first parameter in the range is 'I'
23689a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-3]]:48: note: the last parameter in the range is 'TDID'
23789a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-4]]:36: note: 'int' and 'TDIntDouble' may be implicitly converted: 'int' -> 'const MyInt &' -> 'TDIntDouble', 'TDIntDouble' -> 'MyInt' -> 'int'
23889a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-11]]:3: note: the implicit conversion involves the converting constructor declared here
23989a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-10]]:3: note: the implicit conversion involves the conversion operator declared here
24089a1d03eSRichard
userDefinedConversion6(double D,TDIntDouble TDID)24189a1d03eSRichard void userDefinedConversion6(double D, TDIntDouble TDID) { userDefinedConversion6(TDID, D); }
24289a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: 2 adjacent parameters of 'userDefinedConversion6' of convertible types
24389a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-2]]:36: note: the first parameter in the range is 'D'
24489a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-3]]:51: note: the last parameter in the range is 'TDID'
24589a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-4]]:39: note: 'double' and 'TDIntDouble' may be implicitly converted: 'double' -> 'const MyDouble &' -> 'TDIntDouble', 'TDIntDouble' -> 'MyDouble' -> 'double'
24689a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-18]]:3: note: the implicit conversion involves the converting constructor declared here
24789a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-17]]:3: note: the implicit conversion involves the conversion operator declared here
24889a1d03eSRichard
userDefinedConversion7(char C,TDIntDouble TDID)24989a1d03eSRichard void userDefinedConversion7(char C, TDIntDouble TDID) {} // NO-WARN: Ambiguous.
25089a1d03eSRichard
25189a1d03eSRichard struct Forward1;
25289a1d03eSRichard struct Forward2;
25389a1d03eSRichard
incomplete(Forward1 * F1,Forward2 * F2)25489a1d03eSRichard void incomplete(Forward1 *F1, Forward2 *F2) {} // NO-WARN: Do not compare incomplete types.
25589a1d03eSRichard
pointeeConverison(int * IP,double * DP)25689a1d03eSRichard void pointeeConverison(int *IP, double *DP) {} // NO-WARN.
25789a1d03eSRichard
pointerConversion1(void * VP,int * IP)25889a1d03eSRichard void pointerConversion1(void *VP, int *IP) {} // NO-WARN: One-way.
25989a1d03eSRichard
26089a1d03eSRichard struct PointerBox {
26189a1d03eSRichard PointerBox(void *);
26289a1d03eSRichard operator int *() const;
26389a1d03eSRichard };
26489a1d03eSRichard
pointerConversion2(PointerBox PB,int * IP)26589a1d03eSRichard void pointerConversion2(PointerBox PB, int *IP) { pointerConversion2(IP, PB); }
26689a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: 2 adjacent parameters of 'pointerConversion2' of convertible types
26789a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-2]]:36: note: the first parameter in the range is 'PB'
26889a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-3]]:45: note: the last parameter in the range is 'IP'
26989a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-4]]:40: note: 'PointerBox' and 'int *' may be implicitly converted: 'PointerBox' -> 'int *', 'int *' -> 'void *' -> 'PointerBox'
27089a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-8]]:3: note: the implicit conversion involves the conversion operator declared here
27189a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-10]]:3: note: the implicit conversion involves the converting constructor declared here
27289a1d03eSRichard
pointerConversion3(PointerBox PB,double * DP)27389a1d03eSRichard void pointerConversion3(PointerBox PB, double *DP) {} // NO-WARN: Not convertible.
27489a1d03eSRichard
27589a1d03eSRichard struct Base {};
27689a1d03eSRichard struct Derived : Base {};
27789a1d03eSRichard
pointerConversion4(Base * BP,Derived * DP)27889a1d03eSRichard void pointerConversion4(Base *BP, Derived *DP) {} // NO-WARN: One-way.
27989a1d03eSRichard
28089a1d03eSRichard struct BaseAndDerivedInverter {
28189a1d03eSRichard BaseAndDerivedInverter(Base); // Takes a Base
28289a1d03eSRichard operator Derived() const; // and becomes a Derived.
28389a1d03eSRichard };
28489a1d03eSRichard
pointerConversion5(BaseAndDerivedInverter BADI,Derived D)28589a1d03eSRichard void pointerConversion5(BaseAndDerivedInverter BADI, Derived D) { pointerConversion5(D, BADI); }
28689a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: 2 adjacent parameters of 'pointerConversion5' of convertible types
28789a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-2]]:48: note: the first parameter in the range is 'BADI'
28889a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-3]]:62: note: the last parameter in the range is 'D'
28989a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-4]]:54: note: 'BaseAndDerivedInverter' and 'Derived' may be implicitly converted: 'BaseAndDerivedInverter' -> 'Derived', 'Derived' -> 'Base' -> 'BaseAndDerivedInverter'
29089a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-8]]:3: note: the implicit conversion involves the conversion operator declared here
29189a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-10]]:3: note: the implicit conversion involves the converting constructor declared here
29289a1d03eSRichard
pointerConversion6(void (* NTF)()noexcept,void (* TF)())29389a1d03eSRichard void pointerConversion6(void (*NTF)() noexcept, void (*TF)()) {}
29489a1d03eSRichard // NO-WARN: This call cannot be swapped, even if "getCanonicalType()" believes otherwise.
29589a1d03eSRichard
29689a1d03eSRichard using NonThrowingFunction = void (*)() noexcept;
29789a1d03eSRichard
29889a1d03eSRichard struct NoexceptMaker {
29989a1d03eSRichard NoexceptMaker(void (*ThrowingFunction)());
30089a1d03eSRichard // Need to use a typedef here because
30189a1d03eSRichard // "conversion function cannot convert to a function type".
30289a1d03eSRichard // operator (void (*)() noexcept) () const;
30389a1d03eSRichard operator NonThrowingFunction() const;
30489a1d03eSRichard };
30589a1d03eSRichard
pointerConversion7(void (* NTF)()noexcept,NoexceptMaker NM)30689a1d03eSRichard void pointerConversion7(void (*NTF)() noexcept, NoexceptMaker NM) { pointerConversion7(NM, NTF); }
30789a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: 2 adjacent parameters of 'pointerConversion7' of convertible types
30889a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-2]]:32: note: the first parameter in the range is 'NTF'
30989a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-3]]:63: note: the last parameter in the range is 'NM'
31089a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-4]]:49: note: 'void (*)() noexcept' and 'NoexceptMaker' may be implicitly converted: 'void (*)() noexcept' -> 'void (*)()' -> 'NoexceptMaker', 'NoexceptMaker' -> 'NonThrowingFunction' -> 'void (*)() noexcept'
31189a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-12]]:3: note: the implicit conversion involves the converting constructor declared here
31289a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-9]]:3: note: the implicit conversion involves the conversion operator declared here
31389a1d03eSRichard
31489a1d03eSRichard struct ToType;
31589a1d03eSRichard struct MiddleStep1 {
31689a1d03eSRichard operator ToType() const;
31789a1d03eSRichard };
31889a1d03eSRichard struct FromType {
31989a1d03eSRichard operator MiddleStep1() const;
32089a1d03eSRichard };
32189a1d03eSRichard struct MiddleStep2 {
32289a1d03eSRichard operator FromType() const;
32389a1d03eSRichard };
32489a1d03eSRichard struct ToType {
32589a1d03eSRichard operator MiddleStep2() const;
32689a1d03eSRichard };
32789a1d03eSRichard
f(FromType F,ToType T)32889a1d03eSRichard void f(FromType F, ToType T) { // NO-WARN: The path takes two steps.
32989a1d03eSRichard MiddleStep2 MS2 = T;
33089a1d03eSRichard FromType F2 = MS2;
33189a1d03eSRichard
33289a1d03eSRichard MiddleStep1 MS1 = F;
33389a1d03eSRichard ToType T2 = MS1;
33489a1d03eSRichard
33589a1d03eSRichard f(F2, T2);
33689a1d03eSRichard }
33789a1d03eSRichard
33889a1d03eSRichard // Synthesised example from OpenCV.
33989a1d03eSRichard template <typename T>
34089a1d03eSRichard struct TemplateConversion {
34189a1d03eSRichard template <typename T2>
34289a1d03eSRichard operator TemplateConversion<T2>() const;
34389a1d03eSRichard };
34489a1d03eSRichard using IntConverter = TemplateConversion<int>;
34589a1d03eSRichard using FloatConverter = TemplateConversion<float>;
34689a1d03eSRichard
templateConversion(IntConverter IC,FloatConverter FC)34789a1d03eSRichard void templateConversion(IntConverter IC, FloatConverter FC) { templateConversion(FC, IC); }
34889a1d03eSRichard // Note: even though this swap is possible, we do not model things when it comes to "template magic".
34989a1d03eSRichard // But at least the check should not crash!
350