mizvekov updated this revision to Diff 374921. mizvekov added a comment. update print-type.cpp test.
Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D110216/new/ https://reviews.llvm.org/D110216 Files: clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.cpp clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.cpp clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp clang-tools-extra/clangd/FindTarget.cpp clang-tools-extra/clangd/unittests/ASTTests.cpp clang-tools-extra/clangd/unittests/HoverTests.cpp clang-tools-extra/clangd/unittests/InlayHintTests.cpp clang-tools-extra/clangd/unittests/tweaks/ExpandAutoTypeTests.cpp clang-tools-extra/test/clang-tidy/checkers/cert-static-object-exception.cpp clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-owning-memory.cpp clang/include/clang/AST/ASTContext.h clang/include/clang/AST/Type.h clang/include/clang/Sema/Sema.h clang/lib/AST/ASTContext.cpp clang/lib/AST/ASTImporter.cpp clang/lib/AST/Type.cpp clang/lib/Sema/SemaCXXScopeSpec.cpp clang/lib/Sema/SemaDecl.cpp clang/lib/Sema/SemaDeclCXX.cpp clang/lib/Sema/SemaExprCXX.cpp clang/lib/Sema/SemaInit.cpp clang/lib/Sema/SemaLambda.cpp clang/lib/Sema/SemaStmt.cpp clang/lib/Sema/SemaTemplate.cpp clang/lib/Sema/SemaTemplateDeduction.cpp clang/lib/Sema/SemaType.cpp clang/lib/Sema/TreeTransform.h clang/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp clang/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp clang/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p1-0x.cpp clang/test/Index/print-type.cpp clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp clang/test/SemaCXX/cxx1z-decomposition.cpp clang/test/SemaCXX/deduced-return-type-cxx14.cpp clang/test/SemaCXX/friend.cpp clang/test/SemaCXX/recovery-expr-type.cpp clang/test/SemaCXX/sizeless-1.cpp clang/test/SemaCXX/sugared-auto.cpp clang/test/SemaTemplate/attributes.cpp clang/test/SemaTemplate/friend.cpp clang/test/SemaTemplate/operator-template.cpp clang/unittests/AST/ASTImporterTest.cpp
Index: clang/unittests/AST/ASTImporterTest.cpp =================================================================== --- clang/unittests/AST/ASTImporterTest.cpp +++ clang/unittests/AST/ASTImporterTest.cpp @@ -6176,26 +6176,9 @@ FirstDeclMatcher<FunctionDecl>().match(FromTU, functionDecl()); FunctionDecl *To = Import(From, Lang_CXX14); - EXPECT_TRUE(To); - EXPECT_TRUE(isa<AutoType>(To->getReturnType())); -} - -TEST_P(ImportAutoFunctions, ReturnWithStructDeclaredInside2) { - Decl *FromTU = getTuDecl( - R"( - auto foo() { - struct X {}; - return X(); - } - )", - Lang_CXX14, "input0.cc"); - FunctionDecl *From = - FirstDeclMatcher<FunctionDecl>().match(FromTU, functionDecl()); - - // This time import the type directly. - QualType ToT = ImportType(From->getType(), From, Lang_CXX14); - const FunctionProtoType *FPT = cast<FunctionProtoType>(ToT); - EXPECT_TRUE(isa<AutoType>(FPT->getReturnType())); + // FIXME: We do not support importing these. + // EXPECT: error: cannot import unsupported AST node CXXRecord + EXPECT_FALSE(To); } TEST_P(ImportAutoFunctions, ReturnWithTypedefToStructDeclaredInside) { @@ -6212,8 +6195,9 @@ FirstDeclMatcher<FunctionDecl>().match(FromTU, functionDecl()); FunctionDecl *To = Import(From, Lang_CXX14); - EXPECT_TRUE(To); - EXPECT_TRUE(isa<AutoType>(To->getReturnType())); + // FIXME: We do not support importing these. + // EXPECT: error: cannot import unsupported AST node CXXRecord + EXPECT_FALSE(To); } TEST_P(ImportAutoFunctions, ReturnWithStructDeclaredNestedInside) { @@ -6229,8 +6213,9 @@ FirstDeclMatcher<FunctionDecl>().match(FromTU, functionDecl()); FunctionDecl *To = Import(From, Lang_CXX14); - EXPECT_TRUE(To); - EXPECT_TRUE(isa<AutoType>(To->getReturnType())); + // FIXME: We do not support importing these. + // EXPECT: error: cannot import unsupported AST node CXXRecord + EXPECT_FALSE(To); } TEST_P(ImportAutoFunctions, ReturnWithInternalLambdaType) { @@ -6249,8 +6234,9 @@ FromTU, functionDecl(hasName("f"))); FunctionDecl *To = Import(From, Lang_CXX17); - EXPECT_TRUE(To); - EXPECT_TRUE(isa<AutoType>(To->getReturnType())); + // FIXME: We do not support importing these. + // EXPECT: error: cannot import unsupported AST node CXXRecord + EXPECT_FALSE(To); } TEST_P(ImportAutoFunctions, ReturnWithTypeInIf) { @@ -6268,8 +6254,9 @@ FromTU, functionDecl(hasName("f"))); FunctionDecl *To = Import(From, Lang_CXX17); - EXPECT_TRUE(To); - EXPECT_TRUE(isa<AutoType>(To->getReturnType())); + // FIXME: We do not support importing these. + // EXPECT: error: cannot import unsupported AST node CXXRecord + EXPECT_FALSE(To); } TEST_P(ImportAutoFunctions, ReturnWithTypeInFor) { @@ -6285,8 +6272,9 @@ FromTU, functionDecl(hasName("f"))); FunctionDecl *To = Import(From, Lang_CXX17); - EXPECT_TRUE(To); - EXPECT_TRUE(isa<AutoType>(To->getReturnType())); + // FIXME: We do not support importing these. + // EXPECT: error: cannot import unsupported AST node CXXRecord + EXPECT_FALSE(To); } TEST_P(ImportAutoFunctions, ReturnWithTypeInSwitch) { @@ -6304,8 +6292,9 @@ FromTU, functionDecl(hasName("f"))); FunctionDecl *To = Import(From, Lang_CXX17); - EXPECT_TRUE(To); - EXPECT_TRUE(isa<AutoType>(To->getReturnType())); + // FIXME: We do not support importing these. + // EXPECT: error: cannot import unsupported AST node CXXRecord + EXPECT_FALSE(To); } struct ImportSourceLocations : ASTImporterOptionSpecificTestBase {}; Index: clang/test/SemaTemplate/operator-template.cpp =================================================================== --- clang/test/SemaTemplate/operator-template.cpp +++ clang/test/SemaTemplate/operator-template.cpp @@ -2,7 +2,7 @@ // Make sure we accept this template<class X>struct A{typedef X Y;}; -template<class X>bool operator==(A<X>,typename A<X>::Y); // expected-note{{candidate template ignored: could not match 'A<type-parameter-0-0>' against 'B<int> *'}} +template<class X>bool operator==(A<X>,typename A<X>::Y); // expected-note{{candidate template ignored: could not match 'A<X>' against 'B<int> *'}} int a(A<int> x) { return operator==(x,1); } Index: clang/test/SemaTemplate/friend.cpp =================================================================== --- clang/test/SemaTemplate/friend.cpp +++ clang/test/SemaTemplate/friend.cpp @@ -50,7 +50,7 @@ namespace qualified_friend { void f(int); // expected-note 2{{type mismatch at 1st parameter}} - template<typename T> void f(T*); // expected-note 2{{could not match 'type-parameter-0-0 *' against 'double'}} + template<typename T> void f(T*); // expected-note 2{{could not match 'T *' against 'double'}} template<typename T> void nondep(); template<typename> struct X1 { @@ -66,7 +66,7 @@ struct Y { void f(int); // expected-note 2{{type mismatch at 1st parameter}} - template<typename T> void f(T*); // expected-note 2{{could not match 'type-parameter-0-0 *' against 'double'}} + template<typename T> void f(T*); // expected-note 2{{could not match 'T *' against 'double'}} template<typename T> void nondep(); }; Index: clang/test/SemaTemplate/attributes.cpp =================================================================== --- clang/test/SemaTemplate/attributes.cpp +++ clang/test/SemaTemplate/attributes.cpp @@ -125,7 +125,7 @@ clang::preferred_name(const_iterator)]] Iter {}; }; auto it = MemberTemplate<int>::Iter<const int>(); - int n = it; // expected-error {{no viable conversion from 'preferred_name::MemberTemplate<int>::const_iterator' to 'int'}} + int n = it; // expected-error {{no viable conversion from 'MemberTemplate<int>::Iter<const int>' to 'int'}} template<int A, int B, typename ...T> struct Foo; template<typename ...T> using Bar = Foo<1, 2, T...>; Index: clang/test/SemaCXX/sugared-auto.cpp =================================================================== --- /dev/null +++ clang/test/SemaCXX/sugared-auto.cpp @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++14 + +enum class N {}; + +using T1 = int; +auto x1 = T1(); +N t1 = x1; +// expected-error@-1 {{cannot initialize a variable of type 'N' with an lvalue of type 'T1' (aka 'int')}} + +using T2 = T1 *; +auto x2 = T2(); +N t2 = x2; +// expected-error@-1 {{cannot initialize a variable of type 'N' with an lvalue of type 'T2' (aka 'int *')}} + +auto *x3 = T2(); +N t3 = x3; +// expected-error@-1 {{cannot initialize a variable of type 'N' with an lvalue of type 'T1 *' (aka 'int *')}} + +auto f1() { return T1(); } +auto x4 = f1(); +N t4 = x4; +// expected-error@-1 {{cannot initialize a variable of type 'N' with an lvalue of type 'T1' (aka 'int')}} + +decltype(auto) f2() { return T1(); } +auto x5 = f2(); +N t5 = x5; +// expected-error@-1 {{cannot initialize a variable of type 'N' with an lvalue of type 'T1' (aka 'int')}} + +auto x6 = [a = T1()] { return a; }(); +N t6 = x6; +// expected-error@-1 {{cannot initialize a variable of type 'N' with an lvalue of type 'T1' (aka 'int')}} Index: clang/test/SemaCXX/sizeless-1.cpp =================================================================== --- clang/test/SemaCXX/sizeless-1.cpp +++ clang/test/SemaCXX/sizeless-1.cpp @@ -581,7 +581,7 @@ auto auto_int8 = local_int8; auto auto_int16 = local_int16; #if __cplusplus >= 201703L - auto [auto_int8_a] = local_int8; // expected-error {{cannot decompose non-class, non-array type '__SVInt8_t'}} + auto [auto_int8_a] = local_int8; // expected-error {{cannot decompose non-class, non-array type 'svint8_t' (aka '__SVInt8_t')}} #endif #endif @@ -600,7 +600,7 @@ auto fn1 = [&local_int8](svint8_t x) { local_int8 = x; }; auto fn2 = [&local_int8](svint8_t *ptr) { *ptr = local_int8; }; #if __cplusplus >= 201703L - auto fn3 = [a(return_int8())] {}; // expected-error {{field has sizeless type '__SVInt8_t'}} + auto fn3 = [a(return_int8())] {}; // expected-error {{field has sizeless type 'svint8_t' (aka '__SVInt8_t')}} #endif auto fn4 = [local_int8](svint8_t *ptr) { *ptr = local_int8; }; // expected-error {{by-copy capture of variable 'local_int8' with sizeless type 'svint8_t'}} Index: clang/test/SemaCXX/recovery-expr-type.cpp =================================================================== --- clang/test/SemaCXX/recovery-expr-type.cpp +++ clang/test/SemaCXX/recovery-expr-type.cpp @@ -133,7 +133,7 @@ template <typename T> S(T t) -> S<void *>; void baz() { - bar(S(123)); // expected-error {{no matching conversion for functional-style cast from 'int' to 'test11::S<>'}} + bar(S(123)); // expected-error {{no matching conversion for functional-style cast from 'int' to 'S<void *>'}} } } // namespace test11 Index: clang/test/SemaCXX/friend.cpp =================================================================== --- clang/test/SemaCXX/friend.cpp +++ clang/test/SemaCXX/friend.cpp @@ -415,7 +415,7 @@ namespace qualified_friend_no_match { void f(int); // expected-note {{type mismatch at 1st parameter}} - template<typename T> void f(T*); // expected-note {{could not match 'type-parameter-0-0 *' against 'double'}} + template<typename T> void f(T*); // expected-note {{could not match 'T *' against 'double'}} struct X { friend void qualified_friend_no_match::f(double); // expected-error {{friend declaration of 'f' does not match any declaration in namespace 'qualified_friend_no_match'}} friend void qualified_friend_no_match::g(); // expected-error {{friend declaration of 'g' does not match any declaration in namespace 'qualified_friend_no_match'}} @@ -423,7 +423,7 @@ struct Y { void f(int); // expected-note {{type mismatch at 1st parameter}} - template<typename T> void f(T*); // expected-note {{could not match 'type-parameter-0-0 *' against 'double'}} + template<typename T> void f(T*); // expected-note {{could not match 'T *' against 'double'}} }; struct Z { friend void Y::f(double); // expected-error {{friend declaration of 'f' does not match any declaration in 'qualified_friend_no_match::Y'}} Index: clang/test/SemaCXX/deduced-return-type-cxx14.cpp =================================================================== --- clang/test/SemaCXX/deduced-return-type-cxx14.cpp +++ clang/test/SemaCXX/deduced-return-type-cxx14.cpp @@ -300,7 +300,7 @@ } struct NonLiteral { ~NonLiteral(); } nl; // cxx14-note {{user-provided destructor}} // cxx20_2b-note@-1 {{'NonLiteral' is not literal because its destructor is not constexpr}} - constexpr auto f2(int n) { return nl; } // expected-error {{return type 'Constexpr::NonLiteral' is not a literal type}} + constexpr auto f2(int n) { return nl; } // expected-error {{return type 'struct NonLiteral' is not a literal type}} } // It's not really clear whether these are valid, but this matches g++. Index: clang/test/SemaCXX/cxx1z-decomposition.cpp =================================================================== --- clang/test/SemaCXX/cxx1z-decomposition.cpp +++ clang/test/SemaCXX/cxx1z-decomposition.cpp @@ -9,7 +9,7 @@ int a1[1], a2[2]; auto [] = a0; // expected-warning {{does not allow a decomposition group to be empty}} - auto [v1] = a0; // expected-error {{type 'A0' decomposes into 0 elements, but 1 name was provided}} + auto [v1] = a0; // expected-error {{type 'struct A0' decomposes into 0 elements, but 1 name was provided}} auto [] = a1; // expected-error {{type 'int [1]' decomposes into 1 element, but no names were provided}} expected-warning {{empty}} auto [v2] = a1; auto [v3, v4] = a1; // expected-error {{type 'int [1]' decomposes into 1 element, but 2 names were provided}} @@ -70,7 +70,7 @@ void bitfield() { struct { int a : 3, : 4, b : 5; } a; auto &[x, y] = a; - auto &[p, q, r] = a; // expected-error-re {{type '(unnamed struct at {{.*}})' decomposes into 2 elements, but 3 names were provided}} + auto &[p, q, r] = a; // expected-error-re {{type 'struct (unnamed struct at {{.*}})' decomposes into 2 elements, but 3 names were provided}} } void for_range() { Index: clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp =================================================================== --- clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp +++ clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp @@ -555,6 +555,31 @@ void foo() { insert(Foo(2, 2, 2)); // expected-error{{no viable constructor or deduction guide}} } + +namespace function_prototypes { + template<class T> using fptr1 = void (*) (T); + template<class T> using fptr2 = fptr1<fptr1<T>>; + + template<class T> void foo1(fptr1<const T *>) {} + void bar1(const char * __restrict); + void t1() { foo1(&bar1); } + + template<class T> void foo2(fptr2<const T *>) {} + void bar2(fptr1<const char * __restrict>); + void t2() { foo2(&bar2); } + + template<class T> void foo3(fptr1<const T *>) {} + void bar3(char * __restrict); + void t3() { foo3(&bar3); } + // expected-error@-1 {{no matching function for call to 'foo3'}} + // expected-note@-4 {{candidate template ignored: cannot deduce a type for 'T' that would make 'const T' equal 'char'}} + + template<class T> void foo4(fptr2<const T *>) {} + void bar4(fptr1<char * __restrict>); + void t4() { foo4(&bar4); } + // expected-error@-1 {{no matching function for call to 'foo4'}} + // expected-note@-4 {{candidate template ignored: cannot deduce a type for 'T' that would make 'const T' equal 'char'}} +} #else // expected-no-diagnostics Index: clang/test/Index/print-type.cpp =================================================================== --- clang/test/Index/print-type.cpp +++ clang/test/Index/print-type.cpp @@ -199,7 +199,7 @@ // CHECK: UnexposedExpr=templRefParam:71:40 [type=const Specialization<Specialization<bool> &>] [typekind=Record] const [templateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [isPOD=1] // CHECK: DeclRefExpr=templRefParam:71:40 [type=Specialization<Specialization<bool> &>] [typekind=Unexposed] [templateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [canonicaltype=Specialization<Specialization<bool> &>] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [isPOD=1] // CHECK: TypeAliasDecl=baz:76:7 (Definition) [type=baz] [typekind=Typedef] [templateargs/1= [type=A<void>] [typekind=Unexposed]] [canonicaltype=A<void>] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=void] [typekind=Void]] [isPOD=0] -// CHECK: VarDecl=autoTemplPointer:78:6 (Definition) [type=Specialization<Specialization<bool> &> *] [typekind=Auto] [canonicaltype=Specialization<Specialization<bool> &> *] [canonicaltypekind=Pointer] [isPOD=1] [pointeetype=Specialization<Specialization<bool> &>] [pointeekind=Record] +// CHECK: VarDecl=autoTemplPointer:78:6 (Definition) [type=Specialization<Specialization<bool> &> *] [typekind=Auto] [canonicaltype=Specialization<Specialization<bool> &> *] [canonicaltypekind=Pointer] [isPOD=1] [pointeetype=Specialization<Specialization<bool> &>] [pointeekind=Auto] // CHECK: CallExpr=Bar:17:3 [type=outer::inner::Bar] [typekind=Elaborated] [canonicaltype=outer::inner::Bar] [canonicaltypekind=Record] [args= [outer::Foo<bool> *] [Pointer]] [isPOD=0] [nbFields=3] // CHECK: StructDecl=:84:3 (Definition) [type=X::(anonymous struct at {{.*}}print-type.cpp:84:3)] [typekind=Record] [isPOD=1] [nbFields=1] [isAnon=1] // CHECK: ClassDecl=:85:3 (Definition) [type=X::(anonymous class at {{.*}}print-type.cpp:85:3)] [typekind=Record] [isPOD=1] [nbFields=1] [isAnon=1] Index: clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p1-0x.cpp =================================================================== --- clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p1-0x.cpp +++ clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p1-0x.cpp @@ -53,9 +53,8 @@ } -// FIXME: Use the template parameter names in this diagnostic. template<typename ...Args1, typename ...Args2> -typename get_nth_type<0, Args1...>::type first_arg_pair(pair<Args1, Args2>...); // expected-note{{candidate template ignored: could not match 'pair<type-parameter-0-0, type-parameter-0-1>' against 'int'}} +typename get_nth_type<0, Args1...>::type first_arg_pair(pair<Args1, Args2>...); // expected-note{{candidate template ignored: could not match 'pair<Args1, Args2>' against 'int'}} template<typename ...Args1, typename ...Args2> typename get_nth_type<1, Args1...>::type second_arg_pair(pair<Args1, Args2>...); Index: clang/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp =================================================================== --- clang/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp +++ clang/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp @@ -284,7 +284,7 @@ void g(U &&...u, T &&...t) {} // expected-note {{candidate}} template<typename...U> void h(tuple<T, U> &&...) {} - // expected-note@-1 {{candidate template ignored: could not match 'tuple<type-parameter-0-0, type-parameter-0-0>' against 'int'}} + // expected-note@-1 {{candidate template ignored: could not match 'tuple<T, U>' against 'int'}} // expected-note@-2 {{candidate template ignored: substitution failure: deduced incomplete pack <(no value)> for template parameter 'U'}} template<typename...U> Index: clang/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp =================================================================== --- clang/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp +++ clang/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp @@ -321,14 +321,14 @@ namespace NE { struct E { - void begin(); // expected-note {{member is not a candidate because range type 'p0962r1::NE::E' has no 'end' member}} + void begin(); // expected-note {{member is not a candidate because range type 'NE::E' has no 'end' member}} }; int *end(E); } namespace NF { struct F { - void end(); // expected-note {{member is not a candidate because range type 'p0962r1::NF::F' has no 'begin' member}} + void end(); // expected-note {{member is not a candidate because range type 'NF::F' has no 'begin' member}} }; int *begin(F); } @@ -336,9 +336,9 @@ void use(NA::A a, NB::B b, NC::C c, ND::D d, NE::E e, NF::F f) { for (auto x : a) {} for (auto x : b) {} - for (auto x : c) {} // expected-error {{invalid range expression of type 'p0962r1::NC::C'; no viable 'end' function available}} - for (auto x : d) {} // expected-error {{invalid range expression of type 'p0962r1::ND::D'; no viable 'begin' function available}} - for (auto x : e) {} // expected-error {{invalid range expression of type 'p0962r1::NE::E'; no viable 'begin' function available}} - for (auto x : f) {} // expected-error {{invalid range expression of type 'p0962r1::NF::F'; no viable 'end' function available}} + for (auto x : c) {} // expected-error {{invalid range expression of type 'NC::C'; no viable 'end' function available}} + for (auto x : d) {} // expected-error {{invalid range expression of type 'ND::D'; no viable 'begin' function available}} + for (auto x : e) {} // expected-error {{invalid range expression of type 'NE::E'; no viable 'begin' function available}} + for (auto x : f) {} // expected-error {{invalid range expression of type 'NF::F'; no viable 'end' function available}} } } Index: clang/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp =================================================================== --- clang/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp +++ clang/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp @@ -36,7 +36,7 @@ namespace p0702r1 { template<typename T> struct X { // expected-note {{candidate}} - X(std::initializer_list<T>); // expected-note {{candidate template ignored: could not match 'initializer_list<type-parameter-0-0>' against 'p0702r1::Z'}} + X(std::initializer_list<T>); // expected-note {{candidate template ignored: could not match 'initializer_list<T>' against 'p0702r1::Z'}} }; X xi = {0}; Index: clang/lib/Sema/TreeTransform.h =================================================================== --- clang/lib/Sema/TreeTransform.h +++ clang/lib/Sema/TreeTransform.h @@ -6561,7 +6561,7 @@ T->isDependentType() || T->isConstrained()) { // FIXME: Maybe don't rebuild if all template arguments are the same. llvm::SmallVector<TemplateArgument, 4> NewArgList; - NewArgList.reserve(NewArgList.size()); + NewArgList.reserve(NewTemplateArgs.size()); for (const auto &ArgLoc : NewTemplateArgs.arguments()) NewArgList.push_back(ArgLoc.getArgument()); Result = getDerived().RebuildAutoType(NewDeduced, T->getKeyword(), NewCD, @@ -14446,10 +14446,10 @@ return SemaRef.Context.getTypeDeclType(Ty); } -template<typename Derived> +template <typename Derived> QualType TreeTransform<Derived>::RebuildTypeOfExprType(Expr *E, - SourceLocation Loc) { - return SemaRef.BuildTypeofExprType(E, Loc); + SourceLocation) { + return SemaRef.BuildTypeofExprType(E); } template<typename Derived> @@ -14457,10 +14457,9 @@ return SemaRef.Context.getTypeOfType(Underlying); } -template<typename Derived> -QualType TreeTransform<Derived>::RebuildDecltypeType(Expr *E, - SourceLocation Loc) { - return SemaRef.BuildDecltypeType(E, Loc); +template <typename Derived> +QualType TreeTransform<Derived>::RebuildDecltypeType(Expr *E, SourceLocation) { + return SemaRef.BuildDecltypeType(E); } template<typename Derived> Index: clang/lib/Sema/SemaType.cpp =================================================================== --- clang/lib/Sema/SemaType.cpp +++ clang/lib/Sema/SemaType.cpp @@ -1622,7 +1622,7 @@ Expr *E = DS.getRepAsExpr(); assert(E && "Didn't get an expression for typeof?"); // TypeQuals handled by caller. - Result = S.BuildTypeofExprType(E, DS.getTypeSpecTypeLoc()); + Result = S.BuildTypeofExprType(E); if (Result.isNull()) { Result = Context.IntTy; declarator.setInvalidType(true); @@ -1633,7 +1633,7 @@ Expr *E = DS.getRepAsExpr(); assert(E && "Didn't get an expression for decltype?"); // TypeQuals handled by caller. - Result = S.BuildDecltypeType(E, DS.getTypeSpecTypeLoc()); + Result = S.BuildDecltypeType(E); if (Result.isNull()) { Result = Context.IntTy; declarator.setInvalidType(true); @@ -8893,7 +8893,7 @@ return Context.getElaboratedType(Keyword, NNS, T, OwnedTagDecl); } -QualType Sema::BuildTypeofExprType(Expr *E, SourceLocation Loc) { +QualType Sema::BuildTypeofExprType(Expr *E) { assert(!E->hasPlaceholderType() && "unexpected placeholder"); if (!getLangOpts().CPlusPlus && E->refersToBitField()) @@ -8910,9 +8910,9 @@ /// getDecltypeForExpr - Given an expr, will return the decltype for /// that expression, according to the rules in C++11 /// [dcl.type.simple]p4 and C++11 [expr.lambda.prim]p18. -static QualType getDecltypeForExpr(Sema &S, Expr *E) { +QualType Sema::getDecltypeForExpr(Expr *E) { if (E->isTypeDependent()) - return S.Context.DependentTy; + return Context.DependentTy; Expr *IDExpr = E; if (auto *ImplCastExpr = dyn_cast<ImplicitCastExpr>(E)) @@ -8929,7 +8929,7 @@ // parameter object. This rule makes no difference before C++20 so we apply // it unconditionally. if (const auto *SNTTPE = dyn_cast<SubstNonTypeTemplateParmExpr>(IDExpr)) - return SNTTPE->getParameterType(S.Context); + return SNTTPE->getParameterType(Context); // - if e is an unparenthesized id-expression or an unparenthesized class // member access (5.2.5), decltype(e) is the type of the entity named @@ -8937,22 +8937,20 @@ // functions, the program is ill-formed; // // We apply the same rules for Objective-C ivar and property references. - if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(IDExpr)) { + if (const auto *DRE = dyn_cast<DeclRefExpr>(IDExpr)) { const ValueDecl *VD = DRE->getDecl(); - if (auto *TPO = dyn_cast<TemplateParamObjectDecl>(VD)) - return TPO->getType().getUnqualifiedType(); - return VD->getType(); - } else if (const MemberExpr *ME = dyn_cast<MemberExpr>(IDExpr)) { - if (const ValueDecl *VD = ME->getMemberDecl()) + QualType T = VD->getType(); + return isa<TemplateParamObjectDecl>(VD) ? T.getUnqualifiedType() : T; + } else if (const auto *ME = dyn_cast<MemberExpr>(IDExpr)) { + if (const auto *VD = ME->getMemberDecl()) if (isa<FieldDecl>(VD) || isa<VarDecl>(VD)) return VD->getType(); - } else if (const ObjCIvarRefExpr *IR = dyn_cast<ObjCIvarRefExpr>(IDExpr)) { + } else if (const auto *IR = dyn_cast<ObjCIvarRefExpr>(IDExpr)) { return IR->getDecl()->getType(); - } else if (const ObjCPropertyRefExpr *PR = - dyn_cast<ObjCPropertyRefExpr>(IDExpr)) { + } else if (const auto *PR = dyn_cast<ObjCPropertyRefExpr>(IDExpr)) { if (PR->isExplicitProperty()) return PR->getExplicitProperty()->getType(); - } else if (auto *PE = dyn_cast<PredefinedExpr>(IDExpr)) { + } else if (const auto *PE = dyn_cast<PredefinedExpr>(IDExpr)) { return PE->getType(); } @@ -8963,24 +8961,20 @@ // access to a corresponding data member of the closure type that // would have been declared if x were an odr-use of the denoted // entity. - using namespace sema; - if (S.getCurLambda()) { - if (isa<ParenExpr>(IDExpr)) { - if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(IDExpr->IgnoreParens())) { - if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) { - QualType T = S.getCapturedDeclRefType(Var, DRE->getLocation()); - if (!T.isNull()) - return S.Context.getLValueReferenceType(T); - } + if (getCurLambda() && isa<ParenExpr>(IDExpr)) { + if (auto *DRE = dyn_cast<DeclRefExpr>(IDExpr->IgnoreParens())) { + if (auto *Var = dyn_cast<VarDecl>(DRE->getDecl())) { + QualType T = getCapturedDeclRefType(Var, DRE->getLocation()); + if (!T.isNull()) + return Context.getLValueReferenceType(T); } } } - return S.Context.getReferenceQualifiedType(E); + return Context.getReferenceQualifiedType(E); } -QualType Sema::BuildDecltypeType(Expr *E, SourceLocation Loc, - bool AsUnevaluated) { +QualType Sema::BuildDecltypeType(Expr *E, bool AsUnevaluated) { assert(!E->hasPlaceholderType() && "unexpected placeholder"); if (AsUnevaluated && CodeSynthesisContexts.empty() && @@ -8991,8 +8985,7 @@ // used to build SFINAE gadgets. Diag(E->getExprLoc(), diag::warn_side_effects_unevaluated_context); } - - return Context.getDecltypeType(E, getDecltypeForExpr(*this, E)); + return Context.getDecltypeType(E, getDecltypeForExpr(E)); } QualType Sema::BuildUnaryTransformType(QualType BaseType, Index: clang/lib/Sema/SemaTemplateDeduction.cpp =================================================================== --- clang/lib/Sema/SemaTemplateDeduction.cpp +++ clang/lib/Sema/SemaTemplateDeduction.cpp @@ -139,17 +139,11 @@ TemplateDeductionInfo &Info, SmallVectorImpl<DeducedTemplateArgument> &Deduced); -static Sema::TemplateDeductionResult -DeduceTemplateArgumentsByTypeMatch(Sema &S, - TemplateParameterList *TemplateParams, - QualType Param, - QualType Arg, - TemplateDeductionInfo &Info, - SmallVectorImpl<DeducedTemplateArgument> & - Deduced, - unsigned TDF, - bool PartialOrdering = false, - bool DeducedFromArrayBound = false); +static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( + Sema &S, TemplateParameterList *TemplateParams, QualType Param, + QualType Arg, TemplateDeductionInfo &Info, + SmallVectorImpl<DeducedTemplateArgument> &Deduced, unsigned TDF, + bool PartialOrdering = false, bool DeducedFromArrayBound = false); static Sema::TemplateDeductionResult DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, @@ -565,15 +559,20 @@ QualType Arg, TemplateDeductionInfo &Info, SmallVectorImpl<DeducedTemplateArgument> &Deduced) { - assert(Arg.isCanonical() && "Argument type must be canonical"); + QualType ArgDesug; + auto updateArg = [&Arg, &ArgDesug, &S](QualType T) { + Arg = T; + ArgDesug = T.getDesugaredType(S.Context); + }; + updateArg(Arg); // Treat an injected-class-name as its underlying template-id. - if (auto *Injected = dyn_cast<InjectedClassNameType>(Arg)) - Arg = Injected->getInjectedSpecializationType(); + if (auto *Injected = dyn_cast<InjectedClassNameType>(ArgDesug)) + updateArg(Injected->getInjectedSpecializationType()); // Check whether the template argument is a dependent template-id. - if (const TemplateSpecializationType *SpecArg - = dyn_cast<TemplateSpecializationType>(Arg)) { + if (const TemplateSpecializationType *SpecArg = + dyn_cast<TemplateSpecializationType>(ArgDesug)) { // Perform template argument deduction for the template name. if (Sema::TemplateDeductionResult Result = DeduceTemplateArguments(S, TemplateParams, @@ -595,7 +594,7 @@ // If the argument type is a class template specialization, we // perform template argument deduction using its template // arguments. - const RecordType *RecordArg = dyn_cast<RecordType>(Arg); + const RecordType *RecordArg = dyn_cast<RecordType>(ArgDesug); if (!RecordArg) { Info.FirstArg = TemplateArgument(QualType(Param, 0)); Info.SecondArg = TemplateArgument(Arg); @@ -1047,11 +1046,12 @@ return Sema::TDK_MiscellaneousDeductionFailure; } - if (Sema::TemplateDeductionResult Result - = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, - Params[ParamIdx], Args[ArgIdx], - Info, Deduced, TDF, - PartialOrdering)) + if (Sema::TemplateDeductionResult Result = + DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, Params[ParamIdx].getUnqualifiedType(), + Args[ArgIdx].getUnqualifiedType(), Info, Deduced, TDF, + PartialOrdering, + /*DeducedFromArrayBound=*/false)) return Result; ++ArgIdx; @@ -1073,10 +1073,11 @@ if (ParamIdx + 1 == NumParams || PackScope.hasFixedArity()) { for (; ArgIdx < NumArgs && PackScope.hasNextElement(); ++ArgIdx) { // Deduce template arguments from the pattern. - if (Sema::TemplateDeductionResult Result - = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, Pattern, - Args[ArgIdx], Info, Deduced, - TDF, PartialOrdering)) + if (Sema::TemplateDeductionResult Result = + DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, Pattern.getUnqualifiedType(), + Args[ArgIdx].getUnqualifiedType(), Info, Deduced, TDF, + PartialOrdering, /*DeducedFromArrayBound=*/false)) return Result; PackScope.nextPackElement(); @@ -1341,25 +1342,24 @@ /// \returns the result of template argument deduction so far. Note that a /// "success" result means that template argument deduction has not yet failed, /// but it may still fail, later, for other reasons. -static Sema::TemplateDeductionResult -DeduceTemplateArgumentsByTypeMatch(Sema &S, - TemplateParameterList *TemplateParams, - QualType ParamIn, QualType ArgIn, - TemplateDeductionInfo &Info, - SmallVectorImpl<DeducedTemplateArgument> &Deduced, - unsigned TDF, - bool PartialOrdering, - bool DeducedFromArrayBound) { - // We only want to look at the canonical types, since typedefs and - // sugar are not part of template argument deduction. - QualType Param = S.Context.getCanonicalType(ParamIn); - QualType Arg = S.Context.getCanonicalType(ArgIn); - - // If the argument type is a pack expansion, look at its pattern. - // This isn't explicitly called out - if (const PackExpansionType *ArgExpansion - = dyn_cast<PackExpansionType>(Arg)) - Arg = ArgExpansion->getPattern(); +static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( + Sema &S, TemplateParameterList *TemplateParams, QualType Param, + QualType Arg, TemplateDeductionInfo &Info, + SmallVectorImpl<DeducedTemplateArgument> &Deduced, unsigned TDF, + bool PartialOrdering, bool DeducedFromArrayBound) { + QualType ParDesug; + auto updatePar = [&Param, &ParDesug, &S](QualType T) { + Param = T; + ParDesug = T.getDesugaredType(S.Context); + }; + updatePar(Param); + + QualType ArgDesug; + auto updateArg = [&Arg, &ArgDesug, &S](QualType T) { + Arg = T; + ArgDesug = T.getDesugaredType(S.Context); + }; + updateArg(Arg); if (PartialOrdering) { // C++11 [temp.deduct.partial]p5: @@ -1368,12 +1368,12 @@ // - If P is a reference type, P is replaced by the type referred to. const ReferenceType *ParamRef = Param->getAs<ReferenceType>(); if (ParamRef) - Param = ParamRef->getPointeeType(); + updatePar(ParamRef->getPointeeType()); // - If A is a reference type, A is replaced by the type referred to. - const ReferenceType *ArgRef = Arg->getAs<ReferenceType>(); + const ReferenceType *ArgRef = ArgDesug->getAs<ReferenceType>(); if (ArgRef) - Arg = ArgRef->getPointeeType(); + updateArg(ArgRef->getPointeeType()); if (ParamRef && ArgRef && S.Context.hasSameUnqualifiedType(Param, Arg)) { // C++11 [temp.deduct.partial]p9: @@ -1404,8 +1404,8 @@ ArgQuals.getObjCLifetime() == Qualifiers::OCL_ExplicitNone && ParamQuals.withoutObjCLifetime() == ArgQuals.withoutObjCLifetime())) { - Info.FirstArg = TemplateArgument(ParamIn); - Info.SecondArg = TemplateArgument(ArgIn); + Info.FirstArg = TemplateArgument(Param); + Info.SecondArg = TemplateArgument(Arg); return Sema::TDK_NonDeducedMismatch; } } @@ -1414,10 +1414,10 @@ // Remove any top-level cv-qualifiers: // - If P is a cv-qualified type, P is replaced by the cv-unqualified // version of P. - Param = Param.getUnqualifiedType(); + updatePar(Param.getUnqualifiedType()); // - If A is a cv-qualified type, A is replaced by the cv-unqualified // version of A. - Arg = Arg.getUnqualifiedType(); + updateArg(Arg.getUnqualifiedType()); } else { // C++0x [temp.deduct.call]p4 bullet 1: // - If the original P is a reference type, the deduced A (i.e., the type @@ -1427,8 +1427,8 @@ Qualifiers Quals; QualType UnqualParam = S.Context.getUnqualifiedArrayType(Param, Quals); Quals.setCVRQualifiers(Quals.getCVRQualifiers() & - Arg.getCVRQualifiers()); - Param = S.Context.getQualifiedType(UnqualParam, Quals); + ArgDesug.getCVRQualifiers()); + updatePar(S.Context.getQualifiedType(UnqualParam, Quals)); } if ((TDF & TDF_TopLevelParameterTypeList) && !Param->isFunctionType()) { @@ -1444,8 +1444,8 @@ // Pi is T&& and Ai is X&, the adjusted Pi will be T, causing T to be // deduced as X&. - end note ] TDF &= ~TDF_TopLevelParameterTypeList; - if (isForwardingReference(Param, 0) && Arg->isLValueReferenceType()) - Param = Param->getPointeeType(); + if (isForwardingReference(Param, 0) && ArgDesug->isLValueReferenceType()) + updatePar(Param->getPointeeType()); } } @@ -1456,32 +1456,29 @@ // // T // cv-list T - if (const TemplateTypeParmType *TemplateTypeParm - = Param->getAs<TemplateTypeParmType>()) { + if (const TemplateTypeParmType *TemplateTypeParm = + ParDesug->getAs<TemplateTypeParmType>()) { // Just skip any attempts to deduce from a placeholder type or a parameter // at a different depth. - if (Arg->isPlaceholderType() || + if (ArgDesug->isPlaceholderType() || Info.getDeducedDepth() != TemplateTypeParm->getDepth()) return Sema::TDK_Success; unsigned Index = TemplateTypeParm->getIndex(); - bool RecanonicalizeArg = false; // If the argument type is an array type, move the qualifiers up to the // top level, so they can be matched with the qualifiers on the parameter. - if (isa<ArrayType>(Arg)) { + if (isa<ArrayType>(ArgDesug)) { Qualifiers Quals; - Arg = S.Context.getUnqualifiedArrayType(Arg, Quals); - if (Quals) { - Arg = S.Context.getQualifiedType(Arg, Quals); - RecanonicalizeArg = true; - } + updateArg(S.Context.getUnqualifiedArrayType(ArgDesug, Quals)); + if (Quals) + updateArg(S.Context.getQualifiedType(ArgDesug, Quals)); } // The argument type can not be less qualified than the parameter // type. if (!(TDF & TDF_IgnoreQualifiers) && - hasInconsistentOrSupersetQualifiersOf(Param, Arg)) { + hasInconsistentOrSupersetQualifiersOf(Param, ArgDesug)) { Info.Param = cast<TemplateTypeParmDecl>(TemplateParams->getParam(Index)); Info.FirstArg = TemplateArgument(Param); Info.SecondArg = TemplateArgument(Arg); @@ -1496,7 +1493,8 @@ assert(TemplateTypeParm->getDepth() == Info.getDeducedDepth() && "saw template type parameter with wrong depth"); - assert(Arg != S.Context.OverloadTy && "Unresolved overloaded function"); + assert(ArgDesug != S.Context.OverloadTy && + "Unresolved overloaded function"); QualType DeducedType = Arg; // Remove any qualifiers on the parameter from the deduced type. @@ -1530,11 +1528,8 @@ !DeducedQs.hasObjCLifetime()) DeducedQs.setObjCLifetime(Qualifiers::OCL_Strong); - DeducedType = S.Context.getQualifiedType(DeducedType.getUnqualifiedType(), - DeducedQs); - - if (RecanonicalizeArg) - DeducedType = S.Context.getCanonicalType(DeducedType); + DeducedType = + S.Context.getQualifiedType(DeducedType.getUnqualifiedType(), DeducedQs); DeducedTemplateArgument NewDeduced(DeducedType, DeducedFromArrayBound); DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context, @@ -1552,14 +1547,14 @@ } // Set up the template argument deduction information for a failure. - Info.FirstArg = TemplateArgument(ParamIn); - Info.SecondArg = TemplateArgument(ArgIn); + Info.FirstArg = TemplateArgument(Param); + Info.SecondArg = TemplateArgument(Arg); // If the parameter is an already-substituted template parameter // pack, do nothing: we don't know which of its arguments to look // at, so we have to wait until all of the parameter packs in this // expansion have arguments. - if (isa<SubstTemplateTypeParmPackType>(Param)) + if (isa<SubstTemplateTypeParmPackType>(ParDesug)) return Sema::TDK_Success; // Check the cv-qualifiers on the parameter and argument types. @@ -1573,16 +1568,16 @@ // C++ [temp.deduct.conv]p4: // If the original A is a reference type, A can be more cv-qualified // than the deduced A - if (!Arg.getQualifiers().compatiblyIncludes(Param.getQualifiers())) + if (!ArgDesug.getQualifiers().compatiblyIncludes(Param.getQualifiers())) return Sema::TDK_NonDeducedMismatch; // Strip out all extra qualifiers from the argument to figure out the // type we're converting to, prior to the qualification conversion. Qualifiers Quals; - Arg = S.Context.getUnqualifiedArrayType(Arg, Quals); - Arg = S.Context.getQualifiedType(Arg, Param.getQualifiers()); + updateArg(S.Context.getUnqualifiedArrayType(ArgDesug, Quals)); + updateArg(S.Context.getQualifiedType(ArgDesug, Param.getQualifiers())); } else if (!IsPossiblyOpaquelyQualifiedType(Param)) { - if (Param.getCVRQualifiers() != Arg.getCVRQualifiers()) + if (ParDesug.getCVRQualifiers() != ArgDesug.getCVRQualifiers()) return Sema::TDK_NonDeducedMismatch; } @@ -1592,7 +1587,7 @@ bool NonDeduced = (TDF & TDF_AllowCompatibleFunctionType) ? !S.isSameOrCompatibleFunctionType(CanParam, CanArg) - : Param != Arg; + : CanParam != CanArg; if (NonDeduced) { return Sema::TDK_NonDeducedMismatch; } @@ -1614,7 +1609,7 @@ } } - switch (Param->getTypeClass()) { + switch (ParDesug->getTypeClass()) { // Non-canonical types cannot appear here. #define NON_CANONICAL_TYPE(Class, Base) \ case Type::Class: llvm_unreachable("deducing non-canonical type: " #Class); @@ -1641,99 +1636,98 @@ return Sema::TDK_Success; if (TDF & TDF_IgnoreQualifiers) { - Param = Param.getUnqualifiedType(); - Arg = Arg.getUnqualifiedType(); + ParDesug = ParDesug.getUnqualifiedType(); + ArgDesug = ArgDesug.getUnqualifiedType(); } - return Param == Arg? Sema::TDK_Success : Sema::TDK_NonDeducedMismatch; + return ParDesug == ArgDesug ? Sema::TDK_Success + : Sema::TDK_NonDeducedMismatch; // _Complex T [placeholder extension] case Type::Complex: - if (const ComplexType *ComplexArg = Arg->getAs<ComplexType>()) - return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, - cast<ComplexType>(Param)->getElementType(), - ComplexArg->getElementType(), - Info, Deduced, TDF); + if (const ComplexType *ComplexArg = ArgDesug->getAs<ComplexType>()) + return DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, cast<ComplexType>(ParDesug)->getElementType(), + ComplexArg->getElementType(), Info, Deduced, TDF); return Sema::TDK_NonDeducedMismatch; // _Atomic T [extension] case Type::Atomic: - if (const AtomicType *AtomicArg = Arg->getAs<AtomicType>()) - return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, - cast<AtomicType>(Param)->getValueType(), - AtomicArg->getValueType(), - Info, Deduced, TDF); + if (const AtomicType *AtomicArg = ArgDesug->getAs<AtomicType>()) + return DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, cast<AtomicType>(ParDesug)->getValueType(), + AtomicArg->getValueType(), Info, Deduced, TDF); return Sema::TDK_NonDeducedMismatch; // T * case Type::Pointer: { QualType PointeeType; - if (const PointerType *PointerArg = Arg->getAs<PointerType>()) { + if (const PointerType *PointerArg = ArgDesug->getAs<PointerType>()) { PointeeType = PointerArg->getPointeeType(); - } else if (const ObjCObjectPointerType *PointerArg - = Arg->getAs<ObjCObjectPointerType>()) { + } else if (const ObjCObjectPointerType *PointerArg = + ArgDesug->getAs<ObjCObjectPointerType>()) { PointeeType = PointerArg->getPointeeType(); } else { return Sema::TDK_NonDeducedMismatch; } unsigned SubTDF = TDF & (TDF_IgnoreQualifiers | TDF_DerivedClass); - return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, - cast<PointerType>(Param)->getPointeeType(), - PointeeType, - Info, Deduced, SubTDF); + return DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, cast<PointerType>(ParDesug)->getPointeeType(), + PointeeType, Info, Deduced, SubTDF); } // T & case Type::LValueReference: { const LValueReferenceType *ReferenceArg = - Arg->getAs<LValueReferenceType>(); + ArgDesug->getAs<LValueReferenceType>(); if (!ReferenceArg) return Sema::TDK_NonDeducedMismatch; - return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, - cast<LValueReferenceType>(Param)->getPointeeType(), - ReferenceArg->getPointeeType(), Info, Deduced, 0); + return DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, + cast<LValueReferenceType>(ParDesug)->getPointeeType(), + ReferenceArg->getPointeeType(), Info, Deduced, 0); } // T && [C++0x] case Type::RValueReference: { const RValueReferenceType *ReferenceArg = - Arg->getAs<RValueReferenceType>(); + ArgDesug->getAs<RValueReferenceType>(); if (!ReferenceArg) return Sema::TDK_NonDeducedMismatch; - return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, - cast<RValueReferenceType>(Param)->getPointeeType(), - ReferenceArg->getPointeeType(), - Info, Deduced, 0); + return DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, + cast<RValueReferenceType>(ParDesug)->getPointeeType(), + ReferenceArg->getPointeeType(), Info, Deduced, 0); } // T [] (implied, but not stated explicitly) case Type::IncompleteArray: { const IncompleteArrayType *IncompleteArrayArg = - S.Context.getAsIncompleteArrayType(Arg); + S.Context.getAsIncompleteArrayType(ArgDesug); if (!IncompleteArrayArg) return Sema::TDK_NonDeducedMismatch; unsigned SubTDF = TDF & TDF_IgnoreQualifiers; - return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, - S.Context.getAsIncompleteArrayType(Param)->getElementType(), - IncompleteArrayArg->getElementType(), - Info, Deduced, SubTDF); + return DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, + S.Context.getAsIncompleteArrayType(ParDesug)->getElementType(), + IncompleteArrayArg->getElementType(), Info, Deduced, SubTDF); } // T [integer-constant] case Type::ConstantArray: { const ConstantArrayType *ConstantArrayArg = - S.Context.getAsConstantArrayType(Arg); + S.Context.getAsConstantArrayType(ArgDesug); if (!ConstantArrayArg) return Sema::TDK_NonDeducedMismatch; const ConstantArrayType *ConstantArrayParm = - S.Context.getAsConstantArrayType(Param); + S.Context.getAsConstantArrayType(ParDesug); if (ConstantArrayArg->getSize() != ConstantArrayParm->getSize()) return Sema::TDK_NonDeducedMismatch; @@ -1746,15 +1740,15 @@ // type [i] case Type::DependentSizedArray: { - const ArrayType *ArrayArg = S.Context.getAsArrayType(Arg); + const ArrayType *ArrayArg = S.Context.getAsArrayType(ArgDesug); if (!ArrayArg) return Sema::TDK_NonDeducedMismatch; unsigned SubTDF = TDF & TDF_IgnoreQualifiers; // Check the element type of the arrays - const DependentSizedArrayType *DependentArrayParm - = S.Context.getAsDependentSizedArrayType(Param); + const DependentSizedArrayType *DependentArrayParm = + S.Context.getAsDependentSizedArrayType(ParDesug); if (Sema::TemplateDeductionResult Result = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, DependentArrayParm->getElementType(), @@ -1797,12 +1791,12 @@ case Type::FunctionProto: { unsigned SubTDF = TDF & TDF_TopLevelParameterTypeList; const FunctionProtoType *FunctionProtoArg = - dyn_cast<FunctionProtoType>(Arg); + dyn_cast<FunctionProtoType>(ArgDesug); if (!FunctionProtoArg) return Sema::TDK_NonDeducedMismatch; const FunctionProtoType *FunctionProtoParam = - cast<FunctionProtoType>(Param); + cast<FunctionProtoType>(ParDesug); if (FunctionProtoParam->getMethodQuals() != FunctionProtoArg->getMethodQuals() || @@ -1813,8 +1807,12 @@ // Check return types. if (auto Result = DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, FunctionProtoParam->getReturnType(), - FunctionProtoArg->getReturnType(), Info, Deduced, 0)) + S, TemplateParams, + FunctionProtoParam->getReturnType().getUnqualifiedType(), + FunctionProtoArg->getReturnType().getUnqualifiedType(), Info, + Deduced, 0, + /*PartialOrdering=*/false, + /*DeducedFromArrayBound=*/false)) return Result; // Check parameter types. @@ -1870,9 +1868,9 @@ case Type::InjectedClassName: // Treat a template's injected-class-name as if the template // specialization type had been used. - Param = cast<InjectedClassNameType>(Param) - ->getInjectedSpecializationType(); - assert(isa<TemplateSpecializationType>(Param) && + updatePar(cast<InjectedClassNameType>(ParDesug) + ->getInjectedSpecializationType()); + assert(isa<TemplateSpecializationType>(ParDesug) && "injected class name is not a template specialization type"); LLVM_FALLTHROUGH; @@ -1883,11 +1881,11 @@ // TT<> case Type::TemplateSpecialization: { const TemplateSpecializationType *SpecParam = - cast<TemplateSpecializationType>(Param); + cast<TemplateSpecializationType>(ParDesug); // When Arg cannot be a derived class, we can just try to deduce template // arguments from the template-id. - const RecordType *RecordT = Arg->getAs<RecordType>(); + const RecordType *RecordT = ArgDesug->getAs<RecordType>(); if (!(TDF & TDF_DerivedClass) || !RecordT) return DeduceTemplateArguments(S, TemplateParams, SpecParam, Arg, Info, Deduced); @@ -1929,8 +1927,9 @@ // T (T::*)() // T (T::*)(T) case Type::MemberPointer: { - const MemberPointerType *MemPtrParam = cast<MemberPointerType>(Param); - const MemberPointerType *MemPtrArg = dyn_cast<MemberPointerType>(Arg); + const MemberPointerType *MemPtrParam = cast<MemberPointerType>(ParDesug); + const MemberPointerType *MemPtrArg = + dyn_cast<MemberPointerType>(ArgDesug); if (!MemPtrArg) return Sema::TDK_NonDeducedMismatch; @@ -1964,8 +1963,9 @@ // T(^)() // T(^)(T) case Type::BlockPointer: { - const BlockPointerType *BlockPtrParam = cast<BlockPointerType>(Param); - const BlockPointerType *BlockPtrArg = dyn_cast<BlockPointerType>(Arg); + const BlockPointerType *BlockPtrParam = cast<BlockPointerType>(ParDesug); + const BlockPointerType *BlockPtrArg = + dyn_cast<BlockPointerType>(ArgDesug); if (!BlockPtrArg) return Sema::TDK_NonDeducedMismatch; @@ -1980,8 +1980,8 @@ // // T __attribute__(((ext_vector_type(<integral constant>)))) case Type::ExtVector: { - const ExtVectorType *VectorParam = cast<ExtVectorType>(Param); - if (const ExtVectorType *VectorArg = dyn_cast<ExtVectorType>(Arg)) { + const ExtVectorType *VectorParam = cast<ExtVectorType>(ParDesug); + if (const ExtVectorType *VectorArg = dyn_cast<ExtVectorType>(ArgDesug)) { // Make sure that the vectors have the same number of elements. if (VectorParam->getNumElements() != VectorArg->getNumElements()) return Sema::TDK_NonDeducedMismatch; @@ -1993,8 +1993,8 @@ Info, Deduced, TDF); } - if (const DependentSizedExtVectorType *VectorArg - = dyn_cast<DependentSizedExtVectorType>(Arg)) { + if (const DependentSizedExtVectorType *VectorArg = + dyn_cast<DependentSizedExtVectorType>(ArgDesug)) { // We can't check the number of elements, since the argument has a // dependent number of elements. This can only occur during partial // ordering. @@ -2010,9 +2010,9 @@ } case Type::DependentVector: { - const auto *VectorParam = cast<DependentVectorType>(Param); + const auto *VectorParam = cast<DependentVectorType>(ParDesug); - if (const auto *VectorArg = dyn_cast<VectorType>(Arg)) { + if (const auto *VectorArg = dyn_cast<VectorType>(ArgDesug)) { // Perform deduction on the element types. if (Sema::TemplateDeductionResult Result = DeduceTemplateArgumentsByTypeMatch( @@ -2036,7 +2036,7 @@ Info, Deduced); } - if (const auto *VectorArg = dyn_cast<DependentVectorType>(Arg)) { + if (const auto *VectorArg = dyn_cast<DependentVectorType>(ArgDesug)) { // Perform deduction on the element types. if (Sema::TemplateDeductionResult Result = DeduceTemplateArgumentsByTypeMatch( @@ -2061,10 +2061,10 @@ // // T __attribute__(((ext_vector_type(N)))) case Type::DependentSizedExtVector: { - const DependentSizedExtVectorType *VectorParam - = cast<DependentSizedExtVectorType>(Param); + const DependentSizedExtVectorType *VectorParam = + cast<DependentSizedExtVectorType>(ParDesug); - if (const ExtVectorType *VectorArg = dyn_cast<ExtVectorType>(Arg)) { + if (const ExtVectorType *VectorArg = dyn_cast<ExtVectorType>(ArgDesug)) { // Perform deduction on the element types. if (Sema::TemplateDeductionResult Result = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, @@ -2089,8 +2089,8 @@ Deduced); } - if (const DependentSizedExtVectorType *VectorArg - = dyn_cast<DependentSizedExtVectorType>(Arg)) { + if (const DependentSizedExtVectorType *VectorArg = + dyn_cast<DependentSizedExtVectorType>(ArgDesug)) { // Perform deduction on the element types. if (Sema::TemplateDeductionResult Result = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, @@ -2118,11 +2118,13 @@ // T __attribute__((matrix_type(<integral constant>, // <integral constant>))) case Type::ConstantMatrix: { - const ConstantMatrixType *MatrixArg = dyn_cast<ConstantMatrixType>(Arg); + const ConstantMatrixType *MatrixArg = + dyn_cast<ConstantMatrixType>(ArgDesug); if (!MatrixArg) return Sema::TDK_NonDeducedMismatch; - const ConstantMatrixType *MatrixParam = cast<ConstantMatrixType>(Param); + const ConstantMatrixType *MatrixParam = + cast<ConstantMatrixType>(ParDesug); // Check that the dimensions are the same if (MatrixParam->getNumRows() != MatrixArg->getNumRows() || MatrixParam->getNumColumns() != MatrixArg->getNumColumns()) { @@ -2135,13 +2137,13 @@ } case Type::DependentSizedMatrix: { - const MatrixType *MatrixArg = dyn_cast<MatrixType>(Arg); + const MatrixType *MatrixArg = dyn_cast<MatrixType>(ArgDesug); if (!MatrixArg) return Sema::TDK_NonDeducedMismatch; // Check the element type of the matrixes. const DependentSizedMatrixType *MatrixParam = - cast<DependentSizedMatrixType>(Param); + cast<DependentSizedMatrixType>(ParDesug); if (Sema::TemplateDeductionResult Result = DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, MatrixParam->getElementType(), @@ -2212,10 +2214,10 @@ // T __attribute__(((address_space(N)))) case Type::DependentAddressSpace: { const DependentAddressSpaceType *AddressSpaceParam = - cast<DependentAddressSpaceType>(Param); + cast<DependentAddressSpaceType>(ParDesug); if (const DependentAddressSpaceType *AddressSpaceArg = - dyn_cast<DependentAddressSpaceType>(Arg)) { + dyn_cast<DependentAddressSpaceType>(ArgDesug)) { // Perform deduction on the pointer type. if (Sema::TemplateDeductionResult Result = DeduceTemplateArgumentsByTypeMatch( @@ -2234,16 +2236,17 @@ Deduced); } - if (isTargetAddressSpace(Arg.getAddressSpace())) { + if (isTargetAddressSpace(ArgDesug.getAddressSpace())) { llvm::APSInt ArgAddressSpace(S.Context.getTypeSize(S.Context.IntTy), false); - ArgAddressSpace = toTargetAddressSpace(Arg.getAddressSpace()); + ArgAddressSpace = toTargetAddressSpace(ArgDesug.getAddressSpace()); // Perform deduction on the pointer types. if (Sema::TemplateDeductionResult Result = DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, AddressSpaceParam->getPointeeType(), - S.Context.removeAddrSpaceQualType(Arg), Info, Deduced, TDF)) + S.Context.removeAddrSpaceQualType(ArgDesug), Info, Deduced, + TDF)) return Result; // Perform deduction on the address space, if we can. @@ -2260,9 +2263,9 @@ return Sema::TDK_NonDeducedMismatch; } case Type::DependentExtInt: { - const auto *IntParam = cast<DependentExtIntType>(Param); + const auto *IntParam = cast<DependentExtIntType>(ParDesug); - if (const auto *IntArg = dyn_cast<ExtIntType>(Arg)){ + if (const auto *IntArg = dyn_cast<ExtIntType>(ArgDesug)) { if (IntParam->isUnsigned() != IntArg->isUnsigned()) return Sema::TDK_NonDeducedMismatch; @@ -2279,7 +2282,7 @@ Deduced); } - if (const auto *IntArg = dyn_cast<DependentExtIntType>(Arg)) { + if (const auto *IntArg = dyn_cast<DependentExtIntType>(ArgDesug)) { if (IntParam->isUnsigned() != IntArg->isUnsigned()) return Sema::TDK_NonDeducedMismatch; return Sema::TDK_Success; @@ -2300,7 +2303,7 @@ case Type::Pipe: // No template argument deduction for these types return Sema::TDK_Success; - } + } llvm_unreachable("Invalid Type Class!"); } @@ -2366,43 +2369,40 @@ if (Arg.getKind() == TemplateArgument::Integral) { if (hasSameExtendedValue(Param.getAsIntegral(), Arg.getAsIntegral())) return Sema::TDK_Success; - - Info.FirstArg = Param; - Info.SecondArg = Arg; - return Sema::TDK_NonDeducedMismatch; - } - - if (Arg.getKind() == TemplateArgument::Expression) { - Info.FirstArg = Param; - Info.SecondArg = Arg; - return Sema::TDK_NonDeducedMismatch; } - Info.FirstArg = Param; Info.SecondArg = Arg; return Sema::TDK_NonDeducedMismatch; - case TemplateArgument::Expression: + case TemplateArgument::Expression: { + auto *E = Param.getAsExpr(); + if (!E->isValueDependent()) { + if (const auto Int = E->getIntegerConstantExpr(S.Context)) { + if (Arg.getKind() == TemplateArgument::Integral) { + if (hasSameExtendedValue(*Int, Arg.getAsIntegral())) + return Sema::TDK_Success; + } + Info.FirstArg = Param; + Info.SecondArg = Arg; + return Sema::TDK_NonDeducedMismatch; + } + } if (const NonTypeTemplateParmDecl *NTTP = - getDeducedParameterFromExpr(Info, Param.getAsExpr())) { + getDeducedParameterFromExpr(Info, E)) { if (Arg.getKind() == TemplateArgument::Integral) - return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, - Arg.getAsIntegral(), - Arg.getIntegralType(), - /*ArrayBound=*/false, - Info, Deduced); + return DeduceNonTypeTemplateArgument( + S, TemplateParams, NTTP, Arg.getAsIntegral(), Arg.getIntegralType(), + /*ArrayBound=*/false, Info, Deduced); if (Arg.getKind() == TemplateArgument::NullPtr) - return DeduceNullPtrTemplateArgument(S, TemplateParams, NTTP, - Arg.getNullPtrType(), - Info, Deduced); + return DeduceNullPtrTemplateArgument( + S, TemplateParams, NTTP, Arg.getNullPtrType(), Info, Deduced); if (Arg.getKind() == TemplateArgument::Expression) return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, Arg.getAsExpr(), Info, Deduced); if (Arg.getKind() == TemplateArgument::Declaration) - return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, - Arg.getAsDecl(), - Arg.getParamTypeForDecl(), - Info, Deduced); + return DeduceNonTypeTemplateArgument( + S, TemplateParams, NTTP, Arg.getAsDecl(), Arg.getParamTypeForDecl(), + Info, Deduced); Info.FirstArg = Param; Info.SecondArg = Arg; @@ -2411,7 +2411,7 @@ // Can't deduce anything, but that's okay. return Sema::TDK_Success; - + } case TemplateArgument::Pack: llvm_unreachable("Argument packs should be expanded by the caller!"); } @@ -4358,7 +4358,7 @@ bool HasDeducedReturnType = false; if (getLangOpts().CPlusPlus14 && IsAddressOfFunction && Function->getReturnType()->getContainedAutoType()) { - FunctionType = SubstAutoType(FunctionType, Context.DependentTy); + FunctionType = SubstAutoTypeDependent(FunctionType); HasDeducedReturnType = true; } @@ -4792,12 +4792,8 @@ ExprResult ER = CheckPlaceholderExpr(Init); if (ER.isInvalid()) return DAR_FailedAlreadyDiagnosed; - Init = ER.get(); - QualType Deduced = BuildDecltypeType(Init, Init->getBeginLoc(), false); - if (Deduced.isNull()) - return DAR_FailedAlreadyDiagnosed; - // FIXME: Support a non-canonical deduced type for 'auto'. - Deduced = Context.getCanonicalType(Deduced); + QualType Deduced = getDecltypeForExpr(ER.get()); + assert(!Deduced.isNull()); if (AT->isConstrained() && !IgnoreConstraints) { auto ConstraintsResult = CheckDeducedPlaceholderConstraints(*this, *AT, @@ -4832,7 +4828,7 @@ Context, Loc, Loc, TemplParamPtr, Loc, nullptr); QualType FuncParam = - SubstituteDeducedTypeTransform(*this, TemplArg, /*UseTypeSugar*/false) + SubstituteDeducedTypeTransform(*this, TemplArg, /*UseTypeSugar*/ true) .Apply(Type); assert(!FuncParam.isNull() && "substituting template parameter for 'auto' failed"); @@ -4946,27 +4942,29 @@ QualType Sema::SubstAutoType(QualType TypeWithAuto, QualType TypeToReplaceAuto) { - if (TypeToReplaceAuto->isDependentType()) - return SubstituteDeducedTypeTransform( - *this, DependentAuto{ - TypeToReplaceAuto->containsUnexpandedParameterPack()}) - .TransformType(TypeWithAuto); + assert(TypeToReplaceAuto != Context.DependentTy); return SubstituteDeducedTypeTransform(*this, TypeToReplaceAuto) .TransformType(TypeWithAuto); } TypeSourceInfo *Sema::SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto, QualType TypeToReplaceAuto) { - if (TypeToReplaceAuto->isDependentType()) - return SubstituteDeducedTypeTransform( - *this, - DependentAuto{ - TypeToReplaceAuto->containsUnexpandedParameterPack()}) - .TransformType(TypeWithAuto); + assert(TypeToReplaceAuto != Context.DependentTy); return SubstituteDeducedTypeTransform(*this, TypeToReplaceAuto) .TransformType(TypeWithAuto); } +QualType Sema::SubstAutoTypeDependent(QualType TypeWithAuto) { + return SubstituteDeducedTypeTransform(*this, DependentAuto{false}) + .TransformType(TypeWithAuto); +} + +TypeSourceInfo * +Sema::SubstAutoTypeSourceInfoDependent(TypeSourceInfo *TypeWithAuto) { + return SubstituteDeducedTypeTransform(*this, DependentAuto{false}) + .TransformType(TypeWithAuto); +} + QualType Sema::ReplaceAutoType(QualType TypeWithAuto, QualType TypeToReplaceAuto) { return SubstituteDeducedTypeTransform(*this, TypeToReplaceAuto, @@ -5161,6 +5159,10 @@ Args2.resize(NumComparedArguments); if (Reversed) std::reverse(Args2.begin(), Args2.end()); + + auto TF = [&S](QualType T) { return S.Context.getCanonicalType(T); }; + llvm::transform(Args1, Args1.begin(), TF); + llvm::transform(Args2, Args2.begin(), TF); if (DeduceTemplateArguments(S, TemplateParams, Args2.data(), Args2.size(), Args1.data(), Args1.size(), Info, Deduced, TDF_None, /*PartialOrdering=*/true)) Index: clang/lib/Sema/SemaTemplate.cpp =================================================================== --- clang/lib/Sema/SemaTemplate.cpp +++ clang/lib/Sema/SemaTemplate.cpp @@ -1260,15 +1260,15 @@ BuildDeclRefExpr(NTTP, NTTP->getType(), VK_PRValue, NTTP->getLocation()); if (!Ref) return true; - ExprResult ImmediatelyDeclaredConstraint = - formImmediatelyDeclaredConstraint( - *this, TL.getNestedNameSpecifierLoc(), TL.getConceptNameInfo(), - TL.getNamedConcept(), TL.getLAngleLoc(), TL.getRAngleLoc(), - BuildDecltypeType(Ref, NTTP->getLocation()), NTTP->getLocation(), - [&] (TemplateArgumentListInfo &ConstraintArgs) { - for (unsigned I = 0, C = TL.getNumArgs(); I != C; ++I) - ConstraintArgs.addArgument(TL.getArgLoc(I)); - }, EllipsisLoc); + ExprResult ImmediatelyDeclaredConstraint = formImmediatelyDeclaredConstraint( + *this, TL.getNestedNameSpecifierLoc(), TL.getConceptNameInfo(), + TL.getNamedConcept(), TL.getLAngleLoc(), TL.getRAngleLoc(), + BuildDecltypeType(Ref), NTTP->getLocation(), + [&](TemplateArgumentListInfo &ConstraintArgs) { + for (unsigned I = 0, C = TL.getNumArgs(); I != C; ++I) + ConstraintArgs.addArgument(TL.getArgLoc(I)); + }, + EllipsisLoc); if (ImmediatelyDeclaredConstraint.isInvalid() || !ImmediatelyDeclaredConstraint.isUsable()) return true; @@ -1290,7 +1290,7 @@ // - an identifier associated by name lookup with a non-type // template-parameter declared with a type that contains a // placeholder type (7.1.7.4), - TSI = SubstAutoTypeSourceInfo(TSI, Context.DependentTy); + TSI = SubstAutoTypeSourceInfoDependent(TSI); } return CheckNonTypeTemplateParameterType(TSI->getType(), Loc); @@ -10888,7 +10888,7 @@ // - an identifier associated by name lookup with a non-type // template-parameter declared with a type that contains a // placeholder type (7.1.7.4), - NewTSI = SubstAutoTypeSourceInfo(NewTSI, Context.DependentTy); + NewTSI = SubstAutoTypeSourceInfoDependent(NewTSI); } if (NewTSI != NTTP->getTypeSourceInfo()) { Index: clang/lib/Sema/SemaStmt.cpp =================================================================== --- clang/lib/Sema/SemaStmt.cpp +++ clang/lib/Sema/SemaStmt.cpp @@ -2729,7 +2729,7 @@ if (auto *DD = dyn_cast<DecompositionDecl>(LoopVar)) for (auto *Binding : DD->bindings()) Binding->setType(Context.DependentTy); - LoopVar->setType(SubstAutoType(LoopVar->getType(), Context.DependentTy)); + LoopVar->setType(SubstAutoTypeDependent(LoopVar->getType())); } } else if (!BeginDeclStmt.get()) { SourceLocation RangeLoc = RangeVar->getLocation(); Index: clang/lib/Sema/SemaLambda.cpp =================================================================== --- clang/lib/Sema/SemaLambda.cpp +++ clang/lib/Sema/SemaLambda.cpp @@ -373,7 +373,7 @@ const FunctionProtoType *FPT = MethodType->castAs<FunctionProtoType>(); QualType Result = FPT->getReturnType(); if (Result->isUndeducedType()) { - Result = SubstAutoType(Result, Context.DependentTy); + Result = SubstAutoTypeDependent(Result); MethodType = Context.getFunctionType(Result, FPT->getParamTypes(), FPT->getExtProtoInfo()); } Index: clang/lib/Sema/SemaInit.cpp =================================================================== --- clang/lib/Sema/SemaInit.cpp +++ clang/lib/Sema/SemaInit.cpp @@ -9969,7 +9969,7 @@ auto TemplateName = DeducedTST->getTemplateName(); if (TemplateName.isDependent()) - return SubstAutoType(TSInfo->getType(), Context.DependentTy); + return SubstAutoTypeDependent(TSInfo->getType()); // We can only perform deduction for class templates. auto *Template = @@ -9988,7 +9988,7 @@ Diag(TSInfo->getTypeLoc().getBeginLoc(), diag::warn_cxx14_compat_class_template_argument_deduction) << TSInfo->getTypeLoc().getSourceRange() << 0; - return SubstAutoType(TSInfo->getType(), Context.DependentTy); + return SubstAutoTypeDependent(TSInfo->getType()); } // FIXME: Perform "exact type" matching first, per CWG discussion? Index: clang/lib/Sema/SemaExprCXX.cpp =================================================================== --- clang/lib/Sema/SemaExprCXX.cpp +++ clang/lib/Sema/SemaExprCXX.cpp @@ -468,7 +468,7 @@ assert(DS.getTypeSpecType() == DeclSpec::TST_decltype && "unexpected type in getDestructorType"); - QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc()); + QualType T = BuildDecltypeType(DS.getRepAsExpr()); // If we know the type of the object, check that the correct destructor // type was named now; we can give better diagnostics this way. @@ -7727,8 +7727,7 @@ return true; } - QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc(), - false); + QualType T = BuildDecltypeType(DS.getRepAsExpr(), /*AsUnevaluated=*/false); TypeLocBuilder TLB; DecltypeTypeLoc DecltypeTL = TLB.push<DecltypeTypeLoc>(T); Index: clang/lib/Sema/SemaDeclCXX.cpp =================================================================== --- clang/lib/Sema/SemaDeclCXX.cpp +++ clang/lib/Sema/SemaDeclCXX.cpp @@ -4215,7 +4215,7 @@ if (BaseType.isNull()) return true; } else if (DS.getTypeSpecType() == TST_decltype) { - BaseType = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc()); + BaseType = BuildDecltypeType(DS.getRepAsExpr()); } else if (DS.getTypeSpecType() == TST_decltype_auto) { Diag(DS.getTypeSpecTypeLoc(), diag::err_decltype_auto_invalid); return true; Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ clang/lib/Sema/SemaDecl.cpp @@ -3608,14 +3608,14 @@ // defined, copy the deduced value from the old declaration. AutoType *OldAT = Old->getReturnType()->getContainedAutoType(); if (OldAT && OldAT->isDeduced()) { - New->setType( - SubstAutoType(New->getType(), - OldAT->isDependentType() ? Context.DependentTy - : OldAT->getDeducedType())); - NewQType = Context.getCanonicalType( - SubstAutoType(NewQType, - OldAT->isDependentType() ? Context.DependentTy - : OldAT->getDeducedType())); + QualType DT = OldAT->getDeducedType(); + if (DT.isNull()) { + New->setType(SubstAutoTypeDependent(New->getType())); + NewQType = Context.getCanonicalType(SubstAutoTypeDependent(NewQType)); + } else { + New->setType(SubstAutoType(New->getType(), DT)); + NewQType = Context.getCanonicalType(SubstAutoType(NewQType, DT)); + } } } @@ -9252,8 +9252,7 @@ // a friend yet, so 'isDependentContext' on the FD doesn't work. const FunctionProtoType *FPT = NewFD->getType()->castAs<FunctionProtoType>(); - QualType Result = - SubstAutoType(FPT->getReturnType(), Context.DependentTy); + QualType Result = SubstAutoTypeDependent(FPT->getReturnType()); NewFD->setType(Context.getFunctionType(Result, FPT->getParamTypes(), FPT->getExtProtoInfo())); } @@ -12347,7 +12346,7 @@ /*TreatUnavailableAsInvalid=*/false); ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Args, &DclT); if (Result.isInvalid()) { - // If the provied initializer fails to initialize the var decl, + // If the provided initializer fails to initialize the var decl, // we attach a recovery expr for better recovery. auto RecoveryExpr = CreateRecoveryExpr(Init->getBeginLoc(), Init->getEndLoc(), Args); Index: clang/lib/Sema/SemaCXXScopeSpec.cpp =================================================================== --- clang/lib/Sema/SemaCXXScopeSpec.cpp +++ clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -865,7 +865,7 @@ assert(DS.getTypeSpecType() == DeclSpec::TST_decltype); - QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc()); + QualType T = BuildDecltypeType(DS.getRepAsExpr()); if (T.isNull()) return true; Index: clang/lib/AST/Type.cpp =================================================================== --- clang/lib/AST/Type.cpp +++ clang/lib/AST/Type.cpp @@ -4394,10 +4394,10 @@ } AutoType::AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword, - TypeDependence ExtraDependence, + TypeDependence ExtraDependence, QualType Canon, ConceptDecl *TypeConstraintConcept, ArrayRef<TemplateArgument> TypeConstraintArgs) - : DeducedType(Auto, DeducedAsType, ExtraDependence) { + : DeducedType(Auto, DeducedAsType, ExtraDependence, Canon) { AutoTypeBits.Keyword = (unsigned)Keyword; AutoTypeBits.NumArgs = TypeConstraintArgs.size(); this->TypeConstraintConcept = TypeConstraintConcept; Index: clang/lib/AST/ASTImporter.cpp =================================================================== --- clang/lib/AST/ASTImporter.cpp +++ clang/lib/AST/ASTImporter.cpp @@ -1644,36 +1644,48 @@ return Importer.getToContext().getObjCObjectPointerType(*ToPointeeTypeOrErr); } +static Error checkCycle(ASTImporter &Importer, const RecordDecl *RD, + QualType QT) { + const Type *LeafT = QT.getCanonicalType().getTypePtr(); + while (LeafT->isPointerType() || LeafT->isArrayType()) + LeafT = LeafT->getPointeeOrArrayElementType(); + + const auto *RT = dyn_cast<RecordType>(LeafT); + if (!RT) + return Error::success(); + + for (const DeclContext *DC = RT->getDecl(); DC; DC = DC->getParent()) + if (DC == RD) { + Importer.FromDiag(RD->getLocation(), diag::err_unsupported_ast_node) + << RD->Decl::getDeclKindName(); + return make_error<ImportError>(ImportError::UnsupportedConstruct); + } + return Error::success(); +} + //---------------------------------------------------------------------------- // Import Declarations //---------------------------------------------------------------------------- Error ASTNodeImporter::ImportDeclParts( NamedDecl *D, DeclContext *&DC, DeclContext *&LexicalDC, DeclarationName &Name, NamedDecl *&ToD, SourceLocation &Loc) { - // Check if RecordDecl is in FunctionDecl parameters to avoid infinite loop. - // example: int struct_in_proto(struct data_t{int a;int b;} *d); + // Check if FunctionDecl return / parameters are in the RecordDecl context, + // in order to avoid an infinite loop. + // Example: int struct_in_proto(struct data_t{int a;int b;} *d); + // Example: auto struct_in_body() { struct X {}; return X(); } // FIXME: We could support these constructs by importing a different type of - // this parameter and by importing the original type of the parameter only + // this return / parameter and then importing that original type only // after the FunctionDecl is created. See // VisitFunctionDecl::UsedDifferentProtoType. - DeclContext *OrigDC = D->getDeclContext(); - FunctionDecl *FunDecl; - if (isa<RecordDecl>(D) && (FunDecl = dyn_cast<FunctionDecl>(OrigDC)) && - FunDecl->hasBody()) { - auto getLeafPointeeType = [](const Type *T) { - while (T->isPointerType() || T->isArrayType()) { - T = T->getPointeeOrArrayElementType(); - } - return T; - }; - for (const ParmVarDecl *P : FunDecl->parameters()) { - const Type *LeafT = - getLeafPointeeType(P->getType().getCanonicalType().getTypePtr()); - auto *RT = dyn_cast<RecordType>(LeafT); - if (RT && RT->getDecl() == D) { - Importer.FromDiag(D->getLocation(), diag::err_unsupported_ast_node) - << D->getDeclKindName(); - return make_error<ImportError>(ImportError::UnsupportedConstruct); + { + const auto *FD = dyn_cast<FunctionDecl>(D->getDeclContext()); + const auto *RD = dyn_cast<RecordDecl>(D); + if (RD && FD && FD->hasBody()) { + if (Error Err = checkCycle(Importer, RD, FD->getReturnType())) + return Err; + for (const ParmVarDecl *P : FD->parameters()) { + if (Error Err = checkCycle(Importer, RD, P->getType())) + return Err; } } } Index: clang/lib/AST/ASTContext.cpp =================================================================== --- clang/lib/AST/ASTContext.cpp +++ clang/lib/AST/ASTContext.cpp @@ -4817,6 +4817,23 @@ return QualType(Spec, 0); } +static bool +getCanonicalTemplateArguments(const ASTContext &C, + ArrayRef<TemplateArgument> OrigArgs, + SmallVectorImpl<TemplateArgument> &CanonArgs) { + bool AnyNonCanonArgs = false; + unsigned NumArgs = OrigArgs.size(); + CanonArgs.resize(NumArgs); + for (unsigned I = 0; I != NumArgs; ++I) { + const TemplateArgument &OrigArg = OrigArgs[I]; + TemplateArgument &CanonArg = CanonArgs[I]; + CanonArg = C.getCanonicalTemplateArgument(OrigArg); + if (!CanonArg.structurallyEquals(OrigArg)) + AnyNonCanonArgs = true; + } + return AnyNonCanonArgs; +} + QualType ASTContext::getCanonicalTemplateSpecializationType( TemplateName Template, ArrayRef<TemplateArgument> Args) const { assert(!Template.getAsDependentTemplateName() && @@ -4829,10 +4846,7 @@ // Build the canonical template specialization type. TemplateName CanonTemplate = getCanonicalTemplateName(Template); SmallVector<TemplateArgument, 4> CanonArgs; - unsigned NumArgs = Args.size(); - CanonArgs.reserve(NumArgs); - for (const TemplateArgument &Arg : Args) - CanonArgs.push_back(getCanonicalTemplateArgument(Arg)); + ::getCanonicalTemplateArguments(*this, Args, CanonArgs); // Determine whether this canonical template specialization type already // exists. @@ -4847,7 +4861,7 @@ if (!Spec) { // Allocate a new canonical template specialization type. void *Mem = Allocate((sizeof(TemplateSpecializationType) + - sizeof(TemplateArgument) * NumArgs), + sizeof(TemplateArgument) * CanonArgs.size()), TypeAlignment); Spec = new (Mem) TemplateSpecializationType(CanonTemplate, CanonArgs, @@ -4989,14 +5003,9 @@ ElaboratedTypeKeyword CanonKeyword = Keyword; if (Keyword == ETK_None) CanonKeyword = ETK_Typename; - bool AnyNonCanonArgs = false; - unsigned NumArgs = Args.size(); - SmallVector<TemplateArgument, 16> CanonArgs(NumArgs); - for (unsigned I = 0; I != NumArgs; ++I) { - CanonArgs[I] = getCanonicalTemplateArgument(Args[I]); - if (!CanonArgs[I].structurallyEquals(Args[I])) - AnyNonCanonArgs = true; - } + SmallVector<TemplateArgument, 16> CanonArgs; + bool AnyNonCanonArgs = + ::getCanonicalTemplateArguments(*this, Args, CanonArgs); QualType Canon; if (AnyNonCanonArgs || CanonNNS != NNS || CanonKeyword != Keyword) { @@ -5009,7 +5018,7 @@ } void *Mem = Allocate((sizeof(DependentTemplateSpecializationType) + - sizeof(TemplateArgument) * NumArgs), + sizeof(TemplateArgument) * Args.size()), TypeAlignment); T = new (Mem) DependentTemplateSpecializationType(Keyword, NNS, Name, Args, Canon); @@ -5594,15 +5603,10 @@ return QualType(ut, 0); } -/// getAutoType - Return the uniqued reference to the 'auto' type which has been -/// deduced to the given type, or to the canonical undeduced 'auto' type, or the -/// canonical deduced-but-dependent 'auto' type. -QualType -ASTContext::getAutoType(QualType DeducedType, AutoTypeKeyword Keyword, - bool IsDependent, bool IsPack, - ConceptDecl *TypeConstraintConcept, - ArrayRef<TemplateArgument> TypeConstraintArgs) const { - assert((!IsPack || IsDependent) && "only use IsPack for a dependent pack"); +QualType ASTContext::getAutoTypeInternal( + QualType DeducedType, AutoTypeKeyword Keyword, bool IsDependent, + bool IsPack, ConceptDecl *TypeConstraintConcept, + ArrayRef<TemplateArgument> TypeConstraintArgs, bool IsCanon) const { if (DeducedType.isNull() && Keyword == AutoTypeKeyword::Auto && !TypeConstraintConcept && !IsDependent) return getAutoDeductType(); @@ -5615,21 +5619,52 @@ if (AutoType *AT = AutoTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(AT, 0); + QualType Canon; + if (!IsCanon) { + if (DeducedType.isNull()) { + SmallVector<TemplateArgument, 4> CanonArgs; + bool AnyNonCanonArgs = + ::getCanonicalTemplateArguments(*this, TypeConstraintArgs, CanonArgs); + if (AnyNonCanonArgs) { + Canon = getAutoTypeInternal(QualType(), Keyword, IsDependent, IsPack, + TypeConstraintConcept, CanonArgs, true); + // Find the insert position again. + AutoTypes.FindNodeOrInsertPos(ID, InsertPos); + } + } else { + Canon = DeducedType.getCanonicalType(); + } + } + void *Mem = Allocate(sizeof(AutoType) + - sizeof(TemplateArgument) * TypeConstraintArgs.size(), + sizeof(TemplateArgument) * TypeConstraintArgs.size(), TypeAlignment); auto *AT = new (Mem) AutoType( DeducedType, Keyword, (IsDependent ? TypeDependence::DependentInstantiation : TypeDependence::None) | (IsPack ? TypeDependence::UnexpandedPack : TypeDependence::None), - TypeConstraintConcept, TypeConstraintArgs); + Canon, TypeConstraintConcept, TypeConstraintArgs); Types.push_back(AT); - if (InsertPos) - AutoTypes.InsertNode(AT, InsertPos); + AutoTypes.InsertNode(AT, InsertPos); return QualType(AT, 0); } +/// getAutoType - Return the uniqued reference to the 'auto' type which has been +/// deduced to the given type, or to the canonical undeduced 'auto' type, or the +/// canonical deduced-but-dependent 'auto' type. +QualType +ASTContext::getAutoType(QualType DeducedType, AutoTypeKeyword Keyword, + bool IsDependent, bool IsPack, + ConceptDecl *TypeConstraintConcept, + ArrayRef<TemplateArgument> TypeConstraintArgs) const { + assert((!IsPack || IsDependent) && "only use IsPack for a dependent pack"); + assert((!IsDependent || DeducedType.isNull()) && + "A dependent auto should be undeduced"); + return getAutoTypeInternal(DeducedType, Keyword, IsDependent, IsPack, + TypeConstraintConcept, TypeConstraintArgs); +} + /// Return the uniqued reference to the deduced template specialization type /// which has been deduced to the given type, or to the canonical undeduced /// such type, or the canonical deduced-but-dependent such type. @@ -5647,8 +5682,7 @@ auto *DTST = new (*this, TypeAlignment) DeducedTemplateSpecializationType(Template, DeducedType, IsDependent); Types.push_back(DTST); - if (InsertPos) - DeducedTemplateSpecializationTypes.InsertNode(DTST, InsertPos); + DeducedTemplateSpecializationTypes.InsertNode(DTST, InsertPos); return QualType(DTST, 0); } @@ -5685,7 +5719,7 @@ if (AutoDeductTy.isNull()) AutoDeductTy = QualType(new (*this, TypeAlignment) AutoType(QualType(), AutoTypeKeyword::Auto, - TypeDependence::None, + TypeDependence::None, QualType(), /*concept*/ nullptr, /*args*/ {}), 0); return AutoDeductTy; Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -2348,11 +2348,13 @@ const CXXScopeSpec &SS, QualType T, TagDecl *OwnedTagDecl = nullptr); - QualType BuildTypeofExprType(Expr *E, SourceLocation Loc); + // Returns the underlying type of a decltype with the given expression. + QualType getDecltypeForExpr(Expr *E); + + QualType BuildTypeofExprType(Expr *E); /// If AsUnevaluated is false, E is treated as though it were an evaluated /// context, such as when building a type for decltype(auto). - QualType BuildDecltypeType(Expr *E, SourceLocation Loc, - bool AsUnevaluated = true); + QualType BuildDecltypeType(Expr *E, bool AsUnevaluated = true); QualType BuildUnaryTransformType(QualType BaseType, UnaryTransformType::UTTKind UKind, SourceLocation Loc); @@ -8552,6 +8554,14 @@ /// Substitute Replacement for auto in TypeWithAuto TypeSourceInfo* SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto, QualType Replacement); + + // Substitute auto in TypeWithAuto for a Dependent auto type + QualType SubstAutoTypeDependent(QualType TypeWithAuto); + + // Substitute auto in TypeWithAuto for a Dependent auto type + TypeSourceInfo * + SubstAutoTypeSourceInfoDependent(TypeSourceInfo *TypeWithAuto); + /// Completely replace the \c auto in \p TypeWithAuto by /// \p Replacement. This does not retain any \c auto type sugar. QualType ReplaceAutoType(QualType TypeWithAuto, QualType Replacement); Index: clang/include/clang/AST/Type.h =================================================================== --- clang/include/clang/AST/Type.h +++ clang/include/clang/AST/Type.h @@ -4944,29 +4944,31 @@ /// type-dependent, there is no deduced type and the type is canonical. In /// the latter case, it is also a dependent type. class DeducedType : public Type { + QualType DeducedAsType; + protected: DeducedType(TypeClass TC, QualType DeducedAsType, - TypeDependence ExtraDependence) - : Type(TC, - // FIXME: Retain the sugared deduced type? - DeducedAsType.isNull() ? QualType(this, 0) - : DeducedAsType.getCanonicalType(), + TypeDependence ExtraDependence, QualType Canon) + : Type(TC, Canon, ExtraDependence | (DeducedAsType.isNull() ? TypeDependence::None : DeducedAsType->getDependence() & - ~TypeDependence::VariablyModified)) {} + ~TypeDependence::VariablyModified)), + DeducedAsType(DeducedAsType) {} public: - bool isSugared() const { return !isCanonicalUnqualified(); } - QualType desugar() const { return getCanonicalTypeInternal(); } + bool isSugared() const { return !DeducedAsType.isNull(); } + QualType desugar() const { + return isSugared() ? DeducedAsType : QualType(this, 0); + } /// Get the type deduced for this placeholder type, or null if it's /// either not been deduced or was deduced to a dependent type. QualType getDeducedType() const { - return !isCanonicalUnqualified() ? getCanonicalTypeInternal() : QualType(); + return DeducedAsType.isNull() ? QualType() : DeducedAsType; } bool isDeduced() const { - return !isCanonicalUnqualified() || isDependentType(); + return !DeducedAsType.isNull() || isDependentType(); } static bool classof(const Type *T) { @@ -4983,7 +4985,7 @@ ConceptDecl *TypeConstraintConcept; AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword, - TypeDependence ExtraDependence, ConceptDecl *CD, + TypeDependence ExtraDependence, QualType Canon, ConceptDecl *CD, ArrayRef<TemplateArgument> TypeConstraintArgs); const TemplateArgument *getArgBuffer() const { @@ -5057,7 +5059,9 @@ toTypeDependence(Template.getDependence()) | (IsDeducedAsDependent ? TypeDependence::DependentInstantiation - : TypeDependence::None)), + : TypeDependence::None), + DeducedAsType.isNull() ? QualType(this, 0) + : DeducedAsType.getCanonicalType()), Template(Template) {} public: Index: clang/include/clang/AST/ASTContext.h =================================================================== --- clang/include/clang/AST/ASTContext.h +++ clang/include/clang/AST/ASTContext.h @@ -1525,6 +1525,12 @@ QualType getFunctionTypeInternal(QualType ResultTy, ArrayRef<QualType> Args, const FunctionProtoType::ExtProtoInfo &EPI, bool OnlyWantCanonical) const; + QualType + getAutoTypeInternal(QualType DeducedType, AutoTypeKeyword Keyword, + bool IsDependent, bool IsPack = false, + ConceptDecl *TypeConstraintConcept = nullptr, + ArrayRef<TemplateArgument> TypeConstraintArgs = {}, + bool IsCanon = false) const; public: /// Return the unique reference to the type for the specified type Index: clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-owning-memory.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-owning-memory.cpp +++ clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-owning-memory.cpp @@ -91,13 +91,9 @@ // FIXME:, flow analysis for the case of reassignment. Value must be released before owned_int6 = owned_int3; // BAD, because reassignment without resource release - auto owned_int7 = returns_owner1(); // Bad, since type deduction eliminates the owner wrapper - // CHECK-NOTES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>' - // CHECK-NOTES: [[@LINE-2]]:3: note: type deduction did not result in an owner + auto owned_int7 = returns_owner1(); // Ok, since type deduction does not eliminate the owner wrapper - const auto owned_int8 = returns_owner2(); // Bad, since type deduction eliminates the owner wrapper - // CHECK-NOTES: [[@LINE-1]]:3: warning: initializing non-owner 'int *const' with a newly created 'gsl::owner<>' - // CHECK-NOTES: [[@LINE-2]]:3: note: type deduction did not result in an owner + const auto owned_int8 = returns_owner2(); // Ok, since type deduction does not eliminate the owner wrapper gsl::owner<int *> owned_int9 = returns_owner1(); // Ok int *unowned_int3 = returns_owner1(); // Bad @@ -285,15 +281,12 @@ ClassWithOwner C2{A}; // Bad, since the owner would be initialized with an non-owner, but catched in the class ClassWithOwner C3{gsl::owner<ArbitraryClass *>(new ArbitraryClass)}; // Ok - const auto Owner1 = C3.buggy_but_returns_owner(); // BAD, deduces Owner1 to ArbitraryClass *const - // CHECK-NOTES: [[@LINE-1]]:3: warning: initializing non-owner 'ArbitraryClass *const' with a newly created 'gsl::owner<>' - // CHECK-NOTES: [[@LINE-2]]:3: note: type deduction did not result in an owner + const auto Owner1 = C3.buggy_but_returns_owner(); // Ok, deduces Owner1 to owner<ArbitraryClass *> const - auto Owner2 = C2.buggy_but_returns_owner(); // BAD, deduces Owner2 to ArbitraryClass * - // CHECK-NOTES: [[@LINE-1]]:3: warning: initializing non-owner 'ArbitraryClass *' with a newly created 'gsl::owner<>' - // CHECK-NOTES: [[@LINE-2]]:3: note: type deduction did not result in an owner + auto Owner2 = C2.buggy_but_returns_owner(); //Ok, deduces Owner2 to owner<ArbitraryClass *> - Owner2 = &A; // Ok, since type deduction did NOT result in owner<int*> + Owner2 = &A; // BAD, since type deduction resulted in owner<ArbitraryClass *> + // CHECK-NOTES: [[@LINE-1]]:3: warning: expected assignment source to be of type 'gsl::owner<>'; got 'ArbitraryClass *' gsl::owner<ArbitraryClass *> Owner3 = C1.buggy_but_returns_owner(); // Ok, still an owner Owner3 = &A; // Bad, since assignment of non-owner to owner Index: clang-tools-extra/test/clang-tidy/checkers/cert-static-object-exception.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/checkers/cert-static-object-exception.cpp +++ clang-tools-extra/test/clang-tidy/checkers/cert-static-object-exception.cpp @@ -256,7 +256,7 @@ return []{ S s; return s; }; } }; -auto Okay4 = []{ U u; return u.getBadLambda(); }(); +auto Okay4 = []() noexcept { U u; return u.getBadLambda(); }(); auto NotOkay3 = []() noexcept { U u; return u.getBadLambda(); }()(); // Because the lambda returned and called is not noexcept // CHECK-EXCEPTIONS: :[[@LINE-1]]:6: warning: initialization of 'NotOkay3' with static storage duration may throw an exception that cannot be caught [cert-err58-cpp] // CHECK-EXCEPTIONS: :[[@LINE-6]]:12: note: possibly throwing function declared here @@ -272,4 +272,8 @@ // FIXME: the above should be diagnosed because the capture init can trigger // an exception when constructing the Bad object. #endif // NONEXCEPTIONS + +auto NotOkay5 = []() { U u; return u.getBadLambda(); }(); +// CHECK-EXCEPTIONS: :[[@LINE-1]]:6: warning: initialization of 'NotOkay5' with static storage duration may throw an exception that cannot be caught [cert-err58-cpp] +// CHECK-EXCEPTIONS: :[[@LINE-2]]:17: note: possibly throwing function declared here } Index: clang-tools-extra/clangd/unittests/tweaks/ExpandAutoTypeTests.cpp =================================================================== --- clang-tools-extra/clangd/unittests/tweaks/ExpandAutoTypeTests.cpp +++ clang-tools-extra/clangd/unittests/tweaks/ExpandAutoTypeTests.cpp @@ -57,7 +57,7 @@ EXPECT_UNAVAILABLE("au^to x = []{};"); // inline namespaces EXPECT_EQ(apply("au^to x = inl_ns::Visible();"), - "Visible x = inl_ns::Visible();"); + "inl_ns::Visible x = inl_ns::Visible();"); // local class EXPECT_EQ(apply("namespace x { void y() { struct S{}; ^auto z = S(); } }"), "namespace x { void y() { struct S{}; S z = S(); } }"); @@ -67,8 +67,9 @@ EXPECT_EQ(apply("ns::Class * foo() { au^to c = foo(); }"), "ns::Class * foo() { ns::Class * c = foo(); }"); - EXPECT_EQ(apply("void ns::Func() { au^to x = new ns::Class::Nested{}; }"), - "void ns::Func() { Class::Nested * x = new ns::Class::Nested{}; }"); + EXPECT_EQ( + apply("void ns::Func() { au^to x = new ns::Class::Nested{}; }"), + "void ns::Func() { ns::Class::Nested * x = new ns::Class::Nested{}; }"); EXPECT_UNAVAILABLE("dec^ltype(au^to) x = 10;"); // expanding types in structured bindings is syntactically invalid. Index: clang-tools-extra/clangd/unittests/InlayHintTests.cpp =================================================================== --- clang-tools-extra/clangd/unittests/InlayHintTests.cpp +++ clang-tools-extra/clangd/unittests/InlayHintTests.cpp @@ -466,7 +466,8 @@ } } )cpp", - ExpectedHint{": S1", "x"}, ExpectedHint{": Inner<int>", "y"}); + ExpectedHint{": S1", "x"}, + ExpectedHint{": S2::Inner<int>", "y"}); } TEST(TypeHints, Lambda) { Index: clang-tools-extra/clangd/unittests/HoverTests.cpp =================================================================== --- clang-tools-extra/clangd/unittests/HoverTests.cpp +++ clang-tools-extra/clangd/unittests/HoverTests.cpp @@ -461,7 +461,7 @@ [](HoverInfo &HI) { HI.Name = "auto"; HI.Kind = index::SymbolKind::TypeAlias; - HI.Definition = "class Foo<int>"; + HI.Definition = "Foo<int>"; }}, // auto on specialized template {R"cpp( @@ -474,7 +474,7 @@ [](HoverInfo &HI) { HI.Name = "auto"; HI.Kind = index::SymbolKind::TypeAlias; - HI.Definition = "class Foo<int>"; + HI.Definition = "Foo<int>"; }}, // macro @@ -648,7 +648,7 @@ [](HoverInfo &HI) { HI.Name = "auto"; HI.Kind = index::SymbolKind::TypeAlias; - HI.Definition = "class Foo<X>"; + HI.Definition = "Foo<X>"; }}, {// Falls back to primary template, when the type is not instantiated. R"cpp( @@ -2024,7 +2024,7 @@ [](HoverInfo &HI) { HI.Name = "auto"; HI.Kind = index::SymbolKind::TypeAlias; - HI.Definition = "int"; + HI.Definition = "int_type"; }}, { R"cpp(// auto on alias @@ -2035,7 +2035,7 @@ [](HoverInfo &HI) { HI.Name = "auto"; HI.Kind = index::SymbolKind::TypeAlias; - HI.Definition = "struct cls"; + HI.Definition = "cls_type"; HI.Documentation = "auto on alias"; }}, { @@ -2047,7 +2047,7 @@ [](HoverInfo &HI) { HI.Name = "auto"; HI.Kind = index::SymbolKind::TypeAlias; - HI.Definition = "struct templ<int>"; + HI.Definition = "templ<int>"; HI.Documentation = "auto on alias"; }}, { Index: clang-tools-extra/clangd/unittests/ASTTests.cpp =================================================================== --- clang-tools-extra/clangd/unittests/ASTTests.cpp +++ clang-tools-extra/clangd/unittests/ASTTests.cpp @@ -43,7 +43,7 @@ namespace ns1 { struct S {}; } ^auto v = ns1::S{}; )cpp", - "struct ns1::S", + "ns1::S", }, { R"cpp( // decltype on struct @@ -63,7 +63,7 @@ ns1::S& j = i; ^decltype(auto) k = j; )cpp", - "struct ns1::S &", + "ns1::S &", }, { R"cpp( // auto on template class @@ -71,7 +71,7 @@ template<typename T> class Foo {}; ^auto v = Foo<X>(); )cpp", - "class Foo<class X>", + "Foo<class X>", }, { R"cpp( // auto on initializer list. @@ -177,8 +177,8 @@ using Bar = Foo; ^auto x = Bar(); )cpp", - // FIXME: it'd be nice if this resolved to the alias instead - "struct Foo", + // It's so nice that this is resolved to the alias instead :-D + "Bar", }, }; for (Test T : Tests) { Index: clang-tools-extra/clangd/FindTarget.cpp =================================================================== --- clang-tools-extra/clangd/FindTarget.cpp +++ clang-tools-extra/clangd/FindTarget.cpp @@ -374,7 +374,7 @@ void VisitDeducedType(const DeducedType *DT) { // FIXME: In practice this doesn't work: the AutoType you find inside // TypeLoc never has a deduced type. https://llvm.org/PR42914 - Outer.add(DT->getDeducedType(), Flags | Rel::Underlying); + Outer.add(DT->getDeducedType(), Flags); } void VisitDeducedTemplateSpecializationType( const DeducedTemplateSpecializationType *DTST) { Index: clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp =================================================================== --- clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp +++ clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp @@ -125,18 +125,22 @@ }; auto IsBoundToType = refersToType(equalsBoundNode("type")); + auto UnlessFunctionType = unless(hasUnqualifiedDesugaredType(functionType())); + auto IsAutoDeducedToPointer = [](const auto &...InnerMatchers) { + return autoType(hasDeducedType( + hasUnqualifiedDesugaredType(pointerType(pointee(InnerMatchers...))))); + }; Finder->addMatcher( - ExplicitSingleVarDecl(hasType(autoType(hasDeducedType( - pointerType(pointee(unless(functionType())))))), + ExplicitSingleVarDecl(hasType(IsAutoDeducedToPointer(UnlessFunctionType)), "auto"), this); Finder->addMatcher( ExplicitSingleVarDeclInTemplate( - allOf(hasType(autoType(hasDeducedType(pointerType( - pointee(hasUnqualifiedType(qualType().bind("type")), - unless(functionType())))))), + allOf(hasType(IsAutoDeducedToPointer( + hasUnqualifiedType(qualType().bind("type")), + UnlessFunctionType)), anyOf(hasAncestor( functionDecl(hasAnyTemplateArgument(IsBoundToType))), hasAncestor(classTemplateSpecializationDecl( Index: clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.cpp =================================================================== --- clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.cpp +++ clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.cpp @@ -20,9 +20,11 @@ if (!getLangOpts().CPlusPlus) return; - const auto AllPointerTypes = anyOf( - hasType(pointerType()), hasType(autoType(hasDeducedType(pointerType()))), - hasType(decltypeType(hasUnderlyingType(pointerType())))); + const auto AllPointerTypes = + anyOf(hasType(pointerType()), + hasType(autoType( + hasDeducedType(hasUnqualifiedDesugaredType(pointerType())))), + hasType(decltypeType(hasUnderlyingType(pointerType())))); // Flag all operators +, -, +=, -=, ++, -- that result in a pointer Finder->addMatcher( Index: clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.cpp =================================================================== --- clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.cpp +++ clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.cpp @@ -134,14 +134,9 @@ // Matching on initialization operations where the initial value is a newly // created owner, but the LHS is not an owner. Finder->addMatcher( - traverse( - TK_AsIs, - namedDecl( - varDecl(eachOf(allOf(hasInitializer(CreatesOwner), - unless(IsOwnerType)), - allOf(hasInitializer(ConsideredOwner), - hasType(autoType().bind("deduced_type"))))) - .bind("bad_owner_creation_variable"))), + traverse(TK_AsIs, namedDecl(varDecl(allOf(hasInitializer(CreatesOwner), + unless(IsOwnerType))) + .bind("bad_owner_creation_variable"))), this); // Match on all function calls that expect owners as arguments, but didn't @@ -324,13 +319,6 @@ // FIXME: FixitHint to rewrite the type of the initialized variable // as 'gsl::owner<OriginalType>' - - // If the type of the variable was deduced, the wrapping owner typedef is - // eliminated, therefore the check emits a special note for that case. - if (Nodes.getNodeAs<AutoType>("deduced_type")) { - diag(BadOwnerInitialization->getBeginLoc(), - "type deduction did not result in an owner", DiagnosticIDs::Note); - } return true; }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits