From 1d7fdbbc183aee2f1168425ae21e961164495466 Mon Sep 17 00:00:00 2001 From: Adrian Kuegel Date: Fri, 12 Nov 2021 13:15:51 +0100 Subject: [PATCH] Revert "[clang] retain type sugar in auto / template argument deduction" This reverts commit 9b6036deedf28e10d797fc4ca734d57680d18053. Breaks two libc++ tests. --- .../cppcoreguidelines/OwningMemoryCheck.cpp | 18 +- .../ProBoundsPointerArithmeticCheck.cpp | 8 +- .../readability/QualifiedAutoCheck.cpp | 14 +- clang-tools-extra/clangd/FindTarget.cpp | 2 +- clang-tools-extra/clangd/InlayHints.cpp | 7 +- .../clangd/unittests/ASTTests.cpp | 9 +- .../clangd/unittests/HoverTests.cpp | 12 +- .../clangd/unittests/InlayHintTests.cpp | 9 +- .../unittests/tweaks/ExpandAutoTypeTests.cpp | 7 +- .../cppcoreguidelines-owning-memory.cpp | 19 +- clang/include/clang/AST/ASTContext.h | 6 - clang/include/clang/AST/Type.h | 34 +- .../clang/ASTMatchers/ASTMatchersInternal.h | 24 +- clang/include/clang/Sema/Sema.h | 18 +- clang/lib/AST/ASTContext.cpp | 94 +- clang/lib/AST/ASTImporter.cpp | 16 +- clang/lib/AST/Type.cpp | 4 +- clang/lib/Sema/SemaCXXScopeSpec.cpp | 2 +- clang/lib/Sema/SemaDecl.cpp | 21 +- clang/lib/Sema/SemaDeclCXX.cpp | 2 +- clang/lib/Sema/SemaExprCXX.cpp | 5 +- clang/lib/Sema/SemaInit.cpp | 4 +- clang/lib/Sema/SemaLambda.cpp | 2 +- clang/lib/Sema/SemaStmt.cpp | 2 +- clang/lib/Sema/SemaTemplate.cpp | 22 +- clang/lib/Sema/SemaTemplateDeduction.cpp | 1089 ++++++++++------- clang/lib/Sema/SemaType.cpp | 54 +- clang/lib/Sema/TreeTransform.h | 15 +- .../over.match.class.deduct/p2.cpp | 2 +- .../stmt.stmt/stmt.iter/stmt.ranged/p1.cpp | 12 +- .../multi-level-substitution.cpp | 2 +- .../temp.deduct/temp.deduct.call/p1-0x.cpp | 3 +- .../temp.deduct/temp.deduct.call/p4.cpp | 8 +- clang/test/Index/print-type.cpp | 2 +- ...xx1z-class-template-argument-deduction.cpp | 46 - clang/test/SemaCXX/cxx1z-decomposition.cpp | 4 +- .../SemaCXX/deduced-return-type-cxx14.cpp | 2 +- clang/test/SemaCXX/friend.cpp | 4 +- clang/test/SemaCXX/recovery-expr-type.cpp | 2 +- clang/test/SemaCXX/sizeless-1.cpp | 4 +- clang/test/SemaCXX/sugared-auto.cpp | 43 - clang/test/SemaTemplate/attributes.cpp | 3 +- clang/test/SemaTemplate/friend.cpp | 4 +- clang/test/SemaTemplate/operator-template.cpp | 2 +- 44 files changed, 844 insertions(+), 818 deletions(-) delete mode 100644 clang/test/SemaCXX/sugared-auto.cpp diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.cpp index b87c33dd10bd..13bb7246fd43 100644 --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.cpp +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.cpp @@ -134,9 +134,14 @@ void OwningMemoryCheck::registerMatchers(MatchFinder *Finder) { // 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(allOf(hasInitializer(CreatesOwner), - unless(IsOwnerType))) - .bind("bad_owner_creation_variable"))), + traverse( + TK_AsIs, + namedDecl( + varDecl(eachOf(allOf(hasInitializer(CreatesOwner), + unless(IsOwnerType)), + allOf(hasInitializer(ConsideredOwner), + hasType(autoType().bind("deduced_type"))))) + .bind("bad_owner_creation_variable"))), this); // Match on all function calls that expect owners as arguments, but didn't @@ -319,6 +324,13 @@ bool OwningMemoryCheck::handleAssignmentFromNewOwner(const BoundNodes &Nodes) { // FIXME: FixitHint to rewrite the type of the initialized variable // as 'gsl::owner' + + // 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("deduced_type")) { + diag(BadOwnerInitialization->getBeginLoc(), + "type deduction did not result in an owner", DiagnosticIDs::Note); + } return true; } diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.cpp index 5b88da658f08..680b33787446 100644 --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.cpp +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.cpp @@ -20,11 +20,9 @@ void ProBoundsPointerArithmeticCheck::registerMatchers(MatchFinder *Finder) { if (!getLangOpts().CPlusPlus) return; - const auto AllPointerTypes = - anyOf(hasType(pointerType()), - hasType(autoType( - hasDeducedType(hasUnqualifiedDesugaredType(pointerType())))), - hasType(decltypeType(hasUnderlyingType(pointerType())))); + const auto AllPointerTypes = anyOf( + hasType(pointerType()), hasType(autoType(hasDeducedType(pointerType()))), + hasType(decltypeType(hasUnderlyingType(pointerType())))); // Flag all operators +, -, +=, -=, ++, -- that result in a pointer Finder->addMatcher( diff --git a/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp b/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp index c564b5adcbbf..95380069f527 100644 --- a/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp @@ -125,22 +125,18 @@ void QualifiedAutoCheck::registerMatchers(MatchFinder *Finder) { }; 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(IsAutoDeducedToPointer(UnlessFunctionType)), + ExplicitSingleVarDecl(hasType(autoType(hasDeducedType( + pointerType(pointee(unless(functionType())))))), "auto"), this); Finder->addMatcher( ExplicitSingleVarDeclInTemplate( - allOf(hasType(IsAutoDeducedToPointer( - hasUnqualifiedType(qualType().bind("type")), - UnlessFunctionType)), + allOf(hasType(autoType(hasDeducedType(pointerType( + pointee(hasUnqualifiedType(qualType().bind("type")), + unless(functionType())))))), anyOf(hasAncestor( functionDecl(hasAnyTemplateArgument(IsBoundToType))), hasAncestor(classTemplateSpecializationDecl( diff --git a/clang-tools-extra/clangd/FindTarget.cpp b/clang-tools-extra/clangd/FindTarget.cpp index 70e1d423f542..82e4dfeccf43 100644 --- a/clang-tools-extra/clangd/FindTarget.cpp +++ b/clang-tools-extra/clangd/FindTarget.cpp @@ -374,7 +374,7 @@ public: 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); + Outer.add(DT->getDeducedType(), Flags | Rel::Underlying); } void VisitDeducedTemplateSpecializationType( const DeducedTemplateSpecializationType *DTST) { diff --git a/clang-tools-extra/clangd/InlayHints.cpp b/clang-tools-extra/clangd/InlayHints.cpp index 6b9c8b1eee54..73864b784934 100644 --- a/clang-tools-extra/clangd/InlayHints.cpp +++ b/clang-tools-extra/clangd/InlayHints.cpp @@ -38,9 +38,10 @@ public: // For structured bindings, print canonical types. This is important because // for bindings that use the tuple_element protocol, the non-canonical types // would be "tuple_element::type". - // For "auto", we often prefer sugared types. - // Not setting PrintCanonicalTypes for "auto" allows - // SuppressDefaultTemplateArgs (set by default) to have an effect. + // For "auto", we often prefer sugared types, but the AST doesn't currently + // retain them in DeducedType. However, not setting PrintCanonicalTypes for + // "auto" at least allows SuppressDefaultTemplateArgs (set by default) to + // have an effect. StructuredBindingPolicy = TypeHintPolicy; StructuredBindingPolicy.PrintCanonicalTypes = true; } diff --git a/clang-tools-extra/clangd/unittests/ASTTests.cpp b/clang-tools-extra/clangd/unittests/ASTTests.cpp index 44dc8f0c69cf..df42a28d5ebe 100644 --- a/clang-tools-extra/clangd/unittests/ASTTests.cpp +++ b/clang-tools-extra/clangd/unittests/ASTTests.cpp @@ -43,7 +43,7 @@ TEST(GetDeducedType, KwAutoKwDecltypeExpansion) { namespace ns1 { struct S {}; } ^auto v = ns1::S{}; )cpp", - "ns1::S", + "struct ns1::S", }, { R"cpp( // decltype on struct @@ -63,7 +63,7 @@ TEST(GetDeducedType, KwAutoKwDecltypeExpansion) { ns1::S& j = i; ^decltype(auto) k = j; )cpp", - "ns1::S &", + "struct ns1::S &", }, { R"cpp( // auto on template class @@ -71,7 +71,7 @@ TEST(GetDeducedType, KwAutoKwDecltypeExpansion) { template class Foo {}; ^auto v = Foo(); )cpp", - "Foo", + "class Foo", }, { R"cpp( // auto on initializer list. @@ -177,7 +177,8 @@ TEST(GetDeducedType, KwAutoKwDecltypeExpansion) { using Bar = Foo; ^auto x = Bar(); )cpp", - "Bar", + // FIXME: it'd be nice if this resolved to the alias instead + "struct Foo", }, }; for (Test T : Tests) { diff --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp index 79510ceefa1b..53df965fef2f 100644 --- a/clang-tools-extra/clangd/unittests/HoverTests.cpp +++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp @@ -461,7 +461,7 @@ class Foo {})cpp"; [](HoverInfo &HI) { HI.Name = "auto"; HI.Kind = index::SymbolKind::TypeAlias; - HI.Definition = "Foo"; + HI.Definition = "class Foo"; }}, // auto on specialized template {R"cpp( @@ -474,7 +474,7 @@ class Foo {})cpp"; [](HoverInfo &HI) { HI.Name = "auto"; HI.Kind = index::SymbolKind::TypeAlias; - HI.Definition = "Foo"; + HI.Definition = "class Foo"; }}, // macro @@ -648,7 +648,7 @@ class Foo {})cpp"; [](HoverInfo &HI) { HI.Name = "auto"; HI.Kind = index::SymbolKind::TypeAlias; - HI.Definition = "Foo"; + HI.Definition = "class Foo"; }}, {// Falls back to primary template, when the type is not instantiated. R"cpp( @@ -2024,7 +2024,7 @@ TEST(Hover, All) { [](HoverInfo &HI) { HI.Name = "auto"; HI.Kind = index::SymbolKind::TypeAlias; - HI.Definition = "int_type"; + HI.Definition = "int"; }}, { R"cpp(// auto on alias @@ -2035,7 +2035,7 @@ TEST(Hover, All) { [](HoverInfo &HI) { HI.Name = "auto"; HI.Kind = index::SymbolKind::TypeAlias; - HI.Definition = "cls_type"; + HI.Definition = "struct cls"; HI.Documentation = "auto on alias"; }}, { @@ -2047,7 +2047,7 @@ TEST(Hover, All) { [](HoverInfo &HI) { HI.Name = "auto"; HI.Kind = index::SymbolKind::TypeAlias; - HI.Definition = "templ"; + HI.Definition = "struct templ"; HI.Documentation = "auto on alias"; }}, { diff --git a/clang-tools-extra/clangd/unittests/InlayHintTests.cpp b/clang-tools-extra/clangd/unittests/InlayHintTests.cpp index b6c6dd17dbe3..1c69d504ec6d 100644 --- a/clang-tools-extra/clangd/unittests/InlayHintTests.cpp +++ b/clang-tools-extra/clangd/unittests/InlayHintTests.cpp @@ -466,14 +466,7 @@ TEST(TypeHints, NoQualifiers) { } } )cpp", - ExpectedHint{": S1", "x"}, - // FIXME: We want to suppress scope specifiers - // here because we are into the whole - // brevity thing, but the ElaboratedType - // printer does not honor the SuppressScope - // flag by design, so we need to extend the - // PrintingPolicy to support this use case. - ExpectedHint{": S2::Inner", "y"}); + ExpectedHint{": S1", "x"}, ExpectedHint{": Inner", "y"}); } TEST(TypeHints, Lambda) { diff --git a/clang-tools-extra/clangd/unittests/tweaks/ExpandAutoTypeTests.cpp b/clang-tools-extra/clangd/unittests/tweaks/ExpandAutoTypeTests.cpp index 96574a67b5a4..1b784f63f59c 100644 --- a/clang-tools-extra/clangd/unittests/tweaks/ExpandAutoTypeTests.cpp +++ b/clang-tools-extra/clangd/unittests/tweaks/ExpandAutoTypeTests.cpp @@ -57,7 +57,7 @@ TEST_F(ExpandAutoTypeTest, Test) { EXPECT_UNAVAILABLE("au^to x = []{};"); // inline namespaces EXPECT_EQ(apply("au^to x = inl_ns::Visible();"), - "inl_ns::Visible x = inl_ns::Visible();"); + "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,9 +67,8 @@ TEST_F(ExpandAutoTypeTest, Test) { 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() { ns::Class::Nested * x = new ns::Class::Nested{}; }"); + EXPECT_EQ(apply("void ns::Func() { au^to x = new ns::Class::Nested{}; }"), + "void ns::Func() { Class::Nested * x = new ns::Class::Nested{}; }"); EXPECT_UNAVAILABLE("dec^ltype(au^to) x = 10;"); // expanding types in structured bindings is syntactically invalid. diff --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-owning-memory.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-owning-memory.cpp index 6bf5af82d655..72b13801cf1e 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-owning-memory.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-owning-memory.cpp @@ -91,9 +91,13 @@ void test_assignment_and_initialization() { // 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(); // Ok, since type deduction does not eliminate the owner wrapper + 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 - const auto owned_int8 = returns_owner2(); // 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 gsl::owner owned_int9 = returns_owner1(); // Ok int *unowned_int3 = returns_owner1(); // Bad @@ -281,12 +285,15 @@ void test_class_with_owner() { ClassWithOwner C2{A}; // Bad, since the owner would be initialized with an non-owner, but catched in the class ClassWithOwner C3{gsl::owner(new ArbitraryClass)}; // Ok - const auto Owner1 = C3.buggy_but_returns_owner(); // Ok, deduces Owner1 to owner const + 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 - auto Owner2 = C2.buggy_but_returns_owner(); //Ok, deduces Owner2 to owner + 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 - Owner2 = &A; // BAD, since type deduction resulted in owner - // CHECK-NOTES: [[@LINE-1]]:3: warning: expected assignment source to be of type 'gsl::owner<>'; got 'ArbitraryClass *' + Owner2 = &A; // Ok, since type deduction did NOT result in owner gsl::owner Owner3 = C1.buggy_but_returns_owner(); // Ok, still an owner Owner3 = &A; // Bad, since assignment of non-owner to owner diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index d336342e4cda..b9aa2d2cfadb 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -1531,12 +1531,6 @@ private: QualType getFunctionTypeInternal(QualType ResultTy, ArrayRef Args, const FunctionProtoType::ExtProtoInfo &EPI, bool OnlyWantCanonical) const; - QualType - getAutoTypeInternal(QualType DeducedType, AutoTypeKeyword Keyword, - bool IsDependent, bool IsPack = false, - ConceptDecl *TypeConstraintConcept = nullptr, - ArrayRef TypeConstraintArgs = {}, - bool IsCanon = false) const; public: /// Return the unique reference to the type for the specified type diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index fd25ec25d4f2..722add6cd877 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -4944,29 +4944,29 @@ public: /// 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, QualType Canon) - : Type(TC, Canon, + TypeDependence ExtraDependence) + : Type(TC, + // FIXME: Retain the sugared deduced type? + DeducedAsType.isNull() ? QualType(this, 0) + : DeducedAsType.getCanonicalType(), ExtraDependence | (DeducedAsType.isNull() ? TypeDependence::None : DeducedAsType->getDependence() & - ~TypeDependence::VariablyModified)), - DeducedAsType(DeducedAsType) {} + ~TypeDependence::VariablyModified)) {} public: - bool isSugared() const { return !DeducedAsType.isNull(); } - QualType desugar() const { - return isSugared() ? DeducedAsType : QualType(this, 0); - } + bool isSugared() const { return !isCanonicalUnqualified(); } + QualType desugar() const { return getCanonicalTypeInternal(); } - /// Get the type deduced for this placeholder type, or null if it - /// has not been deduced. - QualType getDeducedType() const { return DeducedAsType; } + /// 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(); + } bool isDeduced() const { - return !DeducedAsType.isNull() || isDependentType(); + return !isCanonicalUnqualified() || isDependentType(); } static bool classof(const Type *T) { @@ -4983,7 +4983,7 @@ class alignas(8) AutoType : public DeducedType, public llvm::FoldingSetNode { ConceptDecl *TypeConstraintConcept; AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword, - TypeDependence ExtraDependence, QualType Canon, ConceptDecl *CD, + TypeDependence ExtraDependence, ConceptDecl *CD, ArrayRef TypeConstraintArgs); const TemplateArgument *getArgBuffer() const { @@ -5057,9 +5057,7 @@ class DeducedTemplateSpecializationType : public DeducedType, toTypeDependence(Template.getDependence()) | (IsDeducedAsDependent ? TypeDependence::DependentInstantiation - : TypeDependence::None), - DeducedAsType.isNull() ? QualType(this, 0) - : DeducedAsType.getCanonicalType()), + : TypeDependence::None)), Template(Template) {} public: diff --git a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h index a77611001fb1..f84582c06f78 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h +++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -1027,29 +1027,31 @@ private: BoundNodesTreeBuilder *Builder) const { // DeducedType does not have declarations of its own, so // match the deduced type instead. + const Type *EffectiveType = &Node; if (const auto *S = dyn_cast(&Node)) { - QualType DT = S->getDeducedType(); - return !DT.isNull() ? matchesSpecialized(*DT, Finder, Builder) : false; + EffectiveType = S->getDeducedType().getTypePtrOrNull(); + if (!EffectiveType) + return false; } // First, for any types that have a declaration, extract the declaration and // match on it. - if (const auto *S = dyn_cast(&Node)) { + if (const auto *S = dyn_cast(EffectiveType)) { return matchesDecl(S->getDecl(), Finder, Builder); } - if (const auto *S = dyn_cast(&Node)) { + if (const auto *S = dyn_cast(EffectiveType)) { return matchesDecl(S->getDecl(), Finder, Builder); } - if (const auto *S = dyn_cast(&Node)) { + if (const auto *S = dyn_cast(EffectiveType)) { return matchesDecl(S->getDecl(), Finder, Builder); } - if (const auto *S = dyn_cast(&Node)) { + if (const auto *S = dyn_cast(EffectiveType)) { return matchesDecl(S->getDecl(), Finder, Builder); } - if (const auto *S = dyn_cast(&Node)) { + if (const auto *S = dyn_cast(EffectiveType)) { return matchesDecl(S->getDecl(), Finder, Builder); } - if (const auto *S = dyn_cast(&Node)) { + if (const auto *S = dyn_cast(EffectiveType)) { return matchesDecl(S->getInterface(), Finder, Builder); } @@ -1061,14 +1063,14 @@ private: // template struct X { T t; } class A {}; X a; // The following matcher will match, which otherwise would not: // fieldDecl(hasType(pointerType())). - if (const auto *S = dyn_cast(&Node)) { + if (const auto *S = dyn_cast(EffectiveType)) { return matchesSpecialized(S->getReplacementType(), Finder, Builder); } // For template specialization types, we want to match the template // declaration, as long as the type is still dependent, and otherwise the // declaration of the instantiated tag type. - if (const auto *S = dyn_cast(&Node)) { + if (const auto *S = dyn_cast(EffectiveType)) { if (!S->isTypeAlias() && S->isSugared()) { // If the template is non-dependent, we want to match the instantiated // tag type. @@ -1087,7 +1089,7 @@ private: // FIXME: We desugar elaborated types. This makes the assumption that users // do never want to match on whether a type is elaborated - there are // arguments for both sides; for now, continue desugaring. - if (const auto *S = dyn_cast(&Node)) { + if (const auto *S = dyn_cast(EffectiveType)) { return matchesSpecialized(S->desugar(), Finder, Builder); } return false; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 5f5755ef1343..c7a6d04ce8f8 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -2359,13 +2359,11 @@ public: const CXXScopeSpec &SS, QualType T, TagDecl *OwnedTagDecl = nullptr); - // Returns the underlying type of a decltype with the given expression. - QualType getDecltypeForExpr(Expr *E); - - QualType BuildTypeofExprType(Expr *E); + QualType BuildTypeofExprType(Expr *E, SourceLocation Loc); /// 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, bool AsUnevaluated = true); + QualType BuildDecltypeType(Expr *E, SourceLocation Loc, + bool AsUnevaluated = true); QualType BuildUnaryTransformType(QualType BaseType, UnaryTransformType::UTTKind UKind, SourceLocation Loc); @@ -3504,7 +3502,7 @@ public: bool IsFunctionConversion(QualType FromType, QualType ToType, QualType &ResultTy); bool DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType); - bool isSameOrCompatibleFunctionType(QualType Param, QualType Arg); + bool isSameOrCompatibleFunctionType(CanQualType Param, CanQualType Arg); bool CanPerformAggregateInitializationForOverloadResolution( const InitializedEntity &Entity, InitListExpr *From); @@ -8567,14 +8565,6 @@ public: /// 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); diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index f0b931bdc905..391a0c0b338e 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -4815,23 +4815,6 @@ ASTContext::getTemplateSpecializationType(TemplateName Template, return QualType(Spec, 0); } -static bool -getCanonicalTemplateArguments(const ASTContext &C, - ArrayRef OrigArgs, - SmallVectorImpl &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 Args) const { assert(!Template.getAsDependentTemplateName() && @@ -4844,7 +4827,10 @@ QualType ASTContext::getCanonicalTemplateSpecializationType( // Build the canonical template specialization type. TemplateName CanonTemplate = getCanonicalTemplateName(Template); SmallVector CanonArgs; - ::getCanonicalTemplateArguments(*this, Args, CanonArgs); + unsigned NumArgs = Args.size(); + CanonArgs.reserve(NumArgs); + for (const TemplateArgument &Arg : Args) + CanonArgs.push_back(getCanonicalTemplateArgument(Arg)); // Determine whether this canonical template specialization type already // exists. @@ -4859,7 +4845,7 @@ QualType ASTContext::getCanonicalTemplateSpecializationType( if (!Spec) { // Allocate a new canonical template specialization type. void *Mem = Allocate((sizeof(TemplateSpecializationType) + - sizeof(TemplateArgument) * CanonArgs.size()), + sizeof(TemplateArgument) * NumArgs), TypeAlignment); Spec = new (Mem) TemplateSpecializationType(CanonTemplate, CanonArgs, @@ -5001,9 +4987,14 @@ ASTContext::getDependentTemplateSpecializationType( ElaboratedTypeKeyword CanonKeyword = Keyword; if (Keyword == ETK_None) CanonKeyword = ETK_Typename; - SmallVector CanonArgs; - bool AnyNonCanonArgs = - ::getCanonicalTemplateArguments(*this, Args, CanonArgs); + bool AnyNonCanonArgs = false; + unsigned NumArgs = Args.size(); + SmallVector CanonArgs(NumArgs); + for (unsigned I = 0; I != NumArgs; ++I) { + CanonArgs[I] = getCanonicalTemplateArgument(Args[I]); + if (!CanonArgs[I].structurallyEquals(Args[I])) + AnyNonCanonArgs = true; + } QualType Canon; if (AnyNonCanonArgs || CanonNNS != NNS || CanonKeyword != Keyword) { @@ -5016,7 +5007,7 @@ ASTContext::getDependentTemplateSpecializationType( } void *Mem = Allocate((sizeof(DependentTemplateSpecializationType) + - sizeof(TemplateArgument) * Args.size()), + sizeof(TemplateArgument) * NumArgs), TypeAlignment); T = new (Mem) DependentTemplateSpecializationType(Keyword, NNS, Name, Args, Canon); @@ -5598,10 +5589,15 @@ QualType ASTContext::getUnaryTransformType(QualType BaseType, return QualType(ut, 0); } -QualType ASTContext::getAutoTypeInternal( - QualType DeducedType, AutoTypeKeyword Keyword, bool IsDependent, - bool IsPack, ConceptDecl *TypeConstraintConcept, - ArrayRef TypeConstraintArgs, bool IsCanon) const { +/// 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 TypeConstraintArgs) const { + assert((!IsPack || IsDependent) && "only use IsPack for a dependent pack"); if (DeducedType.isNull() && Keyword == AutoTypeKeyword::Auto && !TypeConstraintConcept && !IsDependent) return getAutoDeductType(); @@ -5614,52 +5610,21 @@ QualType ASTContext::getAutoTypeInternal( if (AutoType *AT = AutoTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(AT, 0); - QualType Canon; - if (!IsCanon) { - if (DeducedType.isNull()) { - SmallVector 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), - Canon, TypeConstraintConcept, TypeConstraintArgs); + TypeConstraintConcept, TypeConstraintArgs); Types.push_back(AT); - AutoTypes.InsertNode(AT, InsertPos); + if (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 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. @@ -5677,7 +5642,8 @@ QualType ASTContext::getDeducedTemplateSpecializationType( auto *DTST = new (*this, TypeAlignment) DeducedTemplateSpecializationType(Template, DeducedType, IsDependent); Types.push_back(DTST); - DeducedTemplateSpecializationTypes.InsertNode(DTST, InsertPos); + if (InsertPos) + DeducedTemplateSpecializationTypes.InsertNode(DTST, InsertPos); return QualType(DTST, 0); } @@ -5714,7 +5680,7 @@ QualType ASTContext::getAutoDeductType() const { if (AutoDeductTy.isNull()) AutoDeductTy = QualType(new (*this, TypeAlignment) AutoType(QualType(), AutoTypeKeyword::Auto, - TypeDependence::None, QualType(), + TypeDependence::None, /*concept*/ nullptr, /*args*/ {}), 0); return AutoDeductTy; diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 710e40bbb4b7..8062b4fcab53 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -3172,14 +3172,13 @@ static bool isAncestorDeclContextOf(const DeclContext *DC, const Decl *D) { bool ASTNodeImporter::hasAutoReturnTypeDeclaredInside(FunctionDecl *D) { QualType FromTy = D->getType(); - const auto *FromFPT = FromTy->getAs(); + const FunctionProtoType *FromFPT = FromTy->getAs(); assert(FromFPT && "Must be called on FunctionProtoType"); - if (const AutoType *AutoT = - FromFPT->getReturnType()->getContainedAutoType()) { + if (AutoType *AutoT = FromFPT->getReturnType()->getContainedAutoType()) { QualType DeducedT = AutoT->getDeducedType(); - if (const auto *RecordT = - !DeducedT.isNull() ? DeducedT->getAs() : nullptr) { - const RecordDecl *RD = RecordT->getDecl(); + if (const RecordType *RecordT = + DeducedT.isNull() ? nullptr : dyn_cast(DeducedT)) { + RecordDecl *RD = RecordT->getDecl(); assert(RD); if (isAncestorDeclContextOf(D, RD)) { assert(RD->getLexicalDeclContext() == RD->getDeclContext()); @@ -3187,8 +3186,9 @@ bool ASTNodeImporter::hasAutoReturnTypeDeclaredInside(FunctionDecl *D) { } } } - if (const auto *TypedefT = FromFPT->getReturnType()->getAs()) { - const TypedefNameDecl *TD = TypedefT->getDecl(); + if (const TypedefType *TypedefT = + dyn_cast(FromFPT->getReturnType())) { + TypedefNameDecl *TD = TypedefT->getDecl(); assert(TD); if (isAncestorDeclContextOf(D, TD)) { assert(TD->getLexicalDeclContext() == TD->getDeclContext()); diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 4adf367f2da6..ead3944284ae 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -4400,10 +4400,10 @@ void clang::FixedPointValueToString(SmallVectorImpl &Str, } AutoType::AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword, - TypeDependence ExtraDependence, QualType Canon, + TypeDependence ExtraDependence, ConceptDecl *TypeConstraintConcept, ArrayRef TypeConstraintArgs) - : DeducedType(Auto, DeducedAsType, ExtraDependence, Canon) { + : DeducedType(Auto, DeducedAsType, ExtraDependence) { AutoTypeBits.Keyword = (unsigned)Keyword; AutoTypeBits.NumArgs = TypeConstraintArgs.size(); this->TypeConstraintConcept = TypeConstraintConcept; diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp index c4826b5a6e8f..7f8d03008159 100644 --- a/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -865,7 +865,7 @@ bool Sema::ActOnCXXNestedNameSpecifierDecltype(CXXScopeSpec &SS, assert(DS.getTypeSpecType() == DeclSpec::TST_decltype); - QualType T = BuildDecltypeType(DS.getRepAsExpr()); + QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc()); if (T.isNull()) return true; diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 5d15fd2aec58..638fe86c20ab 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -3613,14 +3613,14 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, // defined, copy the deduced value from the old declaration. AutoType *OldAT = Old->getReturnType()->getContainedAutoType(); if (OldAT && OldAT->isDeduced()) { - 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)); - } + New->setType( + SubstAutoType(New->getType(), + OldAT->isDependentType() ? Context.DependentTy + : OldAT->getDeducedType())); + NewQType = Context.getCanonicalType( + SubstAutoType(NewQType, + OldAT->isDependentType() ? Context.DependentTy + : OldAT->getDeducedType())); } } @@ -9258,7 +9258,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // a friend yet, so 'isDependentContext' on the FD doesn't work. const FunctionProtoType *FPT = NewFD->getType()->castAs(); - QualType Result = SubstAutoTypeDependent(FPT->getReturnType()); + QualType Result = + SubstAutoType(FPT->getReturnType(), Context.DependentTy); NewFD->setType(Context.getFunctionType(Result, FPT->getParamTypes(), FPT->getExtProtoInfo())); } @@ -12349,7 +12350,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { /*TreatUnavailableAsInvalid=*/false); ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Args, &DclT); if (Result.isInvalid()) { - // If the provided initializer fails to initialize the var decl, + // If the provied initializer fails to initialize the var decl, // we attach a recovery expr for better recovery. auto RecoveryExpr = CreateRecoveryExpr(Init->getBeginLoc(), Init->getEndLoc(), Args); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 46b41a7b0f43..d67e039dd26c 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -4219,7 +4219,7 @@ Sema::BuildMemInitializer(Decl *ConstructorD, if (BaseType.isNull()) return true; } else if (DS.getTypeSpecType() == TST_decltype) { - BaseType = BuildDecltypeType(DS.getRepAsExpr()); + BaseType = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc()); } else if (DS.getTypeSpecType() == TST_decltype_auto) { Diag(DS.getTypeSpecTypeLoc(), diag::err_decltype_auto_invalid); return true; diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 891909c443cc..571b790b31ea 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -468,7 +468,7 @@ ParsedType Sema::getDestructorTypeForDecltype(const DeclSpec &DS, assert(DS.getTypeSpecType() == DeclSpec::TST_decltype && "unexpected type in getDestructorType"); - QualType T = BuildDecltypeType(DS.getRepAsExpr()); + QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc()); // If we know the type of the object, check that the correct destructor // type was named now; we can give better diagnostics this way. @@ -7761,7 +7761,8 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, return true; } - QualType T = BuildDecltypeType(DS.getRepAsExpr(), /*AsUnevaluated=*/false); + QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc(), + false); TypeLocBuilder TLB; DecltypeTypeLoc DecltypeTL = TLB.push(T); diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 8e435d9cb41f..75686e294704 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -9972,7 +9972,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( auto TemplateName = DeducedTST->getTemplateName(); if (TemplateName.isDependent()) - return SubstAutoTypeDependent(TSInfo->getType()); + return SubstAutoType(TSInfo->getType(), Context.DependentTy); // We can only perform deduction for class templates. auto *Template = @@ -9991,7 +9991,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( Diag(TSInfo->getTypeLoc().getBeginLoc(), diag::warn_cxx14_compat_class_template_argument_deduction) << TSInfo->getTypeLoc().getSourceRange() << 0; - return SubstAutoTypeDependent(TSInfo->getType()); + return SubstAutoType(TSInfo->getType(), Context.DependentTy); } // FIXME: Perform "exact type" matching first, per CWG discussion? diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index b05e0b5cc0f1..c4a8b3487ab9 100644 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -373,7 +373,7 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class, const FunctionProtoType *FPT = MethodType->castAs(); QualType Result = FPT->getReturnType(); if (Result->isUndeducedType()) { - Result = SubstAutoTypeDependent(Result); + Result = SubstAutoType(Result, Context.DependentTy); MethodType = Context.getFunctionType(Result, FPT->getParamTypes(), FPT->getExtProtoInfo()); } diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index 3c820829864d..dc564e318d82 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -2759,7 +2759,7 @@ StmtResult Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, if (auto *DD = dyn_cast(LoopVar)) for (auto *Binding : DD->bindings()) Binding->setType(Context.DependentTy); - LoopVar->setType(SubstAutoTypeDependent(LoopVar->getType())); + LoopVar->setType(SubstAutoType(LoopVar->getType(), Context.DependentTy)); } } else if (!BeginDeclStmt.get()) { SourceLocation RangeLoc = RangeVar->getLocation(); diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 46b5fbe7a350..6ff87eb61bf7 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1259,15 +1259,15 @@ bool Sema::AttachTypeConstraint(AutoTypeLoc TL, NonTypeTemplateParmDecl *NTTP, 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(), - [&](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()), 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; @@ -1289,7 +1289,7 @@ QualType Sema::CheckNonTypeTemplateParameterType(TypeSourceInfo *&TSI, // - 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 = SubstAutoTypeSourceInfoDependent(TSI); + TSI = SubstAutoTypeSourceInfo(TSI, Context.DependentTy); } return CheckNonTypeTemplateParameterType(TSI->getType(), Loc); @@ -10873,7 +10873,7 @@ bool Sema::RebuildTemplateParamsInCurrentInstantiation( // - 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 = SubstAutoTypeSourceInfoDependent(NewTSI); + NewTSI = SubstAutoTypeSourceInfo(NewTSI, Context.DependentTy); } if (NewTSI != NTTP->getTypeSourceInfo()) { diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index f4bb88188021..facd3e0998e8 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -131,16 +131,30 @@ static bool hasSameExtendedValue(llvm::APSInt X, llvm::APSInt Y) { return X == Y; } -static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( - Sema &S, TemplateParameterList *TemplateParams, QualType Param, - QualType Arg, TemplateDeductionInfo &Info, - SmallVectorImpl &Deduced, unsigned TDF, - bool PartialOrdering = false, bool DeducedFromArrayBound = false); +static Sema::TemplateDeductionResult +DeduceTemplateArguments(Sema &S, + TemplateParameterList *TemplateParams, + const TemplateArgument &Param, + TemplateArgument Arg, + TemplateDeductionInfo &Info, + SmallVectorImpl &Deduced); + +static Sema::TemplateDeductionResult +DeduceTemplateArgumentsByTypeMatch(Sema &S, + TemplateParameterList *TemplateParams, + QualType Param, + QualType Arg, + TemplateDeductionInfo &Info, + SmallVectorImpl & + Deduced, + unsigned TDF, + bool PartialOrdering = false, + bool DeducedFromArrayBound = false); static Sema::TemplateDeductionResult DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, - ArrayRef Ps, - ArrayRef As, + ArrayRef Params, + ArrayRef Args, TemplateDeductionInfo &Info, SmallVectorImpl &Deduced, bool NumberOfArgumentsMustMatch); @@ -545,62 +559,70 @@ DeduceTemplateArguments(Sema &S, /// "success" result means that template argument deduction has not yet failed, /// but it may still fail, later, for other reasons. static Sema::TemplateDeductionResult -DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams, - const QualType P, QualType A, - TemplateDeductionInfo &Info, - SmallVectorImpl &Deduced) { - QualType UP = P; - if (const auto *IP = P->getAs()) - UP = IP->getInjectedSpecializationType(); - // FIXME: Try to preserve type sugar here, which is hard - // because of the unresolved template arguments. - const auto *TP = UP.getCanonicalType()->castAs(); - ArrayRef PResolved = TP->template_arguments(); +DeduceTemplateArguments(Sema &S, + TemplateParameterList *TemplateParams, + const TemplateSpecializationType *Param, + QualType Arg, + TemplateDeductionInfo &Info, + SmallVectorImpl &Deduced) { + assert(Arg.isCanonical() && "Argument type must be canonical"); - QualType UA = A; // Treat an injected-class-name as its underlying template-id. - if (const auto *Injected = A->getAs()) - UA = Injected->getInjectedSpecializationType(); + if (auto *Injected = dyn_cast(Arg)) + Arg = Injected->getInjectedSpecializationType(); // Check whether the template argument is a dependent template-id. - // FIXME: Should not lose sugar here. - if (const auto *SA = - dyn_cast(UA.getCanonicalType())) { + if (const TemplateSpecializationType *SpecArg + = dyn_cast(Arg)) { // Perform template argument deduction for the template name. - if (auto Result = - DeduceTemplateArguments(S, TemplateParams, TP->getTemplateName(), - SA->getTemplateName(), Info, Deduced)) + if (Sema::TemplateDeductionResult Result + = DeduceTemplateArguments(S, TemplateParams, + Param->getTemplateName(), + SpecArg->getTemplateName(), + Info, Deduced)) return Result; + + // Perform template argument deduction on each template // argument. Ignore any missing/extra arguments, since they could be // filled in by default arguments. - return DeduceTemplateArguments(S, TemplateParams, PResolved, - SA->template_arguments(), Info, Deduced, + return DeduceTemplateArguments(S, TemplateParams, + Param->template_arguments(), + SpecArg->template_arguments(), Info, Deduced, /*NumberOfArgumentsMustMatch=*/false); } // If the argument type is a class template specialization, we // perform template argument deduction using its template // arguments. - const auto *RA = UA->getAs(); - const auto *SA = - RA ? dyn_cast(RA->getDecl()) : nullptr; - if (!SA) { - Info.FirstArg = TemplateArgument(P); - Info.SecondArg = TemplateArgument(A); + const RecordType *RecordArg = dyn_cast(Arg); + if (!RecordArg) { + Info.FirstArg = TemplateArgument(QualType(Param, 0)); + Info.SecondArg = TemplateArgument(Arg); + return Sema::TDK_NonDeducedMismatch; + } + + ClassTemplateSpecializationDecl *SpecArg + = dyn_cast(RecordArg->getDecl()); + if (!SpecArg) { + Info.FirstArg = TemplateArgument(QualType(Param, 0)); + Info.SecondArg = TemplateArgument(Arg); return Sema::TDK_NonDeducedMismatch; } // Perform template argument deduction for the template name. - if (auto Result = DeduceTemplateArguments( - S, TemplateParams, TP->getTemplateName(), - TemplateName(SA->getSpecializedTemplate()), Info, Deduced)) + if (Sema::TemplateDeductionResult Result + = DeduceTemplateArguments(S, + TemplateParams, + Param->getTemplateName(), + TemplateName(SpecArg->getSpecializedTemplate()), + Info, Deduced)) return Result; // Perform template argument deduction for the template arguments. - return DeduceTemplateArguments(S, TemplateParams, PResolved, - SA->getTemplateArgs().asArray(), Info, Deduced, - /*NumberOfArgumentsMustMatch=*/true); + return DeduceTemplateArguments(S, TemplateParams, Param->template_arguments(), + SpecArg->getTemplateArgs().asArray(), Info, + Deduced, /*NumberOfArgumentsMustMatch=*/true); } /// Determines whether the given type is an opaque type that @@ -1025,12 +1047,11 @@ DeduceTemplateArguments(Sema &S, return Sema::TDK_MiscellaneousDeductionFailure; } - if (Sema::TemplateDeductionResult Result = - DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, Params[ParamIdx].getUnqualifiedType(), - Args[ArgIdx].getUnqualifiedType(), Info, Deduced, TDF, - PartialOrdering, - /*DeducedFromArrayBound=*/false)) + if (Sema::TemplateDeductionResult Result + = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, + Params[ParamIdx], Args[ArgIdx], + Info, Deduced, TDF, + PartialOrdering)) return Result; ++ArgIdx; @@ -1052,11 +1073,10 @@ DeduceTemplateArguments(Sema &S, 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.getUnqualifiedType(), - Args[ArgIdx].getUnqualifiedType(), Info, Deduced, TDF, - PartialOrdering, /*DeducedFromArrayBound=*/false)) + if (Sema::TemplateDeductionResult Result + = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, Pattern, + Args[ArgIdx], Info, Deduced, + TDF, PartialOrdering)) return Result; PackScope.nextPackElement(); @@ -1135,25 +1155,26 @@ static bool hasInconsistentOrSupersetQualifiersOf(QualType ParamType, /// function types (noreturn adjustment, implicit calling conventions). If any /// of parameter and argument is not a function, just perform type comparison. /// -/// \param P the template parameter type. +/// \param Param the template parameter type. /// -/// \param A the argument type. -bool Sema::isSameOrCompatibleFunctionType(QualType P, QualType A) { - const FunctionType *PF = P->getAs(), - *AF = A->getAs(); +/// \param Arg the argument type. +bool Sema::isSameOrCompatibleFunctionType(CanQualType Param, + CanQualType Arg) { + const FunctionType *ParamFunction = Param->getAs(), + *ArgFunction = Arg->getAs(); // Just compare if not functions. - if (!PF || !AF) - return Context.hasSameType(P, A); + if (!ParamFunction || !ArgFunction) + return Param == Arg; // Noreturn and noexcept adjustment. QualType AdjustedParam; - if (IsFunctionConversion(P, A, AdjustedParam)) - return Context.hasSameType(AdjustedParam, A); + if (IsFunctionConversion(Param, Arg, AdjustedParam)) + return Arg == Context.getCanonicalType(AdjustedParam); // FIXME: Compatible calling conventions. - return Context.hasSameType(P, A); + return Param == Arg; } /// Get the index of the first template parameter that was originally from the @@ -1182,11 +1203,6 @@ static bool isForwardingReference(QualType Param, unsigned FirstInnerIndex) { return false; } -static CXXRecordDecl *getCanonicalRD(QualType T) { - return cast( - T->castAs()->getDecl()->getCanonicalDecl()); -} - /// Attempt to deduce the template arguments by checking the base types /// according to (C++20 [temp.deduct.call] p4b3. /// @@ -1205,11 +1221,10 @@ static CXXRecordDecl *getCanonicalRD(QualType T) { /// \returns the result of template argument deduction with the bases. "invalid" /// means no matches, "success" found a single item, and the /// "MiscellaneousDeductionFailure" result happens when the match is ambiguous. -static Sema::TemplateDeductionResult -DeduceTemplateBases(Sema &S, const CXXRecordDecl *RD, - TemplateParameterList *TemplateParams, QualType P, - TemplateDeductionInfo &Info, - SmallVectorImpl &Deduced) { +static Sema::TemplateDeductionResult DeduceTemplateBases( + Sema &S, const RecordType *RecordT, TemplateParameterList *TemplateParams, + const TemplateSpecializationType *SpecParam, TemplateDeductionInfo &Info, + SmallVectorImpl &Deduced) { // C++14 [temp.deduct.call] p4b3: // If P is a class and P has the form simple-template-id, then the // transformed A can be a derived class of the deduced A. Likewise if @@ -1229,44 +1244,45 @@ DeduceTemplateBases(Sema &S, const CXXRecordDecl *RD, // visited, while ToVisit is our stack of records that we still need to // visit. Matches contains a list of matches that have yet to be // disqualified. - llvm::SmallPtrSet Visited; - SmallVector ToVisit; + llvm::SmallPtrSet Visited; + SmallVector ToVisit; // We iterate over this later, so we have to use MapVector to ensure // determinism. - llvm::MapVector> + llvm::MapVector> Matches; - auto AddBases = [&Visited, &ToVisit](const CXXRecordDecl *RD) { + auto AddBases = [&Visited, &ToVisit](const RecordType *RT) { + CXXRecordDecl *RD = cast(RT->getDecl()); for (const auto &Base : RD->bases()) { - QualType T = Base.getType(); - assert(T->isRecordType() && "Base class that isn't a record?"); - if (Visited.insert(::getCanonicalRD(T)).second) - ToVisit.push_back(T); + assert(Base.getType()->isRecordType() && + "Base class that isn't a record?"); + const RecordType *RT = Base.getType()->getAs(); + if (Visited.insert(RT).second) + ToVisit.push_back(Base.getType()->getAs()); } }; // Set up the loop by adding all the bases. - AddBases(RD); + AddBases(RecordT); // Search each path of bases until we either run into a successful match // (where all bases of it are invalid), or we run out of bases. while (!ToVisit.empty()) { - QualType NextT = ToVisit.pop_back_val(); + const RecordType *NextT = ToVisit.pop_back_val(); SmallVector DeducedCopy(Deduced.begin(), Deduced.end()); TemplateDeductionInfo BaseInfo(TemplateDeductionInfo::ForBase, Info); - Sema::TemplateDeductionResult BaseResult = DeduceTemplateSpecArguments( - S, TemplateParams, P, NextT, BaseInfo, DeducedCopy); + Sema::TemplateDeductionResult BaseResult = + DeduceTemplateArguments(S, TemplateParams, SpecParam, + QualType(NextT, 0), BaseInfo, DeducedCopy); // If this was a successful deduction, add it to the list of matches, // otherwise we need to continue searching its bases. - const CXXRecordDecl *RD = ::getCanonicalRD(NextT); if (BaseResult == Sema::TDK_Success) - Matches.insert({RD, DeducedCopy}); + Matches.insert({NextT, DeducedCopy}); else - AddBases(RD); + AddBases(NextT); } // At this point, 'Matches' contains a list of seemingly valid bases, however @@ -1283,12 +1299,12 @@ DeduceTemplateBases(Sema &S, const CXXRecordDecl *RD, // We can give up once we have a single item (or have run out of things to // search) since cyclical inheritance isn't valid. while (Matches.size() > 1 && !ToVisit.empty()) { - const CXXRecordDecl *RD = ::getCanonicalRD(ToVisit.pop_back_val()); - Matches.erase(RD); + const RecordType *NextT = ToVisit.pop_back_val(); + Matches.erase(NextT); // Always add all bases, since the inheritance tree can contain // disqualifications for multiple matches. - AddBases(RD); + AddBases(NextT); } } @@ -1325,26 +1341,41 @@ DeduceTemplateBases(Sema &S, const CXXRecordDecl *RD, /// \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 P, QualType A, - TemplateDeductionInfo &Info, - SmallVectorImpl &Deduced, unsigned TDF, - bool PartialOrdering, bool DeducedFromArrayBound) { +static Sema::TemplateDeductionResult +DeduceTemplateArgumentsByTypeMatch(Sema &S, + TemplateParameterList *TemplateParams, + QualType ParamIn, QualType ArgIn, + TemplateDeductionInfo &Info, + SmallVectorImpl &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(Arg)) + Arg = ArgExpansion->getPattern(); + if (PartialOrdering) { // C++11 [temp.deduct.partial]p5: // Before the partial ordering is done, certain transformations are // performed on the types used for partial ordering: // - If P is a reference type, P is replaced by the type referred to. - const ReferenceType *PRef = P->getAs(); - if (PRef) - P = PRef->getPointeeType(); + const ReferenceType *ParamRef = Param->getAs(); + if (ParamRef) + Param = ParamRef->getPointeeType(); // - If A is a reference type, A is replaced by the type referred to. - const ReferenceType *ARef = A->getAs(); - if (ARef) - A = A->getPointeeType(); + const ReferenceType *ArgRef = Arg->getAs(); + if (ArgRef) + Arg = ArgRef->getPointeeType(); - if (PRef && ARef && S.Context.hasSameUnqualifiedType(P, A)) { + if (ParamRef && ArgRef && S.Context.hasSameUnqualifiedType(Param, Arg)) { // C++11 [temp.deduct.partial]p9: // If, for a given type, deduction succeeds in both directions (i.e., // the types are identical after the transformations above) and both @@ -1364,26 +1395,29 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // succeeds, so we model this as a deduction failure. Note that // [the first type] is P and [the other type] is A here; the standard // gets this backwards. - Qualifiers PQuals = P.getQualifiers(), AQuals = A.getQualifiers(); - if ((PRef->isLValueReferenceType() && !ARef->isLValueReferenceType()) || - PQuals.isStrictSupersetOf(AQuals) || - (PQuals.hasNonTrivialObjCLifetime() && - AQuals.getObjCLifetime() == Qualifiers::OCL_ExplicitNone && - PQuals.withoutObjCLifetime() == AQuals.withoutObjCLifetime())) { - Info.FirstArg = TemplateArgument(P); - Info.SecondArg = TemplateArgument(A); + Qualifiers ParamQuals = Param.getQualifiers(); + Qualifiers ArgQuals = Arg.getQualifiers(); + if ((ParamRef->isLValueReferenceType() && + !ArgRef->isLValueReferenceType()) || + ParamQuals.isStrictSupersetOf(ArgQuals) || + (ParamQuals.hasNonTrivialObjCLifetime() && + ArgQuals.getObjCLifetime() == Qualifiers::OCL_ExplicitNone && + ParamQuals.withoutObjCLifetime() == + ArgQuals.withoutObjCLifetime())) { + Info.FirstArg = TemplateArgument(ParamIn); + Info.SecondArg = TemplateArgument(ArgIn); return Sema::TDK_NonDeducedMismatch; } } - Qualifiers DiscardedQuals; + // C++11 [temp.deduct.partial]p7: // Remove any top-level cv-qualifiers: // - If P is a cv-qualified type, P is replaced by the cv-unqualified // version of P. - P = S.Context.getUnqualifiedArrayType(P, DiscardedQuals); + Param = Param.getUnqualifiedType(); // - If A is a cv-qualified type, A is replaced by the cv-unqualified // version of A. - A = S.Context.getUnqualifiedArrayType(A, DiscardedQuals); + Arg = 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 @@ -1391,12 +1425,13 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // transformed A. if (TDF & TDF_ParamWithReferenceType) { Qualifiers Quals; - QualType UnqualP = S.Context.getUnqualifiedArrayType(P, Quals); - Quals.setCVRQualifiers(Quals.getCVRQualifiers() & A.getCVRQualifiers()); - P = S.Context.getQualifiedType(UnqualP, Quals); + QualType UnqualParam = S.Context.getUnqualifiedArrayType(Param, Quals); + Quals.setCVRQualifiers(Quals.getCVRQualifiers() & + Arg.getCVRQualifiers()); + Param = S.Context.getQualifiedType(UnqualParam, Quals); } - if ((TDF & TDF_TopLevelParameterTypeList) && !P->isFunctionType()) { + if ((TDF & TDF_TopLevelParameterTypeList) && !Param->isFunctionType()) { // C++0x [temp.deduct.type]p10: // If P and A are function types that originated from deduction when // taking the address of a function template (14.8.2.2) or when deducing @@ -1409,9 +1444,8 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // 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(P, /*FirstInnerIndex=*/0) && - A->isLValueReferenceType()) - P = P->getPointeeType(); + if (isForwardingReference(Param, 0) && Arg->isLValueReferenceType()) + Param = Param->getPointeeType(); } } @@ -1422,48 +1456,53 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // // T // cv-list T - if (const auto *TTP = P->getAs()) { + if (const TemplateTypeParmType *TemplateTypeParm + = Param->getAs()) { // Just skip any attempts to deduce from a placeholder type or a parameter // at a different depth. - if (A->isPlaceholderType() || Info.getDeducedDepth() != TTP->getDepth()) + if (Arg->isPlaceholderType() || + Info.getDeducedDepth() != TemplateTypeParm->getDepth()) return Sema::TDK_Success; - unsigned Index = TTP->getIndex(); + 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 (A->isArrayType()) { + if (isa(Arg)) { Qualifiers Quals; - A = S.Context.getUnqualifiedArrayType(A, Quals); - if (Quals) - A = S.Context.getQualifiedType(A, Quals); + Arg = S.Context.getUnqualifiedArrayType(Arg, Quals); + if (Quals) { + Arg = S.Context.getQualifiedType(Arg, Quals); + RecanonicalizeArg = true; + } } // The argument type can not be less qualified than the parameter // type. if (!(TDF & TDF_IgnoreQualifiers) && - hasInconsistentOrSupersetQualifiersOf(P, A)) { + hasInconsistentOrSupersetQualifiersOf(Param, Arg)) { Info.Param = cast(TemplateParams->getParam(Index)); - Info.FirstArg = TemplateArgument(P); - Info.SecondArg = TemplateArgument(A); + Info.FirstArg = TemplateArgument(Param); + Info.SecondArg = TemplateArgument(Arg); return Sema::TDK_Underqualified; } // Do not match a function type with a cv-qualified type. // http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1584 - if (A->isFunctionType() && P.hasQualifiers()) + if (Arg->isFunctionType() && Param.hasQualifiers()) { return Sema::TDK_NonDeducedMismatch; + } - assert(TTP->getDepth() == Info.getDeducedDepth() && + assert(TemplateTypeParm->getDepth() == Info.getDeducedDepth() && "saw template type parameter with wrong depth"); - assert(A->getCanonicalTypeInternal() != S.Context.OverloadTy && - "Unresolved overloaded function"); - QualType DeducedType = A; + assert(Arg != S.Context.OverloadTy && "Unresolved overloaded function"); + QualType DeducedType = Arg; // Remove any qualifiers on the parameter from the deduced type. // We checked the qualifiers for consistency above. Qualifiers DeducedQs = DeducedType.getQualifiers(); - Qualifiers ParamQs = P.getQualifiers(); + Qualifiers ParamQs = Param.getQualifiers(); DeducedQs.removeCVRQualifiers(ParamQs.getCVRQualifiers()); if (ParamQs.hasObjCGCAttr()) DeducedQs.removeObjCGCAttr(); @@ -1478,24 +1517,29 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( if (ParamQs.hasObjCLifetime() && !DeducedType->isObjCLifetimeType() && !DeducedType->isDependentType()) { Info.Param = cast(TemplateParams->getParam(Index)); - Info.FirstArg = TemplateArgument(P); - Info.SecondArg = TemplateArgument(A); + Info.FirstArg = TemplateArgument(Param); + Info.SecondArg = TemplateArgument(Arg); return Sema::TDK_Underqualified; } // Objective-C ARC: // If template deduction would produce an argument type with lifetime type // but no lifetime qualifier, the __strong lifetime qualifier is inferred. - if (S.getLangOpts().ObjCAutoRefCount && DeducedType->isObjCLifetimeType() && + if (S.getLangOpts().ObjCAutoRefCount && + DeducedType->isObjCLifetimeType() && !DeducedQs.hasObjCLifetime()) DeducedQs.setObjCLifetime(Qualifiers::OCL_Strong); - DeducedType = - S.Context.getQualifiedType(DeducedType.getUnqualifiedType(), DeducedQs); + DeducedType = S.Context.getQualifiedType(DeducedType.getUnqualifiedType(), + DeducedQs); + + if (RecanonicalizeArg) + DeducedType = S.Context.getCanonicalType(DeducedType); DeducedTemplateArgument NewDeduced(DeducedType, DeducedFromArrayBound); - DeducedTemplateArgument Result = - checkDeducedTemplateArguments(S.Context, Deduced[Index], NewDeduced); + DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context, + Deduced[Index], + NewDeduced); if (Result.isNull()) { Info.Param = cast(TemplateParams->getParam(Index)); Info.FirstArg = Deduced[Index]; @@ -1508,57 +1552,69 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( } // Set up the template argument deduction information for a failure. - Info.FirstArg = TemplateArgument(P); - Info.SecondArg = TemplateArgument(A); + Info.FirstArg = TemplateArgument(ParamIn); + Info.SecondArg = TemplateArgument(ArgIn); // 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 (P->getAs()) + if (isa(Param)) return Sema::TDK_Success; // Check the cv-qualifiers on the parameter and argument types. + CanQualType CanParam = S.Context.getCanonicalType(Param); + CanQualType CanArg = S.Context.getCanonicalType(Arg); if (!(TDF & TDF_IgnoreQualifiers)) { if (TDF & TDF_ParamWithReferenceType) { - if (hasInconsistentOrSupersetQualifiersOf(P, A)) + if (hasInconsistentOrSupersetQualifiersOf(Param, Arg)) return Sema::TDK_NonDeducedMismatch; } else if (TDF & TDF_ArgWithReferenceType) { // C++ [temp.deduct.conv]p4: // If the original A is a reference type, A can be more cv-qualified // than the deduced A - if (!A.getQualifiers().compatiblyIncludes(P.getQualifiers())) + if (!Arg.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; - A = S.Context.getUnqualifiedArrayType(A, Quals); - A = S.Context.getQualifiedType(A, P.getQualifiers()); - } else if (!IsPossiblyOpaquelyQualifiedType(P)) { - if (P.getCVRQualifiers() != A.getCVRQualifiers()) + Arg = S.Context.getUnqualifiedArrayType(Arg, Quals); + Arg = S.Context.getQualifiedType(Arg, Param.getQualifiers()); + } else if (!IsPossiblyOpaquelyQualifiedType(Param)) { + if (Param.getCVRQualifiers() != Arg.getCVRQualifiers()) return Sema::TDK_NonDeducedMismatch; } + + // If the parameter type is not dependent, there is nothing to deduce. + if (!Param->isDependentType()) { + if (!(TDF & TDF_SkipNonDependent)) { + bool NonDeduced = + (TDF & TDF_AllowCompatibleFunctionType) + ? !S.isSameOrCompatibleFunctionType(CanParam, CanArg) + : Param != Arg; + if (NonDeduced) { + return Sema::TDK_NonDeducedMismatch; + } + } + return Sema::TDK_Success; + } + } else if (!Param->isDependentType()) { + if (!(TDF & TDF_SkipNonDependent)) { + CanQualType ParamUnqualType = CanParam.getUnqualifiedType(), + ArgUnqualType = CanArg.getUnqualifiedType(); + bool Success = + (TDF & TDF_AllowCompatibleFunctionType) + ? S.isSameOrCompatibleFunctionType(ParamUnqualType, ArgUnqualType) + : ParamUnqualType == ArgUnqualType; + if (Success) + return Sema::TDK_Success; + } else { + return Sema::TDK_Success; + } } - // If the parameter type is not dependent, there is nothing to deduce. - if (!P->isDependentType()) { - if (TDF & TDF_SkipNonDependent) - return Sema::TDK_Success; - if ((TDF & TDF_IgnoreQualifiers) ? S.Context.hasSameUnqualifiedType(P, A) - : S.Context.hasSameType(P, A)) - return Sema::TDK_Success; - if (TDF & TDF_AllowCompatibleFunctionType && - S.isSameOrCompatibleFunctionType(P, A)) - return Sema::TDK_Success; - if (!(TDF & TDF_IgnoreQualifiers)) - return Sema::TDK_NonDeducedMismatch; - // Otherwise, when ignoring qualifiers, the types not having the same - // unqualified type does not mean they do not match, so in this case we - // must keep going and analyze with a non-dependent parameter type. - } - - switch (P.getCanonicalType()->getTypeClass()) { + switch (Param->getTypeClass()) { // Non-canonical types cannot appear here. #define NON_CANONICAL_TYPE(Class, Base) \ case Type::Class: llvm_unreachable("deducing non-canonical type: " #Class); @@ -1569,11 +1625,8 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( case Type::SubstTemplateTypeParmPack: llvm_unreachable("Type nodes handled above"); - case Type::Auto: - // FIXME: Implement deduction in dependent case. - if (P->isDependentType()) - return Sema::TDK_Success; - LLVM_FALLTHROUGH; + // These types cannot be dependent, so simply check whether the types are + // the same. case Type::Builtin: case Type::VariableArray: case Type::Vector: @@ -1584,115 +1637,134 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( case Type::ObjCInterface: case Type::ObjCObjectPointer: case Type::ExtInt: - return (TDF & TDF_SkipNonDependent) || - ((TDF & TDF_IgnoreQualifiers) - ? S.Context.hasSameUnqualifiedType(P, A) - : S.Context.hasSameType(P, A)) - ? Sema::TDK_Success - : Sema::TDK_NonDeducedMismatch; + if (TDF & TDF_SkipNonDependent) + return Sema::TDK_Success; + + if (TDF & TDF_IgnoreQualifiers) { + Param = Param.getUnqualifiedType(); + Arg = Arg.getUnqualifiedType(); + } + + return Param == Arg? Sema::TDK_Success : Sema::TDK_NonDeducedMismatch; // _Complex T [placeholder extension] - case Type::Complex: { - const auto *CP = P->castAs(), *CA = A->getAs(); - if (!CA) - return Sema::TDK_NonDeducedMismatch; - return DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, CP->getElementType(), CA->getElementType(), Info, - Deduced, TDF); - } + case Type::Complex: + if (const ComplexType *ComplexArg = Arg->getAs()) + return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, + cast(Param)->getElementType(), + ComplexArg->getElementType(), + Info, Deduced, TDF); + + return Sema::TDK_NonDeducedMismatch; // _Atomic T [extension] - case Type::Atomic: { - const auto *PA = P->castAs(), *AA = A->getAs(); - if (!AA) - return Sema::TDK_NonDeducedMismatch; - return DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, PA->getValueType(), AA->getValueType(), Info, - Deduced, TDF); - } + case Type::Atomic: + if (const AtomicType *AtomicArg = Arg->getAs()) + return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, + cast(Param)->getValueType(), + AtomicArg->getValueType(), + Info, Deduced, TDF); + + return Sema::TDK_NonDeducedMismatch; // T * case Type::Pointer: { QualType PointeeType; - if (const auto *PA = A->getAs()) { - PointeeType = PA->getPointeeType(); - } else if (const auto *PA = A->getAs()) { - PointeeType = PA->getPointeeType(); + if (const PointerType *PointerArg = Arg->getAs()) { + PointeeType = PointerArg->getPointeeType(); + } else if (const ObjCObjectPointerType *PointerArg + = Arg->getAs()) { + PointeeType = PointerArg->getPointeeType(); } else { return Sema::TDK_NonDeducedMismatch; } - return DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, P->castAs()->getPointeeType(), - PointeeType, Info, Deduced, - TDF & (TDF_IgnoreQualifiers | TDF_DerivedClass)); + + unsigned SubTDF = TDF & (TDF_IgnoreQualifiers | TDF_DerivedClass); + return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, + cast(Param)->getPointeeType(), + PointeeType, + Info, Deduced, SubTDF); } // T & case Type::LValueReference: { - const auto *RP = P->castAs(), - *RA = A->getAs(); - if (!RA) + const LValueReferenceType *ReferenceArg = + Arg->getAs(); + if (!ReferenceArg) return Sema::TDK_NonDeducedMismatch; - return DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, RP->getPointeeType(), RA->getPointeeType(), Info, - Deduced, 0); + return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, + cast(Param)->getPointeeType(), + ReferenceArg->getPointeeType(), Info, Deduced, 0); } // T && [C++0x] case Type::RValueReference: { - const auto *RP = P->castAs(), - *RA = A->getAs(); - if (!RA) + const RValueReferenceType *ReferenceArg = + Arg->getAs(); + if (!ReferenceArg) return Sema::TDK_NonDeducedMismatch; - return DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, RP->getPointeeType(), RA->getPointeeType(), Info, - Deduced, 0); + return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, + cast(Param)->getPointeeType(), + ReferenceArg->getPointeeType(), + Info, Deduced, 0); } // T [] (implied, but not stated explicitly) case Type::IncompleteArray: { - const auto *IAA = S.Context.getAsIncompleteArrayType(A); - if (!IAA) + const IncompleteArrayType *IncompleteArrayArg = + S.Context.getAsIncompleteArrayType(Arg); + if (!IncompleteArrayArg) return Sema::TDK_NonDeducedMismatch; - return DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, - S.Context.getAsIncompleteArrayType(P)->getElementType(), - IAA->getElementType(), Info, Deduced, TDF & TDF_IgnoreQualifiers); + unsigned SubTDF = TDF & TDF_IgnoreQualifiers; + return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, + S.Context.getAsIncompleteArrayType(Param)->getElementType(), + IncompleteArrayArg->getElementType(), + Info, Deduced, SubTDF); } // T [integer-constant] case Type::ConstantArray: { - const auto *CAA = S.Context.getAsConstantArrayType(A), - *CAP = S.Context.getAsConstantArrayType(P); - assert(CAP); - if (!CAA || CAA->getSize() != CAP->getSize()) + const ConstantArrayType *ConstantArrayArg = + S.Context.getAsConstantArrayType(Arg); + if (!ConstantArrayArg) return Sema::TDK_NonDeducedMismatch; - return DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, CAP->getElementType(), CAA->getElementType(), Info, - Deduced, TDF & TDF_IgnoreQualifiers); + const ConstantArrayType *ConstantArrayParm = + S.Context.getAsConstantArrayType(Param); + if (ConstantArrayArg->getSize() != ConstantArrayParm->getSize()) + return Sema::TDK_NonDeducedMismatch; + + unsigned SubTDF = TDF & TDF_IgnoreQualifiers; + return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, + ConstantArrayParm->getElementType(), + ConstantArrayArg->getElementType(), + Info, Deduced, SubTDF); } // type [i] case Type::DependentSizedArray: { - const auto *AA = S.Context.getAsArrayType(A); - if (!AA) + const ArrayType *ArrayArg = S.Context.getAsArrayType(Arg); + if (!ArrayArg) return Sema::TDK_NonDeducedMismatch; + unsigned SubTDF = TDF & TDF_IgnoreQualifiers; + // Check the element type of the arrays - const auto *DAP = S.Context.getAsDependentSizedArrayType(P); - assert(DAP); - if (auto Result = DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, DAP->getElementType(), AA->getElementType(), - Info, Deduced, TDF & TDF_IgnoreQualifiers)) + const DependentSizedArrayType *DependentArrayParm + = S.Context.getAsDependentSizedArrayType(Param); + if (Sema::TemplateDeductionResult Result + = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, + DependentArrayParm->getElementType(), + ArrayArg->getElementType(), + Info, Deduced, SubTDF)) return Result; // Determine the array bound is something we can deduce. - const NonTypeTemplateParmDecl *NTTP = - getDeducedParameterFromExpr(Info, DAP->getSizeExpr()); + const NonTypeTemplateParmDecl *NTTP + = getDeducedParameterFromExpr(Info, DependentArrayParm->getSizeExpr()); if (!NTTP) return Sema::TDK_Success; @@ -1700,16 +1772,20 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // template parameter. assert(NTTP->getDepth() == Info.getDeducedDepth() && "saw non-type template parameter with wrong depth"); - if (const auto *CAA = dyn_cast(AA)) { - llvm::APSInt Size(CAA->getSize()); - return DeduceNonTypeTemplateArgument( - S, TemplateParams, NTTP, Size, S.Context.getSizeType(), - /*ArrayBound=*/true, Info, Deduced); + if (const ConstantArrayType *ConstantArrayArg + = dyn_cast(ArrayArg)) { + llvm::APSInt Size(ConstantArrayArg->getSize()); + return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, Size, + S.Context.getSizeType(), + /*ArrayBound=*/true, + Info, Deduced); } - if (const auto *DAA = dyn_cast(AA)) - if (DAA->getSizeExpr()) - return DeduceNonTypeTemplateArgument( - S, TemplateParams, NTTP, DAA->getSizeExpr(), Info, Deduced); + if (const DependentSizedArrayType *DependentArrayArg + = dyn_cast(ArrayArg)) + if (DependentArrayArg->getSizeExpr()) + return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, + DependentArrayArg->getSizeExpr(), + Info, Deduced); // Incomplete type does not match a dependently-sized array type return Sema::TDK_NonDeducedMismatch; @@ -1719,29 +1795,34 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // T(*)() // T(*)(T) case Type::FunctionProto: { - const auto *FPP = P->castAs(), - *FPA = A->getAs(); - if (!FPA) + unsigned SubTDF = TDF & TDF_TopLevelParameterTypeList; + const FunctionProtoType *FunctionProtoArg = + dyn_cast(Arg); + if (!FunctionProtoArg) return Sema::TDK_NonDeducedMismatch; - if (FPP->getMethodQuals() != FPA->getMethodQuals() || - FPP->getRefQualifier() != FPA->getRefQualifier() || - FPP->isVariadic() != FPA->isVariadic()) + const FunctionProtoType *FunctionProtoParam = + cast(Param); + + if (FunctionProtoParam->getMethodQuals() + != FunctionProtoArg->getMethodQuals() || + FunctionProtoParam->getRefQualifier() + != FunctionProtoArg->getRefQualifier() || + FunctionProtoParam->isVariadic() != FunctionProtoArg->isVariadic()) return Sema::TDK_NonDeducedMismatch; // Check return types. if (auto Result = DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, FPP->getReturnType(), FPA->getReturnType(), - Info, Deduced, 0, - /*PartialOrdering=*/false, - /*DeducedFromArrayBound=*/false)) + S, TemplateParams, FunctionProtoParam->getReturnType(), + FunctionProtoArg->getReturnType(), Info, Deduced, 0)) return Result; // Check parameter types. if (auto Result = DeduceTemplateArguments( - S, TemplateParams, FPP->param_type_begin(), FPP->getNumParams(), - FPA->param_type_begin(), FPA->getNumParams(), Info, Deduced, - TDF & TDF_TopLevelParameterTypeList)) + S, TemplateParams, FunctionProtoParam->param_type_begin(), + FunctionProtoParam->getNumParams(), + FunctionProtoArg->param_type_begin(), + FunctionProtoArg->getNumParams(), Info, Deduced, SubTDF)) return Result; if (TDF & TDF_AllowCompatibleFunctionType) @@ -1750,15 +1831,15 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // FIXME: Per core-2016/10/1019 (no corresponding core issue yet), permit // deducing through the noexcept-specifier if it's part of the canonical // type. libstdc++ relies on this. - Expr *NoexceptExpr = FPP->getNoexceptExpr(); + Expr *NoexceptExpr = FunctionProtoParam->getNoexceptExpr(); if (const NonTypeTemplateParmDecl *NTTP = - NoexceptExpr ? getDeducedParameterFromExpr(Info, NoexceptExpr) - : nullptr) { + NoexceptExpr ? getDeducedParameterFromExpr(Info, NoexceptExpr) + : nullptr) { assert(NTTP->getDepth() == Info.getDeducedDepth() && "saw non-type template parameter with wrong depth"); llvm::APSInt Noexcept(1); - switch (FPA->canThrow()) { + switch (FunctionProtoArg->canThrow()) { case CT_Cannot: Noexcept = 1; LLVM_FALLTHROUGH; @@ -1768,10 +1849,10 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // FIXME: Should we? return DeduceNonTypeTemplateArgument( S, TemplateParams, NTTP, Noexcept, S.Context.BoolTy, - /*DeducedFromArrayBound=*/true, Info, Deduced); + /*ArrayBound*/true, Info, Deduced); case CT_Dependent: - if (Expr *ArgNoexceptExpr = FPA->getNoexceptExpr()) + if (Expr *ArgNoexceptExpr = FunctionProtoArg->getNoexceptExpr()) return DeduceNonTypeTemplateArgument( S, TemplateParams, NTTP, ArgNoexceptExpr, Info, Deduced); // Can't deduce anything from throw(T...). @@ -1789,6 +1870,11 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( case Type::InjectedClassName: // Treat a template's injected-class-name as if the template // specialization type had been used. + Param = cast(Param) + ->getInjectedSpecializationType(); + assert(isa(Param) && + "injected class name is not a template specialization type"); + LLVM_FALLTHROUGH; // template-name (where template-name refers to a class template) // template-name @@ -1796,33 +1882,41 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // TT // TT<> case Type::TemplateSpecialization: { + const TemplateSpecializationType *SpecParam = + cast(Param); + // When Arg cannot be a derived class, we can just try to deduce template // arguments from the template-id. - if (!(TDF & TDF_DerivedClass) || !A->isRecordType()) - return DeduceTemplateSpecArguments(S, TemplateParams, P, A, Info, - Deduced); + const RecordType *RecordT = Arg->getAs(); + if (!(TDF & TDF_DerivedClass) || !RecordT) + return DeduceTemplateArguments(S, TemplateParams, SpecParam, Arg, Info, + Deduced); SmallVector DeducedOrig(Deduced.begin(), Deduced.end()); - auto Result = - DeduceTemplateSpecArguments(S, TemplateParams, P, A, Info, Deduced); + Sema::TemplateDeductionResult Result = DeduceTemplateArguments( + S, TemplateParams, SpecParam, Arg, Info, Deduced); + if (Result == Sema::TDK_Success) return Result; // We cannot inspect base classes as part of deduction when the type // is incomplete, so either instantiate any templates necessary to // complete the type, or skip over it if it cannot be completed. - if (!S.isCompleteType(Info.getLocation(), A)) + if (!S.isCompleteType(Info.getLocation(), Arg)) return Result; // Reset the incorrectly deduced argument from above. Deduced = DeducedOrig; // Check bases according to C++14 [temp.deduct.call] p4b3: - auto BaseResult = DeduceTemplateBases(S, getCanonicalRD(A), - TemplateParams, P, Info, Deduced); - return BaseResult != Sema::TDK_Invalid ? BaseResult : Result; + Sema::TemplateDeductionResult BaseResult = DeduceTemplateBases( + S, RecordT, TemplateParams, SpecParam, Info, Deduced); + + if (BaseResult != Sema::TDK_Invalid) + return BaseResult; + return Result; } // T type::* @@ -1835,27 +1929,33 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // T (T::*)() // T (T::*)(T) case Type::MemberPointer: { - const auto *MPP = P->castAs(), - *MPA = A->getAs(); - if (!MPA) + const MemberPointerType *MemPtrParam = cast(Param); + const MemberPointerType *MemPtrArg = dyn_cast(Arg); + if (!MemPtrArg) return Sema::TDK_NonDeducedMismatch; - QualType PPT = MPP->getPointeeType(); - if (PPT->isFunctionType()) - S.adjustMemberFunctionCC(PPT, /*IsStatic=*/true, + QualType ParamPointeeType = MemPtrParam->getPointeeType(); + if (ParamPointeeType->isFunctionType()) + S.adjustMemberFunctionCC(ParamPointeeType, /*IsStatic=*/true, /*IsCtorOrDtor=*/false, Info.getLocation()); - QualType APT = MPA->getPointeeType(); - if (APT->isFunctionType()) - S.adjustMemberFunctionCC(APT, /*IsStatic=*/true, + QualType ArgPointeeType = MemPtrArg->getPointeeType(); + if (ArgPointeeType->isFunctionType()) + S.adjustMemberFunctionCC(ArgPointeeType, /*IsStatic=*/true, /*IsCtorOrDtor=*/false, Info.getLocation()); - unsigned SubTDF = TDF & TDF_IgnoreQualifiers; - if (auto Result = DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, PPT, APT, Info, Deduced, SubTDF)) + if (Sema::TemplateDeductionResult Result + = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, + ParamPointeeType, + ArgPointeeType, + Info, Deduced, + TDF & TDF_IgnoreQualifiers)) return Result; - return DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, QualType(MPP->getClass(), 0), - QualType(MPA->getClass(), 0), Info, Deduced, SubTDF); + + return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, + QualType(MemPtrParam->getClass(), 0), + QualType(MemPtrArg->getClass(), 0), + Info, Deduced, + TDF & TDF_IgnoreQualifiers); } // (clang extension) @@ -1864,58 +1964,70 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // T(^)() // T(^)(T) case Type::BlockPointer: { - const auto *BPP = P->castAs(), - *BPA = A->getAs(); - if (!BPA) + const BlockPointerType *BlockPtrParam = cast(Param); + const BlockPointerType *BlockPtrArg = dyn_cast(Arg); + + if (!BlockPtrArg) return Sema::TDK_NonDeducedMismatch; - return DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, BPP->getPointeeType(), BPA->getPointeeType(), Info, - Deduced, 0); + + return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, + BlockPtrParam->getPointeeType(), + BlockPtrArg->getPointeeType(), + Info, Deduced, 0); } // (clang extension) // // T __attribute__(((ext_vector_type()))) case Type::ExtVector: { - const auto *VP = P->castAs(); - QualType ElementType; - if (const auto *VA = A->getAs()) { + const ExtVectorType *VectorParam = cast(Param); + if (const ExtVectorType *VectorArg = dyn_cast(Arg)) { // Make sure that the vectors have the same number of elements. - if (VP->getNumElements() != VA->getNumElements()) + if (VectorParam->getNumElements() != VectorArg->getNumElements()) return Sema::TDK_NonDeducedMismatch; - ElementType = VA->getElementType(); - } else if (const auto *VA = A->getAs()) { + + // Perform deduction on the element types. + return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, + VectorParam->getElementType(), + VectorArg->getElementType(), + Info, Deduced, TDF); + } + + if (const DependentSizedExtVectorType *VectorArg + = dyn_cast(Arg)) { // We can't check the number of elements, since the argument has a // dependent number of elements. This can only occur during partial // ordering. - ElementType = VA->getElementType(); - } else { - return Sema::TDK_NonDeducedMismatch; + + // Perform deduction on the element types. + return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, + VectorParam->getElementType(), + VectorArg->getElementType(), + Info, Deduced, TDF); } - // Perform deduction on the element types. - return DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, VP->getElementType(), ElementType, Info, Deduced, - TDF); + + return Sema::TDK_NonDeducedMismatch; } case Type::DependentVector: { - const auto *VP = P->castAs(); + const auto *VectorParam = cast(Param); - if (const auto *VA = A->getAs()) { + if (const auto *VectorArg = dyn_cast(Arg)) { // Perform deduction on the element types. - if (auto Result = DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, VP->getElementType(), VA->getElementType(), - Info, Deduced, TDF)) + if (Sema::TemplateDeductionResult Result = + DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, VectorParam->getElementType(), + VectorArg->getElementType(), Info, Deduced, TDF)) return Result; // Perform deduction on the vector size, if we can. const NonTypeTemplateParmDecl *NTTP = - getDeducedParameterFromExpr(Info, VP->getSizeExpr()); + getDeducedParameterFromExpr(Info, VectorParam->getSizeExpr()); if (!NTTP) return Sema::TDK_Success; llvm::APSInt ArgSize(S.Context.getTypeSize(S.Context.IntTy), false); - ArgSize = VA->getNumElements(); + ArgSize = VectorArg->getNumElements(); // Note that we use the "array bound" rules here; just like in that // case, we don't have any particular type for the vector size, but // we can provide one if necessary. @@ -1924,21 +2036,22 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( Info, Deduced); } - if (const auto *VA = A->getAs()) { + if (const auto *VectorArg = dyn_cast(Arg)) { // Perform deduction on the element types. - if (auto Result = DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, VP->getElementType(), VA->getElementType(), - Info, Deduced, TDF)) + if (Sema::TemplateDeductionResult Result = + DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, VectorParam->getElementType(), + VectorArg->getElementType(), Info, Deduced, TDF)) return Result; // Perform deduction on the vector size, if we can. - const NonTypeTemplateParmDecl *NTTP = - getDeducedParameterFromExpr(Info, VP->getSizeExpr()); + const NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr( + Info, VectorParam->getSizeExpr()); if (!NTTP) return Sema::TDK_Success; - return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, - VA->getSizeExpr(), Info, Deduced); + return DeduceNonTypeTemplateArgument( + S, TemplateParams, NTTP, VectorArg->getSizeExpr(), Info, Deduced); } return Sema::TDK_NonDeducedMismatch; @@ -1948,23 +2061,26 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // // T __attribute__(((ext_vector_type(N)))) case Type::DependentSizedExtVector: { - const auto *VP = P->castAs(); + const DependentSizedExtVectorType *VectorParam + = cast(Param); - if (const auto *VA = A->getAs()) { + if (const ExtVectorType *VectorArg = dyn_cast(Arg)) { // Perform deduction on the element types. - if (auto Result = DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, VP->getElementType(), VA->getElementType(), - Info, Deduced, TDF)) + if (Sema::TemplateDeductionResult Result + = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, + VectorParam->getElementType(), + VectorArg->getElementType(), + Info, Deduced, TDF)) return Result; // Perform deduction on the vector size, if we can. const NonTypeTemplateParmDecl *NTTP = - getDeducedParameterFromExpr(Info, VP->getSizeExpr()); + getDeducedParameterFromExpr(Info, VectorParam->getSizeExpr()); if (!NTTP) return Sema::TDK_Success; llvm::APSInt ArgSize(S.Context.getTypeSize(S.Context.IntTy), false); - ArgSize = VA->getNumElements(); + ArgSize = VectorArg->getNumElements(); // Note that we use the "array bound" rules here; just like in that // case, we don't have any particular type for the vector size, but // we can provide one if necessary. @@ -1973,21 +2089,25 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( Deduced); } - if (const auto *VA = A->getAs()) { + if (const DependentSizedExtVectorType *VectorArg + = dyn_cast(Arg)) { // Perform deduction on the element types. - if (auto Result = DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, VP->getElementType(), VA->getElementType(), - Info, Deduced, TDF)) + if (Sema::TemplateDeductionResult Result + = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, + VectorParam->getElementType(), + VectorArg->getElementType(), + Info, Deduced, TDF)) return Result; // Perform deduction on the vector size, if we can. const NonTypeTemplateParmDecl *NTTP = - getDeducedParameterFromExpr(Info, VP->getSizeExpr()); + getDeducedParameterFromExpr(Info, VectorParam->getSizeExpr()); if (!NTTP) return Sema::TDK_Success; return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, - VA->getSizeExpr(), Info, Deduced); + VectorArg->getSizeExpr(), + Info, Deduced); } return Sema::TDK_NonDeducedMismatch; @@ -1998,55 +2118,57 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // T __attribute__((matrix_type(, // ))) case Type::ConstantMatrix: { - const auto *MP = P->castAs(), - *MA = A->getAs(); - if (!MA) + const ConstantMatrixType *MatrixArg = dyn_cast(Arg); + if (!MatrixArg) return Sema::TDK_NonDeducedMismatch; + const ConstantMatrixType *MatrixParam = cast(Param); // Check that the dimensions are the same - if (MP->getNumRows() != MA->getNumRows() || - MP->getNumColumns() != MA->getNumColumns()) { + if (MatrixParam->getNumRows() != MatrixArg->getNumRows() || + MatrixParam->getNumColumns() != MatrixArg->getNumColumns()) { return Sema::TDK_NonDeducedMismatch; } // Perform deduction on element types. return DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, MP->getElementType(), MA->getElementType(), Info, - Deduced, TDF); + S, TemplateParams, MatrixParam->getElementType(), + MatrixArg->getElementType(), Info, Deduced, TDF); } case Type::DependentSizedMatrix: { - const auto *MP = P->castAs(); - const auto *MA = A->getAs(); - if (!MA) + const MatrixType *MatrixArg = dyn_cast(Arg); + if (!MatrixArg) return Sema::TDK_NonDeducedMismatch; // Check the element type of the matrixes. - if (auto Result = DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, MP->getElementType(), MA->getElementType(), - Info, Deduced, TDF)) + const DependentSizedMatrixType *MatrixParam = + cast(Param); + if (Sema::TemplateDeductionResult Result = + DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, MatrixParam->getElementType(), + MatrixArg->getElementType(), Info, Deduced, TDF)) return Result; // Try to deduce a matrix dimension. auto DeduceMatrixArg = [&S, &Info, &Deduced, &TemplateParams]( - Expr *ParamExpr, const MatrixType *A, + Expr *ParamExpr, const MatrixType *Arg, unsigned (ConstantMatrixType::*GetArgDimension)() const, Expr *(DependentSizedMatrixType::*GetArgDimensionExpr)() const) { - const auto *ACM = dyn_cast(A); - const auto *ADM = dyn_cast(A); + const auto *ArgConstMatrix = dyn_cast(Arg); + const auto *ArgDepMatrix = dyn_cast(Arg); if (!ParamExpr->isValueDependent()) { Optional ParamConst = ParamExpr->getIntegerConstantExpr(S.Context); if (!ParamConst) return Sema::TDK_NonDeducedMismatch; - if (ACM) { - if ((ACM->*GetArgDimension)() == *ParamConst) + if (ArgConstMatrix) { + if ((ArgConstMatrix->*GetArgDimension)() == *ParamConst) return Sema::TDK_Success; return Sema::TDK_NonDeducedMismatch; } - Expr *ArgExpr = (ADM->*GetArgDimensionExpr)(); + Expr *ArgExpr = (ArgDepMatrix->*GetArgDimensionExpr)(); if (Optional ArgConst = ArgExpr->getIntegerConstantExpr(S.Context)) if (*ArgConst == *ParamConst) @@ -2059,26 +2181,27 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( if (!NTTP) return Sema::TDK_Success; - if (ACM) { + if (ArgConstMatrix) { llvm::APSInt ArgConst( S.Context.getTypeSize(S.Context.getSizeType())); - ArgConst = (ACM->*GetArgDimension)(); + ArgConst = (ArgConstMatrix->*GetArgDimension)(); return DeduceNonTypeTemplateArgument( S, TemplateParams, NTTP, ArgConst, S.Context.getSizeType(), /*ArrayBound=*/true, Info, Deduced); } - return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, - (ADM->*GetArgDimensionExpr)(), - Info, Deduced); + return DeduceNonTypeTemplateArgument( + S, TemplateParams, NTTP, (ArgDepMatrix->*GetArgDimensionExpr)(), + Info, Deduced); }; - if (auto Result = DeduceMatrixArg(MP->getRowExpr(), MA, - &ConstantMatrixType::getNumRows, - &DependentSizedMatrixType::getRowExpr)) + auto Result = DeduceMatrixArg(MatrixParam->getRowExpr(), MatrixArg, + &ConstantMatrixType::getNumRows, + &DependentSizedMatrixType::getRowExpr); + if (Result) return Result; - return DeduceMatrixArg(MP->getColumnExpr(), MA, + return DeduceMatrixArg(MatrixParam->getColumnExpr(), MatrixArg, &ConstantMatrixType::getNumColumns, &DependentSizedMatrixType::getColumnExpr); } @@ -2087,39 +2210,44 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // // T __attribute__(((address_space(N)))) case Type::DependentAddressSpace: { - const auto *ASP = P->castAs(); + const DependentAddressSpaceType *AddressSpaceParam = + cast(Param); - if (const auto *ASA = A->getAs()) { + if (const DependentAddressSpaceType *AddressSpaceArg = + dyn_cast(Arg)) { // Perform deduction on the pointer type. - if (auto Result = DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, ASP->getPointeeType(), ASA->getPointeeType(), - Info, Deduced, TDF)) + if (Sema::TemplateDeductionResult Result = + DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, AddressSpaceParam->getPointeeType(), + AddressSpaceArg->getPointeeType(), Info, Deduced, TDF)) return Result; // Perform deduction on the address space, if we can. - const NonTypeTemplateParmDecl *NTTP = - getDeducedParameterFromExpr(Info, ASP->getAddrSpaceExpr()); + const NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr( + Info, AddressSpaceParam->getAddrSpaceExpr()); if (!NTTP) return Sema::TDK_Success; return DeduceNonTypeTemplateArgument( - S, TemplateParams, NTTP, ASA->getAddrSpaceExpr(), Info, Deduced); + S, TemplateParams, NTTP, AddressSpaceArg->getAddrSpaceExpr(), Info, + Deduced); } - if (isTargetAddressSpace(A.getAddressSpace())) { + if (isTargetAddressSpace(Arg.getAddressSpace())) { llvm::APSInt ArgAddressSpace(S.Context.getTypeSize(S.Context.IntTy), false); - ArgAddressSpace = toTargetAddressSpace(A.getAddressSpace()); + ArgAddressSpace = toTargetAddressSpace(Arg.getAddressSpace()); // Perform deduction on the pointer types. - if (auto Result = DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, ASP->getPointeeType(), - S.Context.removeAddrSpaceQualType(A), Info, Deduced, TDF)) + if (Sema::TemplateDeductionResult Result = + DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, AddressSpaceParam->getPointeeType(), + S.Context.removeAddrSpaceQualType(Arg), Info, Deduced, TDF)) return Result; // Perform deduction on the address space, if we can. - const NonTypeTemplateParmDecl *NTTP = - getDeducedParameterFromExpr(Info, ASP->getAddrSpaceExpr()); + const NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr( + Info, AddressSpaceParam->getAddrSpaceExpr()); if (!NTTP) return Sema::TDK_Success; @@ -2131,31 +2259,30 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( return Sema::TDK_NonDeducedMismatch; } case Type::DependentExtInt: { - const auto *IP = P->castAs(); + const auto *IntParam = cast(Param); - if (const auto *IA = A->getAs()) { - if (IP->isUnsigned() != IA->isUnsigned()) + if (const auto *IntArg = dyn_cast(Arg)){ + if (IntParam->isUnsigned() != IntArg->isUnsigned()) return Sema::TDK_NonDeducedMismatch; const NonTypeTemplateParmDecl *NTTP = - getDeducedParameterFromExpr(Info, IP->getNumBitsExpr()); + getDeducedParameterFromExpr(Info, IntParam->getNumBitsExpr()); if (!NTTP) return Sema::TDK_Success; llvm::APSInt ArgSize(S.Context.getTypeSize(S.Context.IntTy), false); - ArgSize = IA->getNumBits(); + ArgSize = IntArg->getNumBits(); return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, ArgSize, S.Context.IntTy, true, Info, Deduced); } - if (const auto *IA = A->getAs()) { - if (IP->isUnsigned() != IA->isUnsigned()) + if (const auto *IntArg = dyn_cast(Arg)) { + if (IntParam->isUnsigned() != IntArg->isUnsigned()) return Sema::TDK_NonDeducedMismatch; return Sema::TDK_Success; } - return Sema::TDK_NonDeducedMismatch; } @@ -2165,103 +2292,125 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( case Type::UnresolvedUsing: case Type::Decltype: case Type::UnaryTransform: + case Type::Auto: case Type::DeducedTemplateSpecialization: case Type::DependentTemplateSpecialization: case Type::PackExpansion: case Type::Pipe: // No template argument deduction for these types return Sema::TDK_Success; - } + } llvm_unreachable("Invalid Type Class!"); } static Sema::TemplateDeductionResult -DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, - const TemplateArgument &P, TemplateArgument A, +DeduceTemplateArguments(Sema &S, + TemplateParameterList *TemplateParams, + const TemplateArgument &Param, + TemplateArgument Arg, TemplateDeductionInfo &Info, SmallVectorImpl &Deduced) { // If the template argument is a pack expansion, perform template argument // deduction against the pattern of that expansion. This only occurs during // partial ordering. - if (A.isPackExpansion()) - A = A.getPackExpansionPattern(); + if (Arg.isPackExpansion()) + Arg = Arg.getPackExpansionPattern(); - switch (P.getKind()) { + switch (Param.getKind()) { case TemplateArgument::Null: llvm_unreachable("Null template argument in parameter list"); case TemplateArgument::Type: - if (A.getKind() == TemplateArgument::Type) - return DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, P.getAsType(), A.getAsType(), Info, Deduced, 0); - Info.FirstArg = P; - Info.SecondArg = A; + if (Arg.getKind() == TemplateArgument::Type) + return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, + Param.getAsType(), + Arg.getAsType(), + Info, Deduced, 0); + Info.FirstArg = Param; + Info.SecondArg = Arg; return Sema::TDK_NonDeducedMismatch; case TemplateArgument::Template: - if (A.getKind() == TemplateArgument::Template) - return DeduceTemplateArguments(S, TemplateParams, P.getAsTemplate(), - A.getAsTemplate(), Info, Deduced); - Info.FirstArg = P; - Info.SecondArg = A; + if (Arg.getKind() == TemplateArgument::Template) + return DeduceTemplateArguments(S, TemplateParams, + Param.getAsTemplate(), + Arg.getAsTemplate(), Info, Deduced); + Info.FirstArg = Param; + Info.SecondArg = Arg; return Sema::TDK_NonDeducedMismatch; case TemplateArgument::TemplateExpansion: llvm_unreachable("caller should handle pack expansions"); case TemplateArgument::Declaration: - if (A.getKind() == TemplateArgument::Declaration && - isSameDeclaration(P.getAsDecl(), A.getAsDecl())) + if (Arg.getKind() == TemplateArgument::Declaration && + isSameDeclaration(Param.getAsDecl(), Arg.getAsDecl())) return Sema::TDK_Success; - Info.FirstArg = P; - Info.SecondArg = A; + Info.FirstArg = Param; + Info.SecondArg = Arg; return Sema::TDK_NonDeducedMismatch; case TemplateArgument::NullPtr: - if (A.getKind() == TemplateArgument::NullPtr && - S.Context.hasSameType(P.getNullPtrType(), A.getNullPtrType())) + if (Arg.getKind() == TemplateArgument::NullPtr && + S.Context.hasSameType(Param.getNullPtrType(), Arg.getNullPtrType())) return Sema::TDK_Success; - Info.FirstArg = P; - Info.SecondArg = A; + Info.FirstArg = Param; + Info.SecondArg = Arg; return Sema::TDK_NonDeducedMismatch; case TemplateArgument::Integral: - if (A.getKind() == TemplateArgument::Integral) { - if (hasSameExtendedValue(P.getAsIntegral(), A.getAsIntegral())) + 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; } - Info.FirstArg = P; - Info.SecondArg = A; + + 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: if (const NonTypeTemplateParmDecl *NTTP = - getDeducedParameterFromExpr(Info, P.getAsExpr())) { - if (A.getKind() == TemplateArgument::Integral) - return DeduceNonTypeTemplateArgument( - S, TemplateParams, NTTP, A.getAsIntegral(), A.getIntegralType(), - /*ArrayBound=*/false, Info, Deduced); - if (A.getKind() == TemplateArgument::NullPtr) - return DeduceNullPtrTemplateArgument(S, TemplateParams, NTTP, - A.getNullPtrType(), Info, Deduced); - if (A.getKind() == TemplateArgument::Expression) + getDeducedParameterFromExpr(Info, Param.getAsExpr())) { + if (Arg.getKind() == TemplateArgument::Integral) return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, - A.getAsExpr(), Info, Deduced); - if (A.getKind() == TemplateArgument::Declaration) - return DeduceNonTypeTemplateArgument( - S, TemplateParams, NTTP, A.getAsDecl(), A.getParamTypeForDecl(), - Info, Deduced); + Arg.getAsIntegral(), + Arg.getIntegralType(), + /*ArrayBound=*/false, + Info, Deduced); + if (Arg.getKind() == TemplateArgument::NullPtr) + 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); - Info.FirstArg = P; - Info.SecondArg = A; + Info.FirstArg = Param; + Info.SecondArg = Arg; return Sema::TDK_NonDeducedMismatch; } // 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!"); } @@ -2314,8 +2463,8 @@ static bool hasPackExpansionBeforeEnd(ArrayRef Args) { static Sema::TemplateDeductionResult DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, - ArrayRef Ps, - ArrayRef As, + ArrayRef Params, + ArrayRef Args, TemplateDeductionInfo &Info, SmallVectorImpl &Deduced, bool NumberOfArgumentsMustMatch) { @@ -2323,7 +2472,7 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, // If the template argument list of P contains a pack expansion that is not // the last template argument, the entire template argument list is a // non-deduced context. - if (hasPackExpansionBeforeEnd(Ps)) + if (hasPackExpansionBeforeEnd(Params)) return Sema::TDK_Success; // C++0x [temp.deduct.type]p9: @@ -2331,13 +2480,12 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, // respective template argument list P is compared with the corresponding // argument Ai of the corresponding template argument list of A. unsigned ArgIdx = 0, ParamIdx = 0; - for (; hasTemplateArgumentForDeduction(Ps, ParamIdx); ++ParamIdx) { - const TemplateArgument &P = Ps[ParamIdx]; - if (!P.isPackExpansion()) { + for (; hasTemplateArgumentForDeduction(Params, ParamIdx); ++ParamIdx) { + if (!Params[ParamIdx].isPackExpansion()) { // The simple case: deduce template arguments by matching Pi and Ai. // Check whether we have enough arguments. - if (!hasTemplateArgumentForDeduction(As, ArgIdx)) + if (!hasTemplateArgumentForDeduction(Args, ArgIdx)) return NumberOfArgumentsMustMatch ? Sema::TDK_MiscellaneousDeductionFailure : Sema::TDK_Success; @@ -2345,12 +2493,14 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, // C++1z [temp.deduct.type]p9: // During partial ordering, if Ai was originally a pack expansion [and] // Pi is not a pack expansion, template argument deduction fails. - if (As[ArgIdx].isPackExpansion()) + if (Args[ArgIdx].isPackExpansion()) return Sema::TDK_MiscellaneousDeductionFailure; // Perform deduction for this Pi/Ai pair. - if (auto Result = DeduceTemplateArguments(S, TemplateParams, P, - As[ArgIdx], Info, Deduced)) + if (Sema::TemplateDeductionResult Result + = DeduceTemplateArguments(S, TemplateParams, + Params[ParamIdx], Args[ArgIdx], + Info, Deduced)) return Result; // Move to the next argument. @@ -2365,7 +2515,7 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, // each remaining argument in the template argument list of A. Each // comparison deduces template arguments for subsequent positions in the // template parameter packs expanded by Pi. - TemplateArgument Pattern = P.getPackExpansionPattern(); + TemplateArgument Pattern = Params[ParamIdx].getPackExpansionPattern(); // Prepare to deduce the packs within the pattern. PackDeductionScope PackScope(S, TemplateParams, Deduced, Info, Pattern); @@ -2373,12 +2523,13 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, // Keep track of the deduced template arguments for each parameter pack // expanded by this pack expansion (the outer index) and for each // template argument (the inner SmallVectors). - for (; hasTemplateArgumentForDeduction(As, ArgIdx) && + for (; hasTemplateArgumentForDeduction(Args, ArgIdx) && PackScope.hasNextElement(); ++ArgIdx) { // Deduce template arguments from the pattern. - if (auto Result = DeduceTemplateArguments(S, TemplateParams, Pattern, - As[ArgIdx], Info, Deduced)) + if (Sema::TemplateDeductionResult Result + = DeduceTemplateArguments(S, TemplateParams, Pattern, Args[ArgIdx], + Info, Deduced)) return Result; PackScope.nextPackElement(); @@ -2394,14 +2545,15 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, } static Sema::TemplateDeductionResult -DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, +DeduceTemplateArguments(Sema &S, + TemplateParameterList *TemplateParams, const TemplateArgumentList &ParamList, const TemplateArgumentList &ArgList, TemplateDeductionInfo &Info, SmallVectorImpl &Deduced) { return DeduceTemplateArguments(S, TemplateParams, ParamList.asArray(), ArgList.asArray(), Info, Deduced, - /*NumberOfArgumentsMustMatch=*/false); + /*NumberOfArgumentsMustMatch*/false); } /// Determine whether two template arguments are the same. @@ -4204,7 +4356,7 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( bool HasDeducedReturnType = false; if (getLangOpts().CPlusPlus14 && IsAddressOfFunction && Function->getReturnType()->getContainedAutoType()) { - FunctionType = SubstAutoTypeDependent(FunctionType); + FunctionType = SubstAutoType(FunctionType, Context.DependentTy); HasDeducedReturnType = true; } @@ -4638,8 +4790,12 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result, ExprResult ER = CheckPlaceholderExpr(Init); if (ER.isInvalid()) return DAR_FailedAlreadyDiagnosed; - QualType Deduced = getDecltypeForExpr(ER.get()); - assert(!Deduced.isNull()); + 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); if (AT->isConstrained() && !IgnoreConstraints) { auto ConstraintsResult = CheckDeducedPlaceholderConstraints(*this, *AT, @@ -4674,7 +4830,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result, Context, Loc, Loc, TemplParamPtr, Loc, nullptr); QualType FuncParam = - SubstituteDeducedTypeTransform(*this, TemplArg, /*UseTypeSugar*/ true) + SubstituteDeducedTypeTransform(*this, TemplArg, /*UseTypeSugar*/false) .Apply(Type); assert(!FuncParam.isNull() && "substituting template parameter for 'auto' failed"); @@ -4788,29 +4944,27 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result, QualType Sema::SubstAutoType(QualType TypeWithAuto, QualType TypeToReplaceAuto) { - assert(TypeToReplaceAuto != Context.DependentTy); + if (TypeToReplaceAuto->isDependentType()) + return SubstituteDeducedTypeTransform( + *this, DependentAuto{ + TypeToReplaceAuto->containsUnexpandedParameterPack()}) + .TransformType(TypeWithAuto); return SubstituteDeducedTypeTransform(*this, TypeToReplaceAuto) .TransformType(TypeWithAuto); } TypeSourceInfo *Sema::SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto, QualType TypeToReplaceAuto) { - assert(TypeToReplaceAuto != Context.DependentTy); + if (TypeToReplaceAuto->isDependentType()) + return SubstituteDeducedTypeTransform( + *this, + DependentAuto{ + TypeToReplaceAuto->containsUnexpandedParameterPack()}) + .TransformType(TypeWithAuto); 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, @@ -5005,7 +5159,6 @@ static bool isAtLeastAsSpecializedAs(Sema &S, Args2.resize(NumComparedArguments); if (Reversed) std::reverse(Args2.begin(), Args2.end()); - if (DeduceTemplateArguments(S, TemplateParams, Args2.data(), Args2.size(), Args1.data(), Args1.size(), Info, Deduced, TDF_None, /*PartialOrdering=*/true)) diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index f99b032427e8..3512165ffdbf 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -1622,7 +1622,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { Expr *E = DS.getRepAsExpr(); assert(E && "Didn't get an expression for typeof?"); // TypeQuals handled by caller. - Result = S.BuildTypeofExprType(E); + Result = S.BuildTypeofExprType(E, DS.getTypeSpecTypeLoc()); if (Result.isNull()) { Result = Context.IntTy; declarator.setInvalidType(true); @@ -1633,7 +1633,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { Expr *E = DS.getRepAsExpr(); assert(E && "Didn't get an expression for decltype?"); // TypeQuals handled by caller. - Result = S.BuildDecltypeType(E); + Result = S.BuildDecltypeType(E, DS.getTypeSpecTypeLoc()); if (Result.isNull()) { Result = Context.IntTy; declarator.setInvalidType(true); @@ -8925,7 +8925,7 @@ QualType Sema::getElaboratedType(ElaboratedTypeKeyword Keyword, return Context.getElaboratedType(Keyword, NNS, T, OwnedTagDecl); } -QualType Sema::BuildTypeofExprType(Expr *E) { +QualType Sema::BuildTypeofExprType(Expr *E, SourceLocation Loc) { assert(!E->hasPlaceholderType() && "unexpected placeholder"); if (!getLangOpts().CPlusPlus && E->refersToBitField()) @@ -8942,9 +8942,9 @@ QualType Sema::BuildTypeofExprType(Expr *E) { /// 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. -QualType Sema::getDecltypeForExpr(Expr *E) { +static QualType getDecltypeForExpr(Sema &S, Expr *E) { if (E->isTypeDependent()) - return Context.DependentTy; + return S.Context.DependentTy; Expr *IDExpr = E; if (auto *ImplCastExpr = dyn_cast(E)) @@ -8961,7 +8961,7 @@ QualType Sema::getDecltypeForExpr(Expr *E) { // parameter object. This rule makes no difference before C++20 so we apply // it unconditionally. if (const auto *SNTTPE = dyn_cast(IDExpr)) - return SNTTPE->getParameterType(Context); + return SNTTPE->getParameterType(S.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 @@ -8969,21 +8969,22 @@ QualType Sema::getDecltypeForExpr(Expr *E) { // functions, the program is ill-formed; // // We apply the same rules for Objective-C ivar and property references. - if (const auto *DRE = dyn_cast(IDExpr)) { + if (const DeclRefExpr *DRE = dyn_cast(IDExpr)) { const ValueDecl *VD = DRE->getDecl(); - QualType T = VD->getType(); - return isa(VD) ? T.getUnqualifiedType() : T; - } - if (const auto *ME = dyn_cast(IDExpr)) { - if (const auto *VD = ME->getMemberDecl()) + if (auto *TPO = dyn_cast(VD)) + return TPO->getType().getUnqualifiedType(); + return VD->getType(); + } else if (const MemberExpr *ME = dyn_cast(IDExpr)) { + if (const ValueDecl *VD = ME->getMemberDecl()) if (isa(VD) || isa(VD)) return VD->getType(); - } else if (const auto *IR = dyn_cast(IDExpr)) { + } else if (const ObjCIvarRefExpr *IR = dyn_cast(IDExpr)) { return IR->getDecl()->getType(); - } else if (const auto *PR = dyn_cast(IDExpr)) { + } else if (const ObjCPropertyRefExpr *PR = + dyn_cast(IDExpr)) { if (PR->isExplicitProperty()) return PR->getExplicitProperty()->getType(); - } else if (const auto *PE = dyn_cast(IDExpr)) { + } else if (auto *PE = dyn_cast(IDExpr)) { return PE->getType(); } @@ -8994,20 +8995,24 @@ QualType Sema::getDecltypeForExpr(Expr *E) { // 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. - if (getCurLambda() && isa(IDExpr)) { - if (auto *DRE = dyn_cast(IDExpr->IgnoreParens())) { - if (auto *Var = dyn_cast(DRE->getDecl())) { - QualType T = getCapturedDeclRefType(Var, DRE->getLocation()); - if (!T.isNull()) - return Context.getLValueReferenceType(T); + using namespace sema; + if (S.getCurLambda()) { + if (isa(IDExpr)) { + if (DeclRefExpr *DRE = dyn_cast(IDExpr->IgnoreParens())) { + if (VarDecl *Var = dyn_cast(DRE->getDecl())) { + QualType T = S.getCapturedDeclRefType(Var, DRE->getLocation()); + if (!T.isNull()) + return S.Context.getLValueReferenceType(T); + } } } } - return Context.getReferenceQualifiedType(E); + return S.Context.getReferenceQualifiedType(E); } -QualType Sema::BuildDecltypeType(Expr *E, bool AsUnevaluated) { +QualType Sema::BuildDecltypeType(Expr *E, SourceLocation Loc, + bool AsUnevaluated) { assert(!E->hasPlaceholderType() && "unexpected placeholder"); if (AsUnevaluated && CodeSynthesisContexts.empty() && @@ -9018,7 +9023,8 @@ QualType Sema::BuildDecltypeType(Expr *E, bool AsUnevaluated) { // used to build SFINAE gadgets. Diag(E->getExprLoc(), diag::warn_side_effects_unevaluated_context); } - return Context.getDecltypeType(E, getDecltypeForExpr(E)); + + return Context.getDecltypeType(E, getDecltypeForExpr(*this, E)); } QualType Sema::BuildUnaryTransformType(QualType BaseType, diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 442b4819b808..c1e9890094fd 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -6586,7 +6586,7 @@ QualType TreeTransform::TransformAutoType(TypeLocBuilder &TLB, T->isDependentType() || T->isConstrained()) { // FIXME: Maybe don't rebuild if all template arguments are the same. llvm::SmallVector NewArgList; - NewArgList.reserve(NewTemplateArgs.size()); + NewArgList.reserve(NewArgList.size()); for (const auto &ArgLoc : NewTemplateArgs.arguments()) NewArgList.push_back(ArgLoc.getArgument()); Result = getDerived().RebuildAutoType(NewDeduced, T->getKeyword(), NewCD, @@ -14501,10 +14501,10 @@ QualType TreeTransform::RebuildUnresolvedUsingType(SourceLocation Loc, return SemaRef.Context.getTypeDeclType(Ty); } -template +template QualType TreeTransform::RebuildTypeOfExprType(Expr *E, - SourceLocation) { - return SemaRef.BuildTypeofExprType(E); + SourceLocation Loc) { + return SemaRef.BuildTypeofExprType(E, Loc); } template @@ -14512,9 +14512,10 @@ QualType TreeTransform::RebuildTypeOfType(QualType Underlying) { return SemaRef.Context.getTypeOfType(Underlying); } -template -QualType TreeTransform::RebuildDecltypeType(Expr *E, SourceLocation) { - return SemaRef.BuildDecltypeType(E); +template +QualType TreeTransform::RebuildDecltypeType(Expr *E, + SourceLocation Loc) { + return SemaRef.BuildDecltypeType(E, Loc); } template diff --git a/clang/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp b/clang/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp index 594654730d07..cb9407b1db88 100644 --- a/clang/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp +++ b/clang/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp @@ -36,7 +36,7 @@ namespace std { namespace p0702r1 { template struct X { // expected-note {{candidate}} - X(std::initializer_list); // expected-note {{candidate template ignored: could not match 'std::initializer_list' against 'p0702r1::Z'}} + X(std::initializer_list); // expected-note {{candidate template ignored: could not match 'initializer_list' against 'p0702r1::Z'}} }; X xi = {0}; diff --git a/clang/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp b/clang/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp index 751ad58ad820..0963dd23724a 100644 --- a/clang/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp +++ b/clang/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp @@ -321,14 +321,14 @@ namespace p0962r1 { namespace NE { struct E { - void begin(); // expected-note {{member is not a candidate because range type 'NE::E' has no 'end' member}} + void begin(); // expected-note {{member is not a candidate because range type 'p0962r1::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 'NF::F' has no 'begin' member}} + void end(); // expected-note {{member is not a candidate because range type 'p0962r1::NF::F' has no 'begin' member}} }; int *begin(F); } @@ -336,9 +336,9 @@ namespace p0962r1 { 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 '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}} + 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}} } } diff --git a/clang/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp b/clang/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp index 30e7c65dac91..46fc91325880 100644 --- a/clang/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp +++ b/clang/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp @@ -284,7 +284,7 @@ namespace PR13386 { void g(U &&...u, T &&...t) {} // expected-note {{candidate}} template void h(tuple &&...) {} - // expected-note@-1 {{candidate template ignored: could not match 'tuple' against 'int'}} + // expected-note@-1 {{candidate template ignored: could not match 'tuple' against 'int'}} // expected-note@-2 {{candidate template ignored: substitution failure: deduced incomplete pack <(no value)> for template parameter 'U'}} template diff --git a/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p1-0x.cpp b/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p1-0x.cpp index 1da599ed3c27..081bba2b8dff 100644 --- a/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p1-0x.cpp +++ b/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p1-0x.cpp @@ -53,8 +53,9 @@ void test_simple_ref_deduction(int *ip, float *fp, double *dp) { } +// FIXME: Use the template parameter names in this diagnostic. template -typename get_nth_type<0, Args1...>::type first_arg_pair(pair...); // expected-note{{candidate template ignored: could not match 'pair' against 'int'}} +typename get_nth_type<0, Args1...>::type first_arg_pair(pair...); // expected-note{{candidate template ignored: could not match 'pair' against 'int'}} template typename get_nth_type<1, Args1...>::type second_arg_pair(pair...); diff --git a/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p4.cpp b/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p4.cpp index fe0af399f7b9..357ea664037d 100644 --- a/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p4.cpp +++ b/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p4.cpp @@ -18,12 +18,6 @@ namespace PR12132 { void foo() { fun(&A::x); } - struct B { char* x; }; - void bar() { - fun(&B::x); - // expected-error@-1 {{no matching function for call to 'fun'}} - // expected-note@-9 {{candidate template ignored: could not match 'const int' against 'char'}} - } } #if __cplusplus > 201402L @@ -58,4 +52,6 @@ namespace noexcept_conversion { int i1 = i(g1); int i2 = i(g2); } +#else +// expected-no-diagnostics #endif diff --git a/clang/test/Index/print-type.cpp b/clang/test/Index/print-type.cpp index 458acc42ef3e..f52ee8092e8f 100644 --- a/clang/test/Index/print-type.cpp +++ b/clang/test/Index/print-type.cpp @@ -199,7 +199,7 @@ inline namespace InlineNS {} // CHECK: UnexposedExpr=templRefParam:71:40 [type=const Specialization &>] [typekind=Record] const [templateargs/1= [type=Specialization &] [typekind=LValueReference]] [isPOD=1] // CHECK: DeclRefExpr=templRefParam:71:40 [type=Specialization &>] [typekind=Unexposed] [templateargs/1= [type=Specialization &] [typekind=LValueReference]] [canonicaltype=Specialization &>] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=Specialization &] [typekind=LValueReference]] [isPOD=1] // CHECK: TypeAliasDecl=baz:76:7 (Definition) [type=baz] [typekind=Typedef] [templateargs/1= [type=A] [typekind=Unexposed]] [canonicaltype=A] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=void] [typekind=Void]] [isPOD=0] -// CHECK: VarDecl=autoTemplPointer:78:6 (Definition) [type=Specialization &> *] [typekind=Auto] [canonicaltype=Specialization &> *] [canonicaltypekind=Pointer] [isPOD=1] [pointeetype=Specialization &>] [pointeekind=Auto] +// CHECK: VarDecl=autoTemplPointer:78:6 (Definition) [type=Specialization &> *] [typekind=Auto] [canonicaltype=Specialization &> *] [canonicaltypekind=Pointer] [isPOD=1] [pointeetype=Specialization &>] [pointeekind=Record] // CHECK: CallExpr=Bar:17:3 [type=outer::inner::Bar] [typekind=Elaborated] [canonicaltype=outer::inner::Bar] [canonicaltypekind=Record] [args= [outer::Foo *] [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] diff --git a/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp b/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp index 5a49f28ef9a1..84b3a542dcaa 100644 --- a/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp +++ b/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp @@ -569,52 +569,6 @@ namespace PR52139 { virtual void f() = 0; }; } - -namespace function_prototypes { - template using fptr1 = void (*) (T); - template using fptr2 = fptr1>; - - template void foo0(fptr1) { - static_assert(__is_same(T, const char*)); - } - void bar0(const char *const volatile __restrict); - void t0() { foo0(&bar0); } - - template void foo1(fptr1) { - static_assert(__is_same(T, char)); - } - void bar1(const char * __restrict); - void t1() { foo1(&bar1); } - - template void foo2(fptr2) { - static_assert(__is_same(T, char)); - } - void bar2(fptr1); - void t2() { foo2(&bar2); } - - template void foo3(fptr1) {} - 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 void foo4(fptr2) {} - void bar4(fptr1); - 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'}} - - template void foo5(T(T)) {} - const int bar5(int); - void t5() { foo5(bar5); } - // expected-error@-1 {{no matching function for call to 'foo5'}} - // expected-note@-4 {{candidate template ignored: deduced conflicting types for parameter 'T' ('const int' vs. 'int')}} - - struct Foo6 {}; - template void foo6(void(*)(struct Foo6, T)) {} - void bar6(Foo6, int); - void t6() { foo6(bar6); } -} #else // expected-no-diagnostics diff --git a/clang/test/SemaCXX/cxx1z-decomposition.cpp b/clang/test/SemaCXX/cxx1z-decomposition.cpp index 4c8c64177ed1..f97c5b033e9c 100644 --- a/clang/test/SemaCXX/cxx1z-decomposition.cpp +++ b/clang/test/SemaCXX/cxx1z-decomposition.cpp @@ -9,7 +9,7 @@ void num_elems() { int a1[1], a2[2]; auto [] = a0; // expected-warning {{does not allow a decomposition group to be empty}} - auto [v1] = a0; // expected-error {{type 'struct A0' decomposes into 0 elements, but 1 name was provided}} + auto [v1] = a0; // expected-error {{type '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 enclosing() { void bitfield() { struct { int a : 3, : 4, b : 5; } a; auto &[x, y] = a; - auto &[p, q, r] = a; // expected-error-re {{type 'struct (unnamed struct at {{.*}})' decomposes into 2 elements, but 3 names were provided}} + auto &[p, q, r] = a; // expected-error-re {{type '(unnamed struct at {{.*}})' decomposes into 2 elements, but 3 names were provided}} } void for_range() { diff --git a/clang/test/SemaCXX/deduced-return-type-cxx14.cpp b/clang/test/SemaCXX/deduced-return-type-cxx14.cpp index da2f5f54b247..030a329697ef 100644 --- a/clang/test/SemaCXX/deduced-return-type-cxx14.cpp +++ b/clang/test/SemaCXX/deduced-return-type-cxx14.cpp @@ -300,7 +300,7 @@ namespace Constexpr { } 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 'struct NonLiteral' is not a literal type}} + constexpr auto f2(int n) { return nl; } // expected-error {{return type 'Constexpr::NonLiteral' is not a literal type}} } // It's not really clear whether these are valid, but this matches g++. diff --git a/clang/test/SemaCXX/friend.cpp b/clang/test/SemaCXX/friend.cpp index 367d6a6c1807..822b1de39a1e 100644 --- a/clang/test/SemaCXX/friend.cpp +++ b/clang/test/SemaCXX/friend.cpp @@ -415,7 +415,7 @@ namespace PR33222 { namespace qualified_friend_no_match { void f(int); // expected-note {{type mismatch at 1st parameter}} - template void f(T*); // expected-note {{could not match 'T *' against 'double'}} + template void f(T*); // expected-note {{could not match 'type-parameter-0-0 *' 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 @@ namespace qualified_friend_no_match { struct Y { void f(int); // expected-note {{type mismatch at 1st parameter}} - template void f(T*); // expected-note {{could not match 'T *' against 'double'}} + template void f(T*); // expected-note {{could not match 'type-parameter-0-0 *' 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'}} diff --git a/clang/test/SemaCXX/recovery-expr-type.cpp b/clang/test/SemaCXX/recovery-expr-type.cpp index 94b275c9a362..2fdbd0d3b6c3 100644 --- a/clang/test/SemaCXX/recovery-expr-type.cpp +++ b/clang/test/SemaCXX/recovery-expr-type.cpp @@ -133,7 +133,7 @@ struct S { // expected-note {{candidate}} template S(T t) -> S; void baz() { - bar(S(123)); // expected-error {{no matching conversion for functional-style cast from 'int' to 'S'}} + bar(S(123)); // expected-error {{no matching conversion for functional-style cast from 'int' to 'test11::S<>'}} } } // namespace test11 diff --git a/clang/test/SemaCXX/sizeless-1.cpp b/clang/test/SemaCXX/sizeless-1.cpp index 026c610a60e1..ee3ef51435d5 100644 --- a/clang/test/SemaCXX/sizeless-1.cpp +++ b/clang/test/SemaCXX/sizeless-1.cpp @@ -581,7 +581,7 @@ void cxx_only(int sel) { 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' (aka '__SVInt8_t')}} + auto [auto_int8_a] = local_int8; // expected-error {{cannot decompose non-class, non-array type '__SVInt8_t'}} #endif #endif @@ -600,7 +600,7 @@ void cxx_only(int sel) { 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' (aka '__SVInt8_t')}} + auto fn3 = [a(return_int8())] {}; // expected-error {{field has sizeless type '__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'}} diff --git a/clang/test/SemaCXX/sugared-auto.cpp b/clang/test/SemaCXX/sugared-auto.cpp deleted file mode 100644 index d63b0bccb2ed..000000000000 --- a/clang/test/SemaCXX/sugared-auto.cpp +++ /dev/null @@ -1,43 +0,0 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++20 - -enum class N {}; - -using Animal = int; - -using AnimalPtr = Animal *; - -using Man = Animal; -using Dog = Animal; - -namespace variable { - -auto x1 = Animal(); -N t1 = x1; // expected-error {{lvalue of type 'Animal' (aka 'int')}} - -auto x2 = AnimalPtr(); -N t2 = x2; // expected-error {{lvalue of type 'AnimalPtr' (aka 'int *')}} - -auto *x3 = AnimalPtr(); -N t3 = x3; // expected-error {{lvalue of type 'Animal *' (aka 'int *')}} - -// Each variable deduces separately. -auto x4 = Man(), x5 = Dog(); -N t4 = x4; // expected-error {{lvalue of type 'Man' (aka 'int')}} -N t5 = x5; // expected-error {{lvalue of type 'Dog' (aka 'int')}} - -} // namespace variable - -namespace function_basic { - -auto f1() { return Animal(); } -auto x1 = f1(); -N t1 = x1; // expected-error {{lvalue of type 'Animal' (aka 'int')}} - -decltype(auto) f2() { return Animal(); } -auto x2 = f2(); -N t2 = x2; // expected-error {{lvalue of type 'Animal' (aka 'int')}} - -auto x3 = [a = Animal()] { return a; }(); -N t3 = x3; // expected-error {{lvalue of type 'Animal' (aka 'int')}} - -} // namespace function_basic diff --git a/clang/test/SemaTemplate/attributes.cpp b/clang/test/SemaTemplate/attributes.cpp index b34794968ae8..b0bcca566dd9 100644 --- a/clang/test/SemaTemplate/attributes.cpp +++ b/clang/test/SemaTemplate/attributes.cpp @@ -124,8 +124,7 @@ namespace preferred_name { struct [[clang::preferred_name(iterator), clang::preferred_name(const_iterator)]] Iter {}; }; - template T desugar(T); - auto it = desugar(MemberTemplate::Iter()); + auto it = MemberTemplate::Iter(); int n = it; // expected-error {{no viable conversion from 'preferred_name::MemberTemplate::const_iterator' to 'int'}} template struct Foo; diff --git a/clang/test/SemaTemplate/friend.cpp b/clang/test/SemaTemplate/friend.cpp index 1427db093ec9..fc6cd42a3ba2 100644 --- a/clang/test/SemaTemplate/friend.cpp +++ b/clang/test/SemaTemplate/friend.cpp @@ -50,7 +50,7 @@ C c; namespace qualified_friend { void f(int); // expected-note 2{{type mismatch at 1st parameter}} - template void f(T*); // expected-note 2{{could not match 'T *' against 'double'}} + template void f(T*); // expected-note 2{{could not match 'type-parameter-0-0 *' against 'double'}} template void nondep(); template struct X1 { @@ -66,7 +66,7 @@ namespace qualified_friend { struct Y { void f(int); // expected-note 2{{type mismatch at 1st parameter}} - template void f(T*); // expected-note 2{{could not match 'T *' against 'double'}} + template void f(T*); // expected-note 2{{could not match 'type-parameter-0-0 *' against 'double'}} template void nondep(); }; diff --git a/clang/test/SemaTemplate/operator-template.cpp b/clang/test/SemaTemplate/operator-template.cpp index cf604691b943..e60216ff9631 100644 --- a/clang/test/SemaTemplate/operator-template.cpp +++ b/clang/test/SemaTemplate/operator-template.cpp @@ -2,7 +2,7 @@ // Make sure we accept this templatestruct A{typedef X Y;}; -templatebool operator==(A,typename A::Y); // expected-note{{candidate template ignored: could not match 'A' against 'B *'}} +templatebool operator==(A,typename A::Y); // expected-note{{candidate template ignored: could not match 'A' against 'B *'}} int a(A x) { return operator==(x,1); }