diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.cpp --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.cpp +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.cpp @@ -134,14 +134,9 @@ // Matching on initialization operations where the initial value is a newly // created owner, but the LHS is not an owner. Finder->addMatcher( - traverse( - TK_AsIs, - namedDecl( - varDecl(eachOf(allOf(hasInitializer(CreatesOwner), - unless(IsOwnerType)), - allOf(hasInitializer(ConsideredOwner), - hasType(autoType().bind("deduced_type"))))) - .bind("bad_owner_creation_variable"))), + traverse(TK_AsIs, namedDecl(varDecl(allOf(hasInitializer(CreatesOwner), + unless(IsOwnerType))) + .bind("bad_owner_creation_variable"))), this); // Match on all function calls that expect owners as arguments, but didn't @@ -324,13 +319,6 @@ // FIXME: FixitHint to rewrite the type of the initialized variable // as 'gsl::owner' - - // 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 --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.cpp +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsPointerArithmeticCheck.cpp @@ -20,9 +20,11 @@ if (!getLangOpts().CPlusPlus) return; - const auto AllPointerTypes = anyOf( - hasType(pointerType()), hasType(autoType(hasDeducedType(pointerType()))), - hasType(decltypeType(hasUnderlyingType(pointerType())))); + const auto AllPointerTypes = + anyOf(hasType(pointerType()), + hasType(autoType( + hasDeducedType(hasUnqualifiedDesugaredType(pointerType())))), + hasType(decltypeType(hasUnderlyingType(pointerType())))); // Flag all operators +, -, +=, -=, ++, -- that result in a pointer Finder->addMatcher( diff --git a/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp b/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp --- a/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp @@ -125,18 +125,22 @@ }; auto IsBoundToType = refersToType(equalsBoundNode("type")); + auto UnlessFunctionType = unless(hasUnqualifiedDesugaredType(functionType())); + auto IsAutoDeducedToPointer = [](const auto &...InnerMatchers) { + return autoType(hasDeducedType( + hasUnqualifiedDesugaredType(pointerType(pointee(InnerMatchers...))))); + }; Finder->addMatcher( - ExplicitSingleVarDecl(hasType(autoType(hasDeducedType( - pointerType(pointee(unless(functionType())))))), + ExplicitSingleVarDecl(hasType(IsAutoDeducedToPointer(UnlessFunctionType)), "auto"), this); Finder->addMatcher( ExplicitSingleVarDeclInTemplate( - allOf(hasType(autoType(hasDeducedType(pointerType( - pointee(hasUnqualifiedType(qualType().bind("type")), - unless(functionType())))))), + allOf(hasType(IsAutoDeducedToPointer( + hasUnqualifiedType(qualType().bind("type")), + UnlessFunctionType)), anyOf(hasAncestor( functionDecl(hasAnyTemplateArgument(IsBoundToType))), hasAncestor(classTemplateSpecializationDecl( diff --git a/clang-tools-extra/clangd/FindTarget.cpp b/clang-tools-extra/clangd/FindTarget.cpp --- a/clang-tools-extra/clangd/FindTarget.cpp +++ b/clang-tools-extra/clangd/FindTarget.cpp @@ -374,7 +374,7 @@ void VisitDeducedType(const DeducedType *DT) { // FIXME: In practice this doesn't work: the AutoType you find inside // TypeLoc never has a deduced type. https://llvm.org/PR42914 - Outer.add(DT->getDeducedType(), Flags | Rel::Underlying); + Outer.add(DT->getDeducedType(), Flags); } void VisitDeducedTemplateSpecializationType( const DeducedTemplateSpecializationType *DTST) { diff --git a/clang-tools-extra/clangd/InlayHints.cpp b/clang-tools-extra/clangd/InlayHints.cpp --- a/clang-tools-extra/clangd/InlayHints.cpp +++ b/clang-tools-extra/clangd/InlayHints.cpp @@ -38,10 +38,9 @@ // 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, 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. + // For "auto", we often prefer sugared types. + // Not setting PrintCanonicalTypes for "auto" 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 --- a/clang-tools-extra/clangd/unittests/ASTTests.cpp +++ b/clang-tools-extra/clangd/unittests/ASTTests.cpp @@ -43,7 +43,7 @@ namespace ns1 { struct S {}; } ^auto v = ns1::S{}; )cpp", - "struct ns1::S", + "ns1::S", }, { R"cpp( // decltype on struct @@ -63,7 +63,7 @@ ns1::S& j = i; ^decltype(auto) k = j; )cpp", - "struct ns1::S &", + "ns1::S &", }, { R"cpp( // auto on template class @@ -71,7 +71,7 @@ template class Foo {}; ^auto v = Foo(); )cpp", - "class Foo", + "Foo", }, { R"cpp( // auto on initializer list. @@ -177,8 +177,7 @@ using Bar = Foo; ^auto x = Bar(); )cpp", - // FIXME: it'd be nice if this resolved to the alias instead - "struct Foo", + "Bar", }, }; for (Test T : Tests) { diff --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp --- a/clang-tools-extra/clangd/unittests/HoverTests.cpp +++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp @@ -461,7 +461,7 @@ [](HoverInfo &HI) { HI.Name = "auto"; HI.Kind = index::SymbolKind::TypeAlias; - HI.Definition = "class Foo"; + HI.Definition = "Foo"; }}, // auto on specialized template {R"cpp( @@ -474,7 +474,7 @@ [](HoverInfo &HI) { HI.Name = "auto"; HI.Kind = index::SymbolKind::TypeAlias; - HI.Definition = "class Foo"; + HI.Definition = "Foo"; }}, // macro @@ -648,7 +648,7 @@ [](HoverInfo &HI) { HI.Name = "auto"; HI.Kind = index::SymbolKind::TypeAlias; - HI.Definition = "class Foo"; + HI.Definition = "Foo"; }}, {// Falls back to primary template, when the type is not instantiated. R"cpp( @@ -2024,7 +2024,7 @@ [](HoverInfo &HI) { HI.Name = "auto"; HI.Kind = index::SymbolKind::TypeAlias; - HI.Definition = "int"; + HI.Definition = "int_type"; }}, { R"cpp(// auto on alias @@ -2035,7 +2035,7 @@ [](HoverInfo &HI) { HI.Name = "auto"; HI.Kind = index::SymbolKind::TypeAlias; - HI.Definition = "struct cls"; + HI.Definition = "cls_type"; HI.Documentation = "auto on alias"; }}, { @@ -2047,7 +2047,7 @@ [](HoverInfo &HI) { HI.Name = "auto"; HI.Kind = index::SymbolKind::TypeAlias; - HI.Definition = "struct templ"; + HI.Definition = "templ"; HI.Documentation = "auto on alias"; }}, { diff --git a/clang-tools-extra/clangd/unittests/InlayHintTests.cpp b/clang-tools-extra/clangd/unittests/InlayHintTests.cpp --- a/clang-tools-extra/clangd/unittests/InlayHintTests.cpp +++ b/clang-tools-extra/clangd/unittests/InlayHintTests.cpp @@ -466,7 +466,14 @@ } } )cpp", - ExpectedHint{": S1", "x"}, ExpectedHint{": Inner", "y"}); + 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"}); } TEST(TypeHints, Lambda) { diff --git a/clang-tools-extra/clangd/unittests/tweaks/ExpandAutoTypeTests.cpp b/clang-tools-extra/clangd/unittests/tweaks/ExpandAutoTypeTests.cpp --- a/clang-tools-extra/clangd/unittests/tweaks/ExpandAutoTypeTests.cpp +++ b/clang-tools-extra/clangd/unittests/tweaks/ExpandAutoTypeTests.cpp @@ -57,7 +57,7 @@ EXPECT_UNAVAILABLE("au^to x = []{};"); // inline namespaces EXPECT_EQ(apply("au^to x = inl_ns::Visible();"), - "Visible x = inl_ns::Visible();"); + "inl_ns::Visible x = inl_ns::Visible();"); // local class EXPECT_EQ(apply("namespace x { void y() { struct S{}; ^auto z = S(); } }"), "namespace x { void y() { struct S{}; S z = S(); } }"); @@ -67,8 +67,9 @@ EXPECT_EQ(apply("ns::Class * foo() { au^to c = foo(); }"), "ns::Class * foo() { ns::Class * c = foo(); }"); - EXPECT_EQ(apply("void ns::Func() { au^to x = new ns::Class::Nested{}; }"), - "void ns::Func() { Class::Nested * x = new ns::Class::Nested{}; }"); + EXPECT_EQ( + apply("void ns::Func() { au^to x = new ns::Class::Nested{}; }"), + "void ns::Func() { ns::Class::Nested * x = new ns::Class::Nested{}; }"); EXPECT_UNAVAILABLE("dec^ltype(au^to) x = 10;"); // expanding types in structured bindings is syntactically invalid. 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 --- 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,13 +91,9 @@ // FIXME:, flow analysis for the case of reassignment. Value must be released before owned_int6 = owned_int3; // BAD, because reassignment without resource release - auto owned_int7 = returns_owner1(); // Bad, since type deduction eliminates the owner wrapper - // CHECK-NOTES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>' - // CHECK-NOTES: [[@LINE-2]]:3: note: type deduction did not result in an owner + auto owned_int7 = returns_owner1(); // Ok, since type deduction does not eliminate the owner wrapper - const auto owned_int8 = returns_owner2(); // Bad, since type deduction eliminates the owner wrapper - // CHECK-NOTES: [[@LINE-1]]:3: warning: initializing non-owner 'int *const' with a newly created 'gsl::owner<>' - // CHECK-NOTES: [[@LINE-2]]:3: note: type deduction did not result in an owner + const auto owned_int8 = returns_owner2(); // Ok, since type deduction does not eliminate the owner wrapper gsl::owner owned_int9 = returns_owner1(); // Ok int *unowned_int3 = returns_owner1(); // Bad @@ -285,15 +281,12 @@ ClassWithOwner C2{A}; // Bad, since the owner would be initialized with an non-owner, but catched in the class ClassWithOwner C3{gsl::owner(new ArbitraryClass)}; // Ok - const auto Owner1 = C3.buggy_but_returns_owner(); // BAD, deduces Owner1 to ArbitraryClass *const - // CHECK-NOTES: [[@LINE-1]]:3: warning: initializing non-owner 'ArbitraryClass *const' with a newly created 'gsl::owner<>' - // CHECK-NOTES: [[@LINE-2]]:3: note: type deduction did not result in an owner + const auto Owner1 = C3.buggy_but_returns_owner(); // Ok, deduces Owner1 to owner const - auto Owner2 = C2.buggy_but_returns_owner(); // BAD, deduces Owner2 to ArbitraryClass * - // CHECK-NOTES: [[@LINE-1]]:3: warning: initializing non-owner 'ArbitraryClass *' with a newly created 'gsl::owner<>' - // CHECK-NOTES: [[@LINE-2]]:3: note: type deduction did not result in an owner + auto Owner2 = C2.buggy_but_returns_owner(); //Ok, deduces Owner2 to owner - Owner2 = &A; // Ok, since type deduction did NOT result in 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 *' 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 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -1525,6 +1525,12 @@ 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 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -4944,29 +4944,31 @@ /// type-dependent, there is no deduced type and the type is canonical. In /// the latter case, it is also a dependent type. class DeducedType : public Type { + QualType DeducedAsType; + protected: DeducedType(TypeClass TC, QualType DeducedAsType, - TypeDependence ExtraDependence) - : Type(TC, - // FIXME: Retain the sugared deduced type? - DeducedAsType.isNull() ? QualType(this, 0) - : DeducedAsType.getCanonicalType(), + TypeDependence ExtraDependence, QualType Canon) + : Type(TC, Canon, ExtraDependence | (DeducedAsType.isNull() ? TypeDependence::None : DeducedAsType->getDependence() & - ~TypeDependence::VariablyModified)) {} + ~TypeDependence::VariablyModified)), + DeducedAsType(DeducedAsType) {} public: - bool isSugared() const { return !isCanonicalUnqualified(); } - QualType desugar() const { return getCanonicalTypeInternal(); } + bool isSugared() const { return !DeducedAsType.isNull(); } + QualType desugar() const { + return isSugared() ? DeducedAsType : QualType(this, 0); + } /// Get the type deduced for this placeholder type, or null if it's /// either not been deduced or was deduced to a dependent type. QualType getDeducedType() const { - return !isCanonicalUnqualified() ? getCanonicalTypeInternal() : QualType(); + return DeducedAsType.isNull() ? QualType() : DeducedAsType; } bool isDeduced() const { - return !isCanonicalUnqualified() || isDependentType(); + return !DeducedAsType.isNull() || isDependentType(); } static bool classof(const Type *T) { @@ -4983,7 +4985,7 @@ ConceptDecl *TypeConstraintConcept; AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword, - TypeDependence ExtraDependence, ConceptDecl *CD, + TypeDependence ExtraDependence, QualType Canon, ConceptDecl *CD, ArrayRef TypeConstraintArgs); const TemplateArgument *getArgBuffer() const { @@ -5057,7 +5059,9 @@ toTypeDependence(Template.getDependence()) | (IsDeducedAsDependent ? TypeDependence::DependentInstantiation - : TypeDependence::None)), + : TypeDependence::None), + DeducedAsType.isNull() ? QualType(this, 0) + : DeducedAsType.getCanonicalType()), Template(Template) {} public: diff --git a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h --- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h +++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -1028,31 +1028,29 @@ 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)) { - EffectiveType = S->getDeducedType().getTypePtrOrNull(); - if (!EffectiveType) - return false; + QualType DT = S->getDeducedType(); + return !DT.isNull() ? matchesSpecialized(*DT, Finder, Builder) : false; } // First, for any types that have a declaration, extract the declaration and // match on it. - if (const auto *S = dyn_cast(EffectiveType)) { + if (const auto *S = dyn_cast(&Node)) { return matchesDecl(S->getDecl(), Finder, Builder); } - if (const auto *S = dyn_cast(EffectiveType)) { + if (const auto *S = dyn_cast(&Node)) { return matchesDecl(S->getDecl(), Finder, Builder); } - if (const auto *S = dyn_cast(EffectiveType)) { + if (const auto *S = dyn_cast(&Node)) { return matchesDecl(S->getDecl(), Finder, Builder); } - if (const auto *S = dyn_cast(EffectiveType)) { + if (const auto *S = dyn_cast(&Node)) { return matchesDecl(S->getDecl(), Finder, Builder); } - if (const auto *S = dyn_cast(EffectiveType)) { + if (const auto *S = dyn_cast(&Node)) { return matchesDecl(S->getDecl(), Finder, Builder); } - if (const auto *S = dyn_cast(EffectiveType)) { + if (const auto *S = dyn_cast(&Node)) { return matchesDecl(S->getInterface(), Finder, Builder); } @@ -1064,14 +1062,14 @@ // 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(EffectiveType)) { + if (const auto *S = dyn_cast(&Node)) { 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(EffectiveType)) { + if (const auto *S = dyn_cast(&Node)) { if (!S->isTypeAlias() && S->isSugared()) { // If the template is non-dependent, we want to match the instantiated // tag type. @@ -1090,7 +1088,7 @@ // 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(EffectiveType)) { + if (const auto *S = dyn_cast(&Node)) { return matchesSpecialized(S->desugar(), Finder, Builder); } return false; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -2355,11 +2355,13 @@ const CXXScopeSpec &SS, QualType T, TagDecl *OwnedTagDecl = nullptr); - QualType BuildTypeofExprType(Expr *E, SourceLocation Loc); + // Returns the underlying type of a decltype with the given expression. + QualType getDecltypeForExpr(Expr *E); + + QualType BuildTypeofExprType(Expr *E); /// If AsUnevaluated is false, E is treated as though it were an evaluated /// context, such as when building a type for decltype(auto). - QualType BuildDecltypeType(Expr *E, SourceLocation Loc, - bool AsUnevaluated = true); + QualType BuildDecltypeType(Expr *E, bool AsUnevaluated = true); QualType BuildUnaryTransformType(QualType BaseType, UnaryTransformType::UTTKind UKind, SourceLocation Loc); @@ -3498,7 +3500,7 @@ bool IsFunctionConversion(QualType FromType, QualType ToType, QualType &ResultTy); bool DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType); - bool isSameOrCompatibleFunctionType(CanQualType Param, CanQualType Arg); + bool isSameOrCompatibleFunctionType(QualType Param, QualType Arg); bool CanPerformAggregateInitializationForOverloadResolution( const InitializedEntity &Entity, InitListExpr *From); @@ -8560,6 +8562,14 @@ /// Substitute Replacement for auto in TypeWithAuto TypeSourceInfo* SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto, QualType Replacement); + + // Substitute auto in TypeWithAuto for a Dependent auto type + QualType SubstAutoTypeDependent(QualType TypeWithAuto); + + // Substitute auto in TypeWithAuto for a Dependent auto type + TypeSourceInfo * + SubstAutoTypeSourceInfoDependent(TypeSourceInfo *TypeWithAuto); + /// Completely replace the \c auto in \p TypeWithAuto by /// \p Replacement. This does not retain any \c auto type sugar. QualType ReplaceAutoType(QualType TypeWithAuto, QualType Replacement); diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -4808,6 +4808,23 @@ 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() && @@ -4820,10 +4837,7 @@ // Build the canonical template specialization type. TemplateName CanonTemplate = getCanonicalTemplateName(Template); SmallVector CanonArgs; - unsigned NumArgs = Args.size(); - CanonArgs.reserve(NumArgs); - for (const TemplateArgument &Arg : Args) - CanonArgs.push_back(getCanonicalTemplateArgument(Arg)); + ::getCanonicalTemplateArguments(*this, Args, CanonArgs); // Determine whether this canonical template specialization type already // exists. @@ -4838,7 +4852,7 @@ if (!Spec) { // Allocate a new canonical template specialization type. void *Mem = Allocate((sizeof(TemplateSpecializationType) + - sizeof(TemplateArgument) * NumArgs), + sizeof(TemplateArgument) * CanonArgs.size()), TypeAlignment); Spec = new (Mem) TemplateSpecializationType(CanonTemplate, CanonArgs, @@ -4980,14 +4994,9 @@ ElaboratedTypeKeyword CanonKeyword = Keyword; if (Keyword == ETK_None) CanonKeyword = ETK_Typename; - 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; - } + SmallVector CanonArgs; + bool AnyNonCanonArgs = + ::getCanonicalTemplateArguments(*this, Args, CanonArgs); QualType Canon; if (AnyNonCanonArgs || CanonNNS != NNS || CanonKeyword != Keyword) { @@ -5000,7 +5009,7 @@ } void *Mem = Allocate((sizeof(DependentTemplateSpecializationType) + - sizeof(TemplateArgument) * NumArgs), + sizeof(TemplateArgument) * Args.size()), TypeAlignment); T = new (Mem) DependentTemplateSpecializationType(Keyword, NNS, Name, Args, Canon); @@ -5585,15 +5594,10 @@ return QualType(ut, 0); } -/// getAutoType - Return the uniqued reference to the 'auto' type which has been -/// deduced to the given type, or to the canonical undeduced 'auto' type, or the -/// canonical deduced-but-dependent 'auto' type. -QualType -ASTContext::getAutoType(QualType DeducedType, AutoTypeKeyword Keyword, - bool IsDependent, bool IsPack, - ConceptDecl *TypeConstraintConcept, - ArrayRef TypeConstraintArgs) const { - assert((!IsPack || IsDependent) && "only use IsPack for a dependent pack"); +QualType ASTContext::getAutoTypeInternal( + QualType DeducedType, AutoTypeKeyword Keyword, bool IsDependent, + bool IsPack, ConceptDecl *TypeConstraintConcept, + ArrayRef TypeConstraintArgs, bool IsCanon) const { if (DeducedType.isNull() && Keyword == AutoTypeKeyword::Auto && !TypeConstraintConcept && !IsDependent) return getAutoDeductType(); @@ -5606,21 +5610,52 @@ 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), - TypeConstraintConcept, TypeConstraintArgs); + Canon, TypeConstraintConcept, TypeConstraintArgs); Types.push_back(AT); - if (InsertPos) - AutoTypes.InsertNode(AT, InsertPos); + AutoTypes.InsertNode(AT, InsertPos); return QualType(AT, 0); } +/// getAutoType - Return the uniqued reference to the 'auto' type which has been +/// deduced to the given type, or to the canonical undeduced 'auto' type, or the +/// canonical deduced-but-dependent 'auto' type. +QualType +ASTContext::getAutoType(QualType DeducedType, AutoTypeKeyword Keyword, + bool IsDependent, bool IsPack, + ConceptDecl *TypeConstraintConcept, + ArrayRef 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. @@ -5638,8 +5673,7 @@ auto *DTST = new (*this, TypeAlignment) DeducedTemplateSpecializationType(Template, DeducedType, IsDependent); Types.push_back(DTST); - if (InsertPos) - DeducedTemplateSpecializationTypes.InsertNode(DTST, InsertPos); + DeducedTemplateSpecializationTypes.InsertNode(DTST, InsertPos); return QualType(DTST, 0); } @@ -5676,7 +5710,7 @@ if (AutoDeductTy.isNull()) AutoDeductTy = QualType(new (*this, TypeAlignment) AutoType(QualType(), AutoTypeKeyword::Auto, - TypeDependence::None, + TypeDependence::None, QualType(), /*concept*/ nullptr, /*args*/ {}), 0); return AutoDeductTy; diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -3265,13 +3265,16 @@ bool ASTNodeImporter::hasAutoReturnTypeDeclaredInside(FunctionDecl *D) { QualType FromTy = D->getType(); - const FunctionProtoType *FromFPT = FromTy->getAs(); + const auto *FromFPT = FromTy->getAs(); assert(FromFPT && "Must be called on FunctionProtoType"); - if (AutoType *AutoT = FromFPT->getReturnType()->getContainedAutoType()) { + if (const AutoType *AutoT = + FromFPT->getReturnType()->getContainedAutoType()) { QualType DeducedT = AutoT->getDeducedType(); - if (const RecordType *RecordT = - DeducedT.isNull() ? nullptr : dyn_cast(DeducedT)) { - RecordDecl *RD = RecordT->getDecl(); + if (const auto *RecordT = + !DeducedT.isNull() + ? dyn_cast(DeducedT->getCanonicalTypeInternal()) + : nullptr) { + const RecordDecl *RD = RecordT->getDecl(); assert(RD); if (isAncestorDeclContextOf(D, RD)) { assert(RD->getLexicalDeclContext() == RD->getDeclContext()); @@ -3279,9 +3282,8 @@ } } } - if (const TypedefType *TypedefT = - dyn_cast(FromFPT->getReturnType())) { - TypedefNameDecl *TD = TypedefT->getDecl(); + if (const auto *TypedefT = dyn_cast(FromFPT->getReturnType())) { + const 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 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -4394,10 +4394,10 @@ } AutoType::AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword, - TypeDependence ExtraDependence, + TypeDependence ExtraDependence, QualType Canon, ConceptDecl *TypeConstraintConcept, ArrayRef TypeConstraintArgs) - : DeducedType(Auto, DeducedAsType, ExtraDependence) { + : DeducedType(Auto, DeducedAsType, ExtraDependence, Canon) { 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 --- a/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -865,7 +865,7 @@ assert(DS.getTypeSpecType() == DeclSpec::TST_decltype); - QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc()); + QualType T = BuildDecltypeType(DS.getRepAsExpr()); if (T.isNull()) return true; diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -3607,14 +3607,14 @@ // defined, copy the deduced value from the old declaration. AutoType *OldAT = Old->getReturnType()->getContainedAutoType(); if (OldAT && OldAT->isDeduced()) { - New->setType( - SubstAutoType(New->getType(), - OldAT->isDependentType() ? Context.DependentTy - : OldAT->getDeducedType())); - NewQType = Context.getCanonicalType( - SubstAutoType(NewQType, - OldAT->isDependentType() ? Context.DependentTy - : OldAT->getDeducedType())); + QualType DT = OldAT->getDeducedType(); + if (DT.isNull()) { + New->setType(SubstAutoTypeDependent(New->getType())); + NewQType = Context.getCanonicalType(SubstAutoTypeDependent(NewQType)); + } else { + New->setType(SubstAutoType(New->getType(), DT)); + NewQType = Context.getCanonicalType(SubstAutoType(NewQType, DT)); + } } } @@ -9251,8 +9251,7 @@ // a friend yet, so 'isDependentContext' on the FD doesn't work. const FunctionProtoType *FPT = NewFD->getType()->castAs(); - QualType Result = - SubstAutoType(FPT->getReturnType(), Context.DependentTy); + QualType Result = SubstAutoTypeDependent(FPT->getReturnType()); NewFD->setType(Context.getFunctionType(Result, FPT->getParamTypes(), FPT->getExtProtoInfo())); } @@ -12346,7 +12345,7 @@ /*TreatUnavailableAsInvalid=*/false); ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Args, &DclT); if (Result.isInvalid()) { - // If the provied initializer fails to initialize the var decl, + // If the provided initializer fails to initialize the var decl, // we attach a recovery expr for better recovery. auto RecoveryExpr = CreateRecoveryExpr(Init->getBeginLoc(), Init->getEndLoc(), Args); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -4217,7 +4217,7 @@ if (BaseType.isNull()) return true; } else if (DS.getTypeSpecType() == TST_decltype) { - BaseType = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc()); + BaseType = BuildDecltypeType(DS.getRepAsExpr()); } else if (DS.getTypeSpecType() == TST_decltype_auto) { Diag(DS.getTypeSpecTypeLoc(), diag::err_decltype_auto_invalid); return true; diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -468,7 +468,7 @@ assert(DS.getTypeSpecType() == DeclSpec::TST_decltype && "unexpected type in getDestructorType"); - QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc()); + QualType T = BuildDecltypeType(DS.getRepAsExpr()); // If we know the type of the object, check that the correct destructor // type was named now; we can give better diagnostics this way. @@ -7734,8 +7734,7 @@ return true; } - QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc(), - false); + QualType T = BuildDecltypeType(DS.getRepAsExpr(), /*AsUnevaluated=*/false); TypeLocBuilder TLB; DecltypeTypeLoc DecltypeTL = TLB.push(T); diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -9972,7 +9972,7 @@ auto TemplateName = DeducedTST->getTemplateName(); if (TemplateName.isDependent()) - return SubstAutoType(TSInfo->getType(), Context.DependentTy); + return SubstAutoTypeDependent(TSInfo->getType()); // We can only perform deduction for class templates. auto *Template = @@ -9991,7 +9991,7 @@ Diag(TSInfo->getTypeLoc().getBeginLoc(), diag::warn_cxx14_compat_class_template_argument_deduction) << TSInfo->getTypeLoc().getSourceRange() << 0; - return SubstAutoType(TSInfo->getType(), Context.DependentTy); + return SubstAutoTypeDependent(TSInfo->getType()); } // FIXME: Perform "exact type" matching first, per CWG discussion? diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -373,7 +373,7 @@ const FunctionProtoType *FPT = MethodType->castAs(); QualType Result = FPT->getReturnType(); if (Result->isUndeducedType()) { - Result = SubstAutoType(Result, Context.DependentTy); + Result = SubstAutoTypeDependent(Result); MethodType = Context.getFunctionType(Result, FPT->getParamTypes(), FPT->getExtProtoInfo()); } diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -2759,7 +2759,7 @@ if (auto *DD = dyn_cast(LoopVar)) for (auto *Binding : DD->bindings()) Binding->setType(Context.DependentTy); - LoopVar->setType(SubstAutoType(LoopVar->getType(), Context.DependentTy)); + LoopVar->setType(SubstAutoTypeDependent(LoopVar->getType())); } } else if (!BeginDeclStmt.get()) { SourceLocation RangeLoc = RangeVar->getLocation(); diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1260,15 +1260,15 @@ BuildDeclRefExpr(NTTP, NTTP->getType(), VK_PRValue, NTTP->getLocation()); if (!Ref) return true; - ExprResult ImmediatelyDeclaredConstraint = - formImmediatelyDeclaredConstraint( - *this, TL.getNestedNameSpecifierLoc(), TL.getConceptNameInfo(), - TL.getNamedConcept(), TL.getLAngleLoc(), TL.getRAngleLoc(), - BuildDecltypeType(Ref, NTTP->getLocation()), NTTP->getLocation(), - [&] (TemplateArgumentListInfo &ConstraintArgs) { - for (unsigned I = 0, C = TL.getNumArgs(); I != C; ++I) - ConstraintArgs.addArgument(TL.getArgLoc(I)); - }, EllipsisLoc); + ExprResult ImmediatelyDeclaredConstraint = formImmediatelyDeclaredConstraint( + *this, TL.getNestedNameSpecifierLoc(), TL.getConceptNameInfo(), + TL.getNamedConcept(), TL.getLAngleLoc(), TL.getRAngleLoc(), + BuildDecltypeType(Ref), NTTP->getLocation(), + [&](TemplateArgumentListInfo &ConstraintArgs) { + for (unsigned I = 0, C = TL.getNumArgs(); I != C; ++I) + ConstraintArgs.addArgument(TL.getArgLoc(I)); + }, + EllipsisLoc); if (ImmediatelyDeclaredConstraint.isInvalid() || !ImmediatelyDeclaredConstraint.isUsable()) return true; @@ -1290,7 +1290,7 @@ // - an identifier associated by name lookup with a non-type // template-parameter declared with a type that contains a // placeholder type (7.1.7.4), - TSI = SubstAutoTypeSourceInfo(TSI, Context.DependentTy); + TSI = SubstAutoTypeSourceInfoDependent(TSI); } return CheckNonTypeTemplateParameterType(TSI->getType(), Loc); @@ -10874,7 +10874,7 @@ // - an identifier associated by name lookup with a non-type // template-parameter declared with a type that contains a // placeholder type (7.1.7.4), - NewTSI = SubstAutoTypeSourceInfo(NewTSI, Context.DependentTy); + NewTSI = SubstAutoTypeSourceInfoDependent(NewTSI); } if (NewTSI != NTTP->getTypeSourceInfo()) { diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -131,30 +131,16 @@ return X == Y; } -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 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 Params, - ArrayRef Args, + ArrayRef Ps, + ArrayRef As, TemplateDeductionInfo &Info, SmallVectorImpl &Deduced, bool NumberOfArgumentsMustMatch); @@ -559,70 +545,69 @@ /// "success" result means that template argument deduction has not yet failed, /// but it may still fail, later, for other reasons. static Sema::TemplateDeductionResult -DeduceTemplateArguments(Sema &S, - TemplateParameterList *TemplateParams, - const TemplateSpecializationType *Param, - QualType Arg, - TemplateDeductionInfo &Info, - SmallVectorImpl &Deduced) { - assert(Arg.isCanonical() && "Argument type must be canonical"); - +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(); + const auto *TP = + UP->getUnqualifiedDesugaredType()->castAs(); + + // Get the resolved template arguments from the canonical type. + // FIXME: Handle the as-written arguments so the sugar is not lost. + ArrayRef PResolved = + TP->getCanonicalTypeInternal() + ->castAs() + ->template_arguments(); + + QualType UA = A; // Treat an injected-class-name as its underlying template-id. - if (auto *Injected = dyn_cast(Arg)) - Arg = Injected->getInjectedSpecializationType(); + if (const auto *Injected = A->getAs()) + UA = Injected->getInjectedSpecializationType(); // Check whether the template argument is a dependent template-id. - if (const TemplateSpecializationType *SpecArg - = dyn_cast(Arg)) { + if (UA->getCanonicalTypeInternal()->getTypeClass() == + Type::TemplateSpecialization) { + const auto *SA = + UA->getUnqualifiedDesugaredType()->castAs(); + // Perform template argument deduction for the template name. - if (Sema::TemplateDeductionResult Result - = DeduceTemplateArguments(S, TemplateParams, - Param->getTemplateName(), - SpecArg->getTemplateName(), - Info, Deduced)) + if (auto Result = + DeduceTemplateArguments(S, TemplateParams, TP->getTemplateName(), + SA->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, - Param->template_arguments(), - SpecArg->template_arguments(), Info, Deduced, + return DeduceTemplateArguments(S, TemplateParams, PResolved, + SA->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 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); + const auto *RA = UA->getAs(); + const auto *SA = + RA ? dyn_cast(RA->getDecl()) : nullptr; + if (!SA) { + Info.FirstArg = TemplateArgument(P); + Info.SecondArg = TemplateArgument(A); return Sema::TDK_NonDeducedMismatch; } // Perform template argument deduction for the template name. - if (Sema::TemplateDeductionResult Result - = DeduceTemplateArguments(S, - TemplateParams, - Param->getTemplateName(), - TemplateName(SpecArg->getSpecializedTemplate()), - Info, Deduced)) + if (auto Result = DeduceTemplateArguments( + S, TemplateParams, TP->getTemplateName(), + TemplateName(SA->getSpecializedTemplate()), Info, Deduced)) return Result; // Perform template argument deduction for the template arguments. - return DeduceTemplateArguments(S, TemplateParams, Param->template_arguments(), - SpecArg->getTemplateArgs().asArray(), Info, - Deduced, /*NumberOfArgumentsMustMatch=*/true); + return DeduceTemplateArguments(S, TemplateParams, PResolved, + SA->getTemplateArgs().asArray(), Info, Deduced, + /*NumberOfArgumentsMustMatch=*/true); } /// Determines whether the given type is an opaque type that @@ -1047,11 +1032,12 @@ return Sema::TDK_MiscellaneousDeductionFailure; } - if (Sema::TemplateDeductionResult Result - = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, - Params[ParamIdx], Args[ArgIdx], - Info, Deduced, TDF, - PartialOrdering)) + if (Sema::TemplateDeductionResult Result = + DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, Params[ParamIdx].getUnqualifiedType(), + Args[ArgIdx].getUnqualifiedType(), Info, Deduced, TDF, + PartialOrdering, + /*DeducedFromArrayBound=*/false)) return Result; ++ArgIdx; @@ -1073,10 +1059,11 @@ if (ParamIdx + 1 == NumParams || PackScope.hasFixedArity()) { for (; ArgIdx < NumArgs && PackScope.hasNextElement(); ++ArgIdx) { // Deduce template arguments from the pattern. - if (Sema::TemplateDeductionResult Result - = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, Pattern, - Args[ArgIdx], Info, Deduced, - TDF, PartialOrdering)) + if (Sema::TemplateDeductionResult Result = + DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, Pattern.getUnqualifiedType(), + Args[ArgIdx].getUnqualifiedType(), Info, Deduced, TDF, + PartialOrdering, /*DeducedFromArrayBound=*/false)) return Result; PackScope.nextPackElement(); @@ -1158,10 +1145,9 @@ /// \param Param the template parameter type. /// /// \param Arg the argument type. -bool Sema::isSameOrCompatibleFunctionType(CanQualType Param, - CanQualType Arg) { +bool Sema::isSameOrCompatibleFunctionType(QualType Param, QualType Arg) { const FunctionType *ParamFunction = Param->getAs(), - *ArgFunction = Arg->getAs(); + *ArgFunction = Arg->getAs(); // Just compare if not functions. if (!ParamFunction || !ArgFunction) @@ -1221,10 +1207,11 @@ /// \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 RecordType *RecordT, TemplateParameterList *TemplateParams, - const TemplateSpecializationType *SpecParam, TemplateDeductionInfo &Info, - SmallVectorImpl &Deduced) { +static Sema::TemplateDeductionResult +DeduceTemplateBases(Sema &S, const RecordType *RecordT, + TemplateParameterList *TemplateParams, QualType P, + 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 @@ -1273,9 +1260,8 @@ SmallVector DeducedCopy(Deduced.begin(), Deduced.end()); TemplateDeductionInfo BaseInfo(TemplateDeductionInfo::ForBase, Info); - Sema::TemplateDeductionResult BaseResult = - DeduceTemplateArguments(S, TemplateParams, SpecParam, - QualType(NextT, 0), BaseInfo, DeducedCopy); + Sema::TemplateDeductionResult BaseResult = DeduceTemplateSpecArguments( + S, TemplateParams, P, 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. @@ -1341,41 +1327,26 @@ /// \returns the result of template argument deduction so far. Note that a /// "success" result means that template argument deduction has not yet failed, /// but it may still fail, later, for other reasons. -static Sema::TemplateDeductionResult -DeduceTemplateArgumentsByTypeMatch(Sema &S, - TemplateParameterList *TemplateParams, - QualType ParamIn, QualType ArgIn, - TemplateDeductionInfo &Info, - SmallVectorImpl &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(); - +static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( + Sema &S, TemplateParameterList *TemplateParams, QualType P, QualType A, + TemplateDeductionInfo &Info, + SmallVectorImpl &Deduced, unsigned TDF, + bool PartialOrdering, bool DeducedFromArrayBound) { 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 *ParamRef = Param->getAs(); - if (ParamRef) - Param = ParamRef->getPointeeType(); + const ReferenceType *PRef = P->getAs(); + if (PRef) + P = PRef->getPointeeType(); // - If A is a reference type, A is replaced by the type referred to. - const ReferenceType *ArgRef = Arg->getAs(); - if (ArgRef) - Arg = ArgRef->getPointeeType(); + const ReferenceType *ARef = A->getAs(); + if (ARef) + A = A->getPointeeType(); - if (ParamRef && ArgRef && S.Context.hasSameUnqualifiedType(Param, Arg)) { + if (PRef && ARef && S.Context.hasSameUnqualifiedType(P, A)) { // 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 @@ -1395,17 +1366,14 @@ // 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 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); + 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); return Sema::TDK_NonDeducedMismatch; } } @@ -1414,10 +1382,10 @@ // Remove any top-level cv-qualifiers: // - If P is a cv-qualified type, P is replaced by the cv-unqualified // version of P. - Param = Param.getUnqualifiedType(); + P = P.getUnqualifiedType(); // - If A is a cv-qualified type, A is replaced by the cv-unqualified // version of A. - Arg = Arg.getUnqualifiedType(); + A = A.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 @@ -1425,13 +1393,12 @@ // transformed A. if (TDF & TDF_ParamWithReferenceType) { Qualifiers Quals; - QualType UnqualParam = S.Context.getUnqualifiedArrayType(Param, Quals); - Quals.setCVRQualifiers(Quals.getCVRQualifiers() & - Arg.getCVRQualifiers()); - Param = S.Context.getQualifiedType(UnqualParam, Quals); + QualType UnqualP = S.Context.getUnqualifiedArrayType(P, Quals); + Quals.setCVRQualifiers(Quals.getCVRQualifiers() & A.getCVRQualifiers()); + P = S.Context.getQualifiedType(UnqualP, Quals); } - if ((TDF & TDF_TopLevelParameterTypeList) && !Param->isFunctionType()) { + if ((TDF & TDF_TopLevelParameterTypeList) && !P->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 @@ -1444,8 +1411,9 @@ // Pi is T&& and Ai is X&, the adjusted Pi will be T, causing T to be // deduced as X&. - end note ] TDF &= ~TDF_TopLevelParameterTypeList; - if (isForwardingReference(Param, 0) && Arg->isLValueReferenceType()) - Param = Param->getPointeeType(); + if (isForwardingReference(P, /*FirstInnerIndex=*/0) && + A->isLValueReferenceType()) + P = P->getPointeeType(); } } @@ -1456,53 +1424,48 @@ // // T // cv-list T - if (const TemplateTypeParmType *TemplateTypeParm - = Param->getAs()) { + if (const auto *TTP = P->getAs()) { // Just skip any attempts to deduce from a placeholder type or a parameter // at a different depth. - if (Arg->isPlaceholderType() || - Info.getDeducedDepth() != TemplateTypeParm->getDepth()) + if (A->isPlaceholderType() || Info.getDeducedDepth() != TTP->getDepth()) return Sema::TDK_Success; - unsigned Index = TemplateTypeParm->getIndex(); - bool RecanonicalizeArg = false; + unsigned Index = TTP->getIndex(); // If the argument type is an array type, move the qualifiers up to the // top level, so they can be matched with the qualifiers on the parameter. - if (isa(Arg)) { + if (isa(A)) { Qualifiers Quals; - Arg = S.Context.getUnqualifiedArrayType(Arg, Quals); - if (Quals) { - Arg = S.Context.getQualifiedType(Arg, Quals); - RecanonicalizeArg = true; - } + A = S.Context.getUnqualifiedArrayType(A, Quals); + if (Quals) + A = S.Context.getQualifiedType(A, Quals); } // The argument type can not be less qualified than the parameter // type. if (!(TDF & TDF_IgnoreQualifiers) && - hasInconsistentOrSupersetQualifiersOf(Param, Arg)) { + hasInconsistentOrSupersetQualifiersOf(P, A)) { Info.Param = cast(TemplateParams->getParam(Index)); - Info.FirstArg = TemplateArgument(Param); - Info.SecondArg = TemplateArgument(Arg); + Info.FirstArg = TemplateArgument(P); + Info.SecondArg = TemplateArgument(A); 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 (Arg->isFunctionType() && Param.hasQualifiers()) { + if (A->isFunctionType() && P.hasQualifiers()) return Sema::TDK_NonDeducedMismatch; - } - assert(TemplateTypeParm->getDepth() == Info.getDeducedDepth() && + assert(TTP->getDepth() == Info.getDeducedDepth() && "saw template type parameter with wrong depth"); - assert(Arg != S.Context.OverloadTy && "Unresolved overloaded function"); - QualType DeducedType = Arg; + assert(A->getCanonicalTypeInternal() != S.Context.OverloadTy && + "Unresolved overloaded function"); + QualType DeducedType = A; // Remove any qualifiers on the parameter from the deduced type. // We checked the qualifiers for consistency above. Qualifiers DeducedQs = DeducedType.getQualifiers(); - Qualifiers ParamQs = Param.getQualifiers(); + Qualifiers ParamQs = P.getQualifiers(); DeducedQs.removeCVRQualifiers(ParamQs.getCVRQualifiers()); if (ParamQs.hasObjCGCAttr()) DeducedQs.removeObjCGCAttr(); @@ -1517,29 +1480,24 @@ if (ParamQs.hasObjCLifetime() && !DeducedType->isObjCLifetimeType() && !DeducedType->isDependentType()) { Info.Param = cast(TemplateParams->getParam(Index)); - Info.FirstArg = TemplateArgument(Param); - Info.SecondArg = TemplateArgument(Arg); + Info.FirstArg = TemplateArgument(P); + Info.SecondArg = TemplateArgument(A); 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); - - if (RecanonicalizeArg) - DeducedType = S.Context.getCanonicalType(DeducedType); + DeducedType = + S.Context.getQualifiedType(DeducedType.getUnqualifiedType(), DeducedQs); 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]; @@ -1552,69 +1510,62 @@ } // Set up the template argument deduction information for a failure. - Info.FirstArg = TemplateArgument(ParamIn); - Info.SecondArg = TemplateArgument(ArgIn); + Info.FirstArg = TemplateArgument(P); + Info.SecondArg = TemplateArgument(A); // If the parameter is an already-substituted template parameter // pack, do nothing: we don't know which of its arguments to look // at, so we have to wait until all of the parameter packs in this // expansion have arguments. - if (isa(Param)) + if (P->getAs()) 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(Param, Arg)) + if (hasInconsistentOrSupersetQualifiersOf(P, A)) 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 (!Arg.getQualifiers().compatiblyIncludes(Param.getQualifiers())) + if (!A.getQualifiers().compatiblyIncludes(P.getQualifiers())) return Sema::TDK_NonDeducedMismatch; // Strip out all extra qualifiers from the argument to figure out the // type we're converting to, prior to the qualification conversion. Qualifiers Quals; - Arg = S.Context.getUnqualifiedArrayType(Arg, Quals); - Arg = S.Context.getQualifiedType(Arg, Param.getQualifiers()); - } else if (!IsPossiblyOpaquelyQualifiedType(Param)) { - if (Param.getCVRQualifiers() != Arg.getCVRQualifiers()) + A = S.Context.getUnqualifiedArrayType(A, Quals); + A = S.Context.getQualifiedType(A, P.getQualifiers()); + } else if (!IsPossiblyOpaquelyQualifiedType(P)) { + if (P.getCVRQualifiers() != A.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; - } - } + QualType CanP = P.getCanonicalType(); + // If the parameter type is not dependent, there is nothing to deduce. + if (!P->isDependentType()) { + if (TDF & TDF_SkipNonDependent) return Sema::TDK_Success; + + QualType CanA = A.getCanonicalType(); + if (TDF & TDF_IgnoreQualifiers) { + CanP = CanP.getUnqualifiedType(); + CanA = CanA.getUnqualifiedType(); } - } 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 { + bool Success = (TDF & TDF_AllowCompatibleFunctionType) + ? S.isSameOrCompatibleFunctionType(CanP, CanA) + : CanP == CanA; + if (Success) return Sema::TDK_Success; - } + if (!(TDF & TDF_IgnoreQualifiers)) + return Sema::TDK_NonDeducedMismatch; + // We don't know how to compare the types in one step here, so + // keep digging down. } - switch (Param->getTypeClass()) { + switch (CanP->getTypeClass()) { // Non-canonical types cannot appear here. #define NON_CANONICAL_TYPE(Class, Base) \ case Type::Class: llvm_unreachable("deducing non-canonical type: " #Class); @@ -1625,8 +1576,11 @@ case Type::SubstTemplateTypeParmPack: llvm_unreachable("Type nodes handled above"); - // These types cannot be dependent, so simply check whether the types are - // the same. + case Type::Auto: + // FIXME: Implement deduction in dependent case. + if (P->isDependentType()) + return Sema::TDK_Success; + LLVM_FALLTHROUGH; case Type::Builtin: case Type::VariableArray: case Type::Vector: @@ -1637,134 +1591,115 @@ case Type::ObjCInterface: case Type::ObjCObjectPointer: case Type::ExtInt: - 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; + return (TDF & TDF_SkipNonDependent) || + ((TDF & TDF_IgnoreQualifiers) + ? S.Context.hasSameUnqualifiedType(P, A) + : S.Context.hasSameType(P, A)) + ? Sema::TDK_Success + : Sema::TDK_NonDeducedMismatch; // _Complex T [placeholder extension] - 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; + 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); + } // _Atomic T [extension] - 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; + 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); + } // T * case Type::Pointer: { QualType PointeeType; - if (const PointerType *PointerArg = Arg->getAs()) { - PointeeType = PointerArg->getPointeeType(); - } else if (const ObjCObjectPointerType *PointerArg - = Arg->getAs()) { - PointeeType = PointerArg->getPointeeType(); + if (const auto *PA = A->getAs()) { + PointeeType = PA->getPointeeType(); + } else if (const auto *PA = A->getAs()) { + PointeeType = PA->getPointeeType(); } else { return Sema::TDK_NonDeducedMismatch; } - - unsigned SubTDF = TDF & (TDF_IgnoreQualifiers | TDF_DerivedClass); - return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, - cast(Param)->getPointeeType(), - PointeeType, - Info, Deduced, SubTDF); + return DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, P->castAs()->getPointeeType(), + PointeeType, Info, Deduced, + TDF & (TDF_IgnoreQualifiers | TDF_DerivedClass)); } // T & case Type::LValueReference: { - const LValueReferenceType *ReferenceArg = - Arg->getAs(); - if (!ReferenceArg) + const auto *RP = P->castAs(), + *RA = A->getAs(); + if (!RA) return Sema::TDK_NonDeducedMismatch; - return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, - cast(Param)->getPointeeType(), - ReferenceArg->getPointeeType(), Info, Deduced, 0); + return DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, RP->getPointeeType(), RA->getPointeeType(), Info, + Deduced, 0); } // T && [C++0x] case Type::RValueReference: { - const RValueReferenceType *ReferenceArg = - Arg->getAs(); - if (!ReferenceArg) + const auto *RP = P->castAs(), + *RA = A->getAs(); + if (!RA) return Sema::TDK_NonDeducedMismatch; - return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, - cast(Param)->getPointeeType(), - ReferenceArg->getPointeeType(), - Info, Deduced, 0); + return DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, RP->getPointeeType(), RA->getPointeeType(), Info, + Deduced, 0); } // T [] (implied, but not stated explicitly) case Type::IncompleteArray: { - const IncompleteArrayType *IncompleteArrayArg = - S.Context.getAsIncompleteArrayType(Arg); - if (!IncompleteArrayArg) + const auto *IAA = S.Context.getAsIncompleteArrayType(A); + if (!IAA) return Sema::TDK_NonDeducedMismatch; - unsigned SubTDF = TDF & TDF_IgnoreQualifiers; - return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, - S.Context.getAsIncompleteArrayType(Param)->getElementType(), - IncompleteArrayArg->getElementType(), - Info, Deduced, SubTDF); + return DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, + S.Context.getAsIncompleteArrayType(P)->getElementType(), + IAA->getElementType(), Info, Deduced, TDF & TDF_IgnoreQualifiers); } // T [integer-constant] case Type::ConstantArray: { - const ConstantArrayType *ConstantArrayArg = - S.Context.getAsConstantArrayType(Arg); - if (!ConstantArrayArg) - return Sema::TDK_NonDeducedMismatch; - - const ConstantArrayType *ConstantArrayParm = - S.Context.getAsConstantArrayType(Param); - if (ConstantArrayArg->getSize() != ConstantArrayParm->getSize()) + const auto *CAA = S.Context.getAsConstantArrayType(A), + *CAP = S.Context.getAsConstantArrayType(P); + assert(CAP); + if (!CAA || CAA->getSize() != CAP->getSize()) return Sema::TDK_NonDeducedMismatch; - unsigned SubTDF = TDF & TDF_IgnoreQualifiers; - return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, - ConstantArrayParm->getElementType(), - ConstantArrayArg->getElementType(), - Info, Deduced, SubTDF); + return DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, CAP->getElementType(), CAA->getElementType(), Info, + Deduced, TDF & TDF_IgnoreQualifiers); } // type [i] case Type::DependentSizedArray: { - const ArrayType *ArrayArg = S.Context.getAsArrayType(Arg); - if (!ArrayArg) + const auto *AA = S.Context.getAsArrayType(A); + if (!AA) return Sema::TDK_NonDeducedMismatch; - unsigned SubTDF = TDF & TDF_IgnoreQualifiers; - // Check the element type of the arrays - const DependentSizedArrayType *DependentArrayParm - = S.Context.getAsDependentSizedArrayType(Param); - if (Sema::TemplateDeductionResult Result - = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, - DependentArrayParm->getElementType(), - ArrayArg->getElementType(), - Info, Deduced, SubTDF)) + const auto *DAP = S.Context.getAsDependentSizedArrayType(P); + assert(DAP); + if (auto Result = DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, DAP->getElementType(), AA->getElementType(), + Info, Deduced, TDF & TDF_IgnoreQualifiers)) return Result; // Determine the array bound is something we can deduce. - const NonTypeTemplateParmDecl *NTTP - = getDeducedParameterFromExpr(Info, DependentArrayParm->getSizeExpr()); + const NonTypeTemplateParmDecl *NTTP = + getDeducedParameterFromExpr(Info, DAP->getSizeExpr()); if (!NTTP) return Sema::TDK_Success; @@ -1772,20 +1707,16 @@ // template parameter. assert(NTTP->getDepth() == Info.getDeducedDepth() && "saw non-type template parameter with wrong depth"); - 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 *CAA = dyn_cast(AA)) { + llvm::APSInt Size(CAA->getSize()); + return DeduceNonTypeTemplateArgument( + S, TemplateParams, NTTP, Size, S.Context.getSizeType(), + /*ArrayBound=*/true, Info, Deduced); } - if (const DependentSizedArrayType *DependentArrayArg - = dyn_cast(ArrayArg)) - if (DependentArrayArg->getSizeExpr()) - return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, - DependentArrayArg->getSizeExpr(), - Info, Deduced); + if (const auto *DAA = dyn_cast(AA)) + if (DAA->getSizeExpr()) + return DeduceNonTypeTemplateArgument( + S, TemplateParams, NTTP, DAA->getSizeExpr(), Info, Deduced); // Incomplete type does not match a dependently-sized array type return Sema::TDK_NonDeducedMismatch; @@ -1795,34 +1726,29 @@ // T(*)() // T(*)(T) case Type::FunctionProto: { - unsigned SubTDF = TDF & TDF_TopLevelParameterTypeList; - const FunctionProtoType *FunctionProtoArg = - dyn_cast(Arg); - if (!FunctionProtoArg) + const auto *FPP = P->castAs(), + *FPA = A->getAs(); + if (!FPA) return Sema::TDK_NonDeducedMismatch; - const FunctionProtoType *FunctionProtoParam = - cast(Param); - - if (FunctionProtoParam->getMethodQuals() - != FunctionProtoArg->getMethodQuals() || - FunctionProtoParam->getRefQualifier() - != FunctionProtoArg->getRefQualifier() || - FunctionProtoParam->isVariadic() != FunctionProtoArg->isVariadic()) + if (FPP->getMethodQuals() != FPA->getMethodQuals() || + FPP->getRefQualifier() != FPA->getRefQualifier() || + FPP->isVariadic() != FPA->isVariadic()) return Sema::TDK_NonDeducedMismatch; // Check return types. if (auto Result = DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, FunctionProtoParam->getReturnType(), - FunctionProtoArg->getReturnType(), Info, Deduced, 0)) + S, TemplateParams, FPP->getReturnType(), FPA->getReturnType(), + Info, Deduced, 0, + /*PartialOrdering=*/false, + /*DeducedFromArrayBound=*/false)) return Result; // Check parameter types. if (auto Result = DeduceTemplateArguments( - S, TemplateParams, FunctionProtoParam->param_type_begin(), - FunctionProtoParam->getNumParams(), - FunctionProtoArg->param_type_begin(), - FunctionProtoArg->getNumParams(), Info, Deduced, SubTDF)) + S, TemplateParams, FPP->param_type_begin(), FPP->getNumParams(), + FPA->param_type_begin(), FPA->getNumParams(), Info, Deduced, + TDF & TDF_TopLevelParameterTypeList)) return Result; if (TDF & TDF_AllowCompatibleFunctionType) @@ -1831,15 +1757,15 @@ // 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 = FunctionProtoParam->getNoexceptExpr(); + Expr *NoexceptExpr = FPP->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 (FunctionProtoArg->canThrow()) { + switch (FPA->canThrow()) { case CT_Cannot: Noexcept = 1; LLVM_FALLTHROUGH; @@ -1849,10 +1775,10 @@ // FIXME: Should we? return DeduceNonTypeTemplateArgument( S, TemplateParams, NTTP, Noexcept, S.Context.BoolTy, - /*ArrayBound*/true, Info, Deduced); + /*DeducedFromArrayBound=*/true, Info, Deduced); case CT_Dependent: - if (Expr *ArgNoexceptExpr = FunctionProtoArg->getNoexceptExpr()) + if (Expr *ArgNoexceptExpr = FPA->getNoexceptExpr()) return DeduceNonTypeTemplateArgument( S, TemplateParams, NTTP, ArgNoexceptExpr, Info, Deduced); // Can't deduce anything from throw(T...). @@ -1870,11 +1796,6 @@ 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 @@ -1882,41 +1803,34 @@ // 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. - const RecordType *RecordT = Arg->getAs(); - if (!(TDF & TDF_DerivedClass) || !RecordT) - return DeduceTemplateArguments(S, TemplateParams, SpecParam, Arg, Info, - Deduced); + const auto *RA = A->getAs(); + if (!(TDF & TDF_DerivedClass) || !RA) + return DeduceTemplateSpecArguments(S, TemplateParams, P, A, Info, + Deduced); SmallVector DeducedOrig(Deduced.begin(), Deduced.end()); - Sema::TemplateDeductionResult Result = DeduceTemplateArguments( - S, TemplateParams, SpecParam, Arg, Info, Deduced); - + auto Result = + DeduceTemplateSpecArguments(S, TemplateParams, P, A, 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(), Arg)) + if (!S.isCompleteType(Info.getLocation(), A)) return Result; // Reset the incorrectly deduced argument from above. Deduced = DeducedOrig; // Check bases according to C++14 [temp.deduct.call] p4b3: - Sema::TemplateDeductionResult BaseResult = DeduceTemplateBases( - S, RecordT, TemplateParams, SpecParam, Info, Deduced); - - if (BaseResult != Sema::TDK_Invalid) - return BaseResult; - return Result; + auto BaseResult = + DeduceTemplateBases(S, RA, TemplateParams, P, Info, Deduced); + return BaseResult != Sema::TDK_Invalid ? BaseResult : Result; } // T type::* @@ -1929,33 +1843,27 @@ // T (T::*)() // T (T::*)(T) case Type::MemberPointer: { - const MemberPointerType *MemPtrParam = cast(Param); - const MemberPointerType *MemPtrArg = dyn_cast(Arg); - if (!MemPtrArg) + const auto *MPP = P->castAs(), + *MPA = A->getAs(); + if (!MPA) return Sema::TDK_NonDeducedMismatch; - QualType ParamPointeeType = MemPtrParam->getPointeeType(); - if (ParamPointeeType->isFunctionType()) - S.adjustMemberFunctionCC(ParamPointeeType, /*IsStatic=*/true, + QualType PPT = MPP->getPointeeType(); + if (PPT->isFunctionType()) + S.adjustMemberFunctionCC(PPT, /*IsStatic=*/true, /*IsCtorOrDtor=*/false, Info.getLocation()); - QualType ArgPointeeType = MemPtrArg->getPointeeType(); - if (ArgPointeeType->isFunctionType()) - S.adjustMemberFunctionCC(ArgPointeeType, /*IsStatic=*/true, + QualType APT = MPA->getPointeeType(); + if (APT->isFunctionType()) + S.adjustMemberFunctionCC(APT, /*IsStatic=*/true, /*IsCtorOrDtor=*/false, Info.getLocation()); - if (Sema::TemplateDeductionResult Result - = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, - ParamPointeeType, - ArgPointeeType, - Info, Deduced, - TDF & TDF_IgnoreQualifiers)) + unsigned SubTDF = TDF & TDF_IgnoreQualifiers; + if (auto Result = DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, PPT, APT, Info, Deduced, SubTDF)) return Result; - - return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, - QualType(MemPtrParam->getClass(), 0), - QualType(MemPtrArg->getClass(), 0), - Info, Deduced, - TDF & TDF_IgnoreQualifiers); + return DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, QualType(MPP->getClass(), 0), + QualType(MPA->getClass(), 0), Info, Deduced, SubTDF); } // (clang extension) @@ -1964,70 +1872,58 @@ // T(^)() // T(^)(T) case Type::BlockPointer: { - const BlockPointerType *BlockPtrParam = cast(Param); - const BlockPointerType *BlockPtrArg = dyn_cast(Arg); - - if (!BlockPtrArg) + const auto *BPP = P->castAs(), + *BPA = A->getAs(); + if (!BPA) return Sema::TDK_NonDeducedMismatch; - - return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, - BlockPtrParam->getPointeeType(), - BlockPtrArg->getPointeeType(), - Info, Deduced, 0); + return DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, BPP->getPointeeType(), BPA->getPointeeType(), Info, + Deduced, 0); } // (clang extension) // // T __attribute__(((ext_vector_type()))) case Type::ExtVector: { - const ExtVectorType *VectorParam = cast(Param); - if (const ExtVectorType *VectorArg = dyn_cast(Arg)) { + const auto *VP = P->castAs(); + QualType ElementType; + if (const auto *VA = A->getAs()) { // Make sure that the vectors have the same number of elements. - if (VectorParam->getNumElements() != VectorArg->getNumElements()) + if (VP->getNumElements() != VA->getNumElements()) return Sema::TDK_NonDeducedMismatch; - - // Perform deduction on the element types. - return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, - VectorParam->getElementType(), - VectorArg->getElementType(), - Info, Deduced, TDF); - } - - if (const DependentSizedExtVectorType *VectorArg - = dyn_cast(Arg)) { + ElementType = VA->getElementType(); + } else if (const auto *VA = A->getAs()) { // We can't check the number of elements, since the argument has a // dependent number of elements. This can only occur during partial // ordering. - - // Perform deduction on the element types. - return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, - VectorParam->getElementType(), - VectorArg->getElementType(), - Info, Deduced, TDF); + ElementType = VA->getElementType(); + } else { + return Sema::TDK_NonDeducedMismatch; } - - return Sema::TDK_NonDeducedMismatch; + // Perform deduction on the element types. + return DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, VP->getElementType(), ElementType, Info, Deduced, + TDF); } case Type::DependentVector: { - const auto *VectorParam = cast(Param); + const auto *VP = P->castAs(); - if (const auto *VectorArg = dyn_cast(Arg)) { + if (const auto *VA = A->getAs()) { // Perform deduction on the element types. - if (Sema::TemplateDeductionResult Result = - DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, VectorParam->getElementType(), - VectorArg->getElementType(), Info, Deduced, TDF)) + if (auto Result = DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, VP->getElementType(), VA->getElementType(), + Info, Deduced, TDF)) return Result; // Perform deduction on the vector size, if we can. const NonTypeTemplateParmDecl *NTTP = - getDeducedParameterFromExpr(Info, VectorParam->getSizeExpr()); + getDeducedParameterFromExpr(Info, VP->getSizeExpr()); if (!NTTP) return Sema::TDK_Success; llvm::APSInt ArgSize(S.Context.getTypeSize(S.Context.IntTy), false); - ArgSize = VectorArg->getNumElements(); + ArgSize = VA->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. @@ -2036,22 +1932,21 @@ Info, Deduced); } - if (const auto *VectorArg = dyn_cast(Arg)) { + if (const auto *VA = A->getAs()) { // Perform deduction on the element types. - if (Sema::TemplateDeductionResult Result = - DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, VectorParam->getElementType(), - VectorArg->getElementType(), Info, Deduced, TDF)) + if (auto Result = DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, VP->getElementType(), VA->getElementType(), + Info, Deduced, TDF)) return Result; // Perform deduction on the vector size, if we can. - const NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr( - Info, VectorParam->getSizeExpr()); + const NonTypeTemplateParmDecl *NTTP = + getDeducedParameterFromExpr(Info, VP->getSizeExpr()); if (!NTTP) return Sema::TDK_Success; - return DeduceNonTypeTemplateArgument( - S, TemplateParams, NTTP, VectorArg->getSizeExpr(), Info, Deduced); + return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, + VA->getSizeExpr(), Info, Deduced); } return Sema::TDK_NonDeducedMismatch; @@ -2061,26 +1956,23 @@ // // T __attribute__(((ext_vector_type(N)))) case Type::DependentSizedExtVector: { - const DependentSizedExtVectorType *VectorParam - = cast(Param); + const auto *VP = P->castAs(); - if (const ExtVectorType *VectorArg = dyn_cast(Arg)) { + if (const auto *VA = A->getAs()) { // Perform deduction on the element types. - if (Sema::TemplateDeductionResult Result - = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, - VectorParam->getElementType(), - VectorArg->getElementType(), - Info, Deduced, TDF)) + if (auto Result = DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, VP->getElementType(), VA->getElementType(), + Info, Deduced, TDF)) return Result; // Perform deduction on the vector size, if we can. const NonTypeTemplateParmDecl *NTTP = - getDeducedParameterFromExpr(Info, VectorParam->getSizeExpr()); + getDeducedParameterFromExpr(Info, VP->getSizeExpr()); if (!NTTP) return Sema::TDK_Success; llvm::APSInt ArgSize(S.Context.getTypeSize(S.Context.IntTy), false); - ArgSize = VectorArg->getNumElements(); + ArgSize = VA->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. @@ -2089,25 +1981,21 @@ Deduced); } - if (const DependentSizedExtVectorType *VectorArg - = dyn_cast(Arg)) { + if (const auto *VA = A->getAs()) { // Perform deduction on the element types. - if (Sema::TemplateDeductionResult Result - = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, - VectorParam->getElementType(), - VectorArg->getElementType(), - Info, Deduced, TDF)) + if (auto Result = DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, VP->getElementType(), VA->getElementType(), + Info, Deduced, TDF)) return Result; // Perform deduction on the vector size, if we can. const NonTypeTemplateParmDecl *NTTP = - getDeducedParameterFromExpr(Info, VectorParam->getSizeExpr()); + getDeducedParameterFromExpr(Info, VP->getSizeExpr()); if (!NTTP) return Sema::TDK_Success; return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, - VectorArg->getSizeExpr(), - Info, Deduced); + VA->getSizeExpr(), Info, Deduced); } return Sema::TDK_NonDeducedMismatch; @@ -2118,57 +2006,55 @@ // T __attribute__((matrix_type(, // ))) case Type::ConstantMatrix: { - const ConstantMatrixType *MatrixArg = dyn_cast(Arg); - if (!MatrixArg) + const auto *MP = P->castAs(), + *MA = A->getAs(); + if (!MA) return Sema::TDK_NonDeducedMismatch; - const ConstantMatrixType *MatrixParam = cast(Param); // Check that the dimensions are the same - if (MatrixParam->getNumRows() != MatrixArg->getNumRows() || - MatrixParam->getNumColumns() != MatrixArg->getNumColumns()) { + if (MP->getNumRows() != MA->getNumRows() || + MP->getNumColumns() != MA->getNumColumns()) { return Sema::TDK_NonDeducedMismatch; } // Perform deduction on element types. return DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, MatrixParam->getElementType(), - MatrixArg->getElementType(), Info, Deduced, TDF); + S, TemplateParams, MP->getElementType(), MA->getElementType(), Info, + Deduced, TDF); } case Type::DependentSizedMatrix: { - const MatrixType *MatrixArg = dyn_cast(Arg); - if (!MatrixArg) + const auto *MP = P->castAs(); + const auto *MA = A->getAs(); + if (!MA) return Sema::TDK_NonDeducedMismatch; // Check the element type of the matrixes. - const DependentSizedMatrixType *MatrixParam = - cast(Param); - if (Sema::TemplateDeductionResult Result = - DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, MatrixParam->getElementType(), - MatrixArg->getElementType(), Info, Deduced, TDF)) + if (auto Result = DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, MP->getElementType(), MA->getElementType(), + Info, Deduced, TDF)) return Result; // Try to deduce a matrix dimension. auto DeduceMatrixArg = [&S, &Info, &Deduced, &TemplateParams]( - Expr *ParamExpr, const MatrixType *Arg, + Expr *ParamExpr, const MatrixType *A, unsigned (ConstantMatrixType::*GetArgDimension)() const, Expr *(DependentSizedMatrixType::*GetArgDimensionExpr)() const) { - const auto *ArgConstMatrix = dyn_cast(Arg); - const auto *ArgDepMatrix = dyn_cast(Arg); + const auto *ACM = dyn_cast(A); + const auto *ADM = dyn_cast(A); if (!ParamExpr->isValueDependent()) { Optional ParamConst = ParamExpr->getIntegerConstantExpr(S.Context); if (!ParamConst) return Sema::TDK_NonDeducedMismatch; - if (ArgConstMatrix) { - if ((ArgConstMatrix->*GetArgDimension)() == *ParamConst) + if (ACM) { + if ((ACM->*GetArgDimension)() == *ParamConst) return Sema::TDK_Success; return Sema::TDK_NonDeducedMismatch; } - Expr *ArgExpr = (ArgDepMatrix->*GetArgDimensionExpr)(); + Expr *ArgExpr = (ADM->*GetArgDimensionExpr)(); if (!ArgExpr->isValueDependent()) if (Optional ArgConst = ArgExpr->getIntegerConstantExpr(S.Context)) @@ -2182,27 +2068,26 @@ if (!NTTP) return Sema::TDK_Success; - if (ArgConstMatrix) { + if (ACM) { llvm::APSInt ArgConst( S.Context.getTypeSize(S.Context.getSizeType())); - ArgConst = (ArgConstMatrix->*GetArgDimension)(); + ArgConst = (ACM->*GetArgDimension)(); return DeduceNonTypeTemplateArgument( S, TemplateParams, NTTP, ArgConst, S.Context.getSizeType(), /*ArrayBound=*/true, Info, Deduced); } - return DeduceNonTypeTemplateArgument( - S, TemplateParams, NTTP, (ArgDepMatrix->*GetArgDimensionExpr)(), - Info, Deduced); + return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, + (ADM->*GetArgDimensionExpr)(), + Info, Deduced); }; - auto Result = DeduceMatrixArg(MatrixParam->getRowExpr(), MatrixArg, - &ConstantMatrixType::getNumRows, - &DependentSizedMatrixType::getRowExpr); - if (Result) + if (auto Result = DeduceMatrixArg(MP->getRowExpr(), MA, + &ConstantMatrixType::getNumRows, + &DependentSizedMatrixType::getRowExpr)) return Result; - return DeduceMatrixArg(MatrixParam->getColumnExpr(), MatrixArg, + return DeduceMatrixArg(MP->getColumnExpr(), MA, &ConstantMatrixType::getNumColumns, &DependentSizedMatrixType::getColumnExpr); } @@ -2211,44 +2096,39 @@ // // T __attribute__(((address_space(N)))) case Type::DependentAddressSpace: { - const DependentAddressSpaceType *AddressSpaceParam = - cast(Param); + const auto *ASP = P->castAs(); - if (const DependentAddressSpaceType *AddressSpaceArg = - dyn_cast(Arg)) { + if (const auto *ASA = A->getAs()) { // Perform deduction on the pointer type. - if (Sema::TemplateDeductionResult Result = - DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, AddressSpaceParam->getPointeeType(), - AddressSpaceArg->getPointeeType(), Info, Deduced, TDF)) + if (auto Result = DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, ASP->getPointeeType(), ASA->getPointeeType(), + Info, Deduced, TDF)) return Result; // Perform deduction on the address space, if we can. - const NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr( - Info, AddressSpaceParam->getAddrSpaceExpr()); + const NonTypeTemplateParmDecl *NTTP = + getDeducedParameterFromExpr(Info, ASP->getAddrSpaceExpr()); if (!NTTP) return Sema::TDK_Success; return DeduceNonTypeTemplateArgument( - S, TemplateParams, NTTP, AddressSpaceArg->getAddrSpaceExpr(), Info, - Deduced); + S, TemplateParams, NTTP, ASA->getAddrSpaceExpr(), Info, Deduced); } - if (isTargetAddressSpace(Arg.getAddressSpace())) { + if (isTargetAddressSpace(A.getAddressSpace())) { llvm::APSInt ArgAddressSpace(S.Context.getTypeSize(S.Context.IntTy), false); - ArgAddressSpace = toTargetAddressSpace(Arg.getAddressSpace()); + ArgAddressSpace = toTargetAddressSpace(A.getAddressSpace()); // Perform deduction on the pointer types. - if (Sema::TemplateDeductionResult Result = - DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, AddressSpaceParam->getPointeeType(), - S.Context.removeAddrSpaceQualType(Arg), Info, Deduced, TDF)) + if (auto Result = DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, ASP->getPointeeType(), + S.Context.removeAddrSpaceQualType(A), Info, Deduced, TDF)) return Result; // Perform deduction on the address space, if we can. - const NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr( - Info, AddressSpaceParam->getAddrSpaceExpr()); + const NonTypeTemplateParmDecl *NTTP = + getDeducedParameterFromExpr(Info, ASP->getAddrSpaceExpr()); if (!NTTP) return Sema::TDK_Success; @@ -2260,30 +2140,31 @@ return Sema::TDK_NonDeducedMismatch; } case Type::DependentExtInt: { - const auto *IntParam = cast(Param); + const auto *IP = P->castAs(); - if (const auto *IntArg = dyn_cast(Arg)){ - if (IntParam->isUnsigned() != IntArg->isUnsigned()) + if (const auto *IA = A->getAs()) { + if (IP->isUnsigned() != IA->isUnsigned()) return Sema::TDK_NonDeducedMismatch; const NonTypeTemplateParmDecl *NTTP = - getDeducedParameterFromExpr(Info, IntParam->getNumBitsExpr()); + getDeducedParameterFromExpr(Info, IP->getNumBitsExpr()); if (!NTTP) return Sema::TDK_Success; llvm::APSInt ArgSize(S.Context.getTypeSize(S.Context.IntTy), false); - ArgSize = IntArg->getNumBits(); + ArgSize = IA->getNumBits(); return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, ArgSize, S.Context.IntTy, true, Info, Deduced); } - if (const auto *IntArg = dyn_cast(Arg)) { - if (IntParam->isUnsigned() != IntArg->isUnsigned()) + if (const auto *IA = A->getAs()) { + if (IP->isUnsigned() != IA->isUnsigned()) return Sema::TDK_NonDeducedMismatch; return Sema::TDK_Success; } + return Sema::TDK_NonDeducedMismatch; } @@ -2293,125 +2174,103 @@ 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 &Param, - TemplateArgument Arg, +DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, + const TemplateArgument &P, TemplateArgument A, 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 (Arg.isPackExpansion()) - Arg = Arg.getPackExpansionPattern(); + if (A.isPackExpansion()) + A = A.getPackExpansionPattern(); - switch (Param.getKind()) { + switch (P.getKind()) { case TemplateArgument::Null: llvm_unreachable("Null template argument in parameter list"); case TemplateArgument::Type: - if (Arg.getKind() == TemplateArgument::Type) - return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, - Param.getAsType(), - Arg.getAsType(), - Info, Deduced, 0); - Info.FirstArg = Param; - Info.SecondArg = Arg; + if (A.getKind() == TemplateArgument::Type) + return DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, P.getAsType(), A.getAsType(), Info, Deduced, 0); + Info.FirstArg = P; + Info.SecondArg = A; return Sema::TDK_NonDeducedMismatch; case TemplateArgument::Template: - if (Arg.getKind() == TemplateArgument::Template) - return DeduceTemplateArguments(S, TemplateParams, - Param.getAsTemplate(), - Arg.getAsTemplate(), Info, Deduced); - Info.FirstArg = Param; - Info.SecondArg = Arg; + if (A.getKind() == TemplateArgument::Template) + return DeduceTemplateArguments(S, TemplateParams, P.getAsTemplate(), + A.getAsTemplate(), Info, Deduced); + Info.FirstArg = P; + Info.SecondArg = A; return Sema::TDK_NonDeducedMismatch; case TemplateArgument::TemplateExpansion: llvm_unreachable("caller should handle pack expansions"); case TemplateArgument::Declaration: - if (Arg.getKind() == TemplateArgument::Declaration && - isSameDeclaration(Param.getAsDecl(), Arg.getAsDecl())) + if (A.getKind() == TemplateArgument::Declaration && + isSameDeclaration(P.getAsDecl(), A.getAsDecl())) return Sema::TDK_Success; - Info.FirstArg = Param; - Info.SecondArg = Arg; + Info.FirstArg = P; + Info.SecondArg = A; return Sema::TDK_NonDeducedMismatch; case TemplateArgument::NullPtr: - if (Arg.getKind() == TemplateArgument::NullPtr && - S.Context.hasSameType(Param.getNullPtrType(), Arg.getNullPtrType())) + if (A.getKind() == TemplateArgument::NullPtr && + S.Context.hasSameType(P.getNullPtrType(), A.getNullPtrType())) return Sema::TDK_Success; - Info.FirstArg = Param; - Info.SecondArg = Arg; + Info.FirstArg = P; + Info.SecondArg = A; return Sema::TDK_NonDeducedMismatch; case TemplateArgument::Integral: - if (Arg.getKind() == TemplateArgument::Integral) { - if (hasSameExtendedValue(Param.getAsIntegral(), Arg.getAsIntegral())) + if (A.getKind() == TemplateArgument::Integral) { + if (hasSameExtendedValue(P.getAsIntegral(), A.getAsIntegral())) return Sema::TDK_Success; - - Info.FirstArg = Param; - Info.SecondArg = Arg; - return Sema::TDK_NonDeducedMismatch; } - - if (Arg.getKind() == TemplateArgument::Expression) { - Info.FirstArg = Param; - Info.SecondArg = Arg; - return Sema::TDK_NonDeducedMismatch; - } - - Info.FirstArg = Param; - Info.SecondArg = Arg; + Info.FirstArg = P; + Info.SecondArg = A; return Sema::TDK_NonDeducedMismatch; case TemplateArgument::Expression: if (const NonTypeTemplateParmDecl *NTTP = - getDeducedParameterFromExpr(Info, Param.getAsExpr())) { - if (Arg.getKind() == TemplateArgument::Integral) - return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, - Arg.getAsIntegral(), - Arg.getIntegralType(), - /*ArrayBound=*/false, - Info, Deduced); - if (Arg.getKind() == TemplateArgument::NullPtr) + 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, - Arg.getNullPtrType(), - Info, Deduced); - if (Arg.getKind() == TemplateArgument::Expression) + A.getNullPtrType(), Info, Deduced); + if (A.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); + A.getAsExpr(), Info, Deduced); + if (A.getKind() == TemplateArgument::Declaration) + return DeduceNonTypeTemplateArgument( + S, TemplateParams, NTTP, A.getAsDecl(), A.getParamTypeForDecl(), + Info, Deduced); - Info.FirstArg = Param; - Info.SecondArg = Arg; + Info.FirstArg = P; + Info.SecondArg = A; 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!"); } @@ -2464,8 +2323,8 @@ static Sema::TemplateDeductionResult DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, - ArrayRef Params, - ArrayRef Args, + ArrayRef Ps, + ArrayRef As, TemplateDeductionInfo &Info, SmallVectorImpl &Deduced, bool NumberOfArgumentsMustMatch) { @@ -2473,7 +2332,7 @@ // 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(Params)) + if (hasPackExpansionBeforeEnd(Ps)) return Sema::TDK_Success; // C++0x [temp.deduct.type]p9: @@ -2481,12 +2340,13 @@ // 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(Params, ParamIdx); ++ParamIdx) { - if (!Params[ParamIdx].isPackExpansion()) { + for (; hasTemplateArgumentForDeduction(Ps, ParamIdx); ++ParamIdx) { + const TemplateArgument &P = Ps[ParamIdx]; + if (!P.isPackExpansion()) { // The simple case: deduce template arguments by matching Pi and Ai. // Check whether we have enough arguments. - if (!hasTemplateArgumentForDeduction(Args, ArgIdx)) + if (!hasTemplateArgumentForDeduction(As, ArgIdx)) return NumberOfArgumentsMustMatch ? Sema::TDK_MiscellaneousDeductionFailure : Sema::TDK_Success; @@ -2494,14 +2354,12 @@ // 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 (Args[ArgIdx].isPackExpansion()) + if (As[ArgIdx].isPackExpansion()) return Sema::TDK_MiscellaneousDeductionFailure; // Perform deduction for this Pi/Ai pair. - if (Sema::TemplateDeductionResult Result - = DeduceTemplateArguments(S, TemplateParams, - Params[ParamIdx], Args[ArgIdx], - Info, Deduced)) + if (auto Result = DeduceTemplateArguments(S, TemplateParams, P, + As[ArgIdx], Info, Deduced)) return Result; // Move to the next argument. @@ -2516,7 +2374,7 @@ // 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 = Params[ParamIdx].getPackExpansionPattern(); + TemplateArgument Pattern = P.getPackExpansionPattern(); // Prepare to deduce the packs within the pattern. PackDeductionScope PackScope(S, TemplateParams, Deduced, Info, Pattern); @@ -2524,13 +2382,12 @@ // 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(Args, ArgIdx) && + for (; hasTemplateArgumentForDeduction(As, ArgIdx) && PackScope.hasNextElement(); ++ArgIdx) { // Deduce template arguments from the pattern. - if (Sema::TemplateDeductionResult Result - = DeduceTemplateArguments(S, TemplateParams, Pattern, Args[ArgIdx], - Info, Deduced)) + if (auto Result = DeduceTemplateArguments(S, TemplateParams, Pattern, + As[ArgIdx], Info, Deduced)) return Result; PackScope.nextPackElement(); @@ -2546,15 +2403,14 @@ } 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. @@ -4357,7 +4213,7 @@ bool HasDeducedReturnType = false; if (getLangOpts().CPlusPlus14 && IsAddressOfFunction && Function->getReturnType()->getContainedAutoType()) { - FunctionType = SubstAutoType(FunctionType, Context.DependentTy); + FunctionType = SubstAutoTypeDependent(FunctionType); HasDeducedReturnType = true; } @@ -4791,12 +4647,8 @@ ExprResult ER = CheckPlaceholderExpr(Init); if (ER.isInvalid()) return DAR_FailedAlreadyDiagnosed; - Init = ER.get(); - QualType Deduced = BuildDecltypeType(Init, Init->getBeginLoc(), false); - if (Deduced.isNull()) - return DAR_FailedAlreadyDiagnosed; - // FIXME: Support a non-canonical deduced type for 'auto'. - Deduced = Context.getCanonicalType(Deduced); + QualType Deduced = getDecltypeForExpr(ER.get()); + assert(!Deduced.isNull()); if (AT->isConstrained() && !IgnoreConstraints) { auto ConstraintsResult = CheckDeducedPlaceholderConstraints(*this, *AT, @@ -4831,7 +4683,7 @@ Context, Loc, Loc, TemplParamPtr, Loc, nullptr); QualType FuncParam = - SubstituteDeducedTypeTransform(*this, TemplArg, /*UseTypeSugar*/false) + SubstituteDeducedTypeTransform(*this, TemplArg, /*UseTypeSugar*/ true) .Apply(Type); assert(!FuncParam.isNull() && "substituting template parameter for 'auto' failed"); @@ -4945,27 +4797,29 @@ QualType Sema::SubstAutoType(QualType TypeWithAuto, QualType TypeToReplaceAuto) { - if (TypeToReplaceAuto->isDependentType()) - return SubstituteDeducedTypeTransform( - *this, DependentAuto{ - TypeToReplaceAuto->containsUnexpandedParameterPack()}) - .TransformType(TypeWithAuto); + assert(TypeToReplaceAuto != Context.DependentTy); return SubstituteDeducedTypeTransform(*this, TypeToReplaceAuto) .TransformType(TypeWithAuto); } TypeSourceInfo *Sema::SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto, QualType TypeToReplaceAuto) { - if (TypeToReplaceAuto->isDependentType()) - return SubstituteDeducedTypeTransform( - *this, - DependentAuto{ - TypeToReplaceAuto->containsUnexpandedParameterPack()}) - .TransformType(TypeWithAuto); + assert(TypeToReplaceAuto != Context.DependentTy); return SubstituteDeducedTypeTransform(*this, TypeToReplaceAuto) .TransformType(TypeWithAuto); } +QualType Sema::SubstAutoTypeDependent(QualType TypeWithAuto) { + return SubstituteDeducedTypeTransform(*this, DependentAuto{false}) + .TransformType(TypeWithAuto); +} + +TypeSourceInfo * +Sema::SubstAutoTypeSourceInfoDependent(TypeSourceInfo *TypeWithAuto) { + return SubstituteDeducedTypeTransform(*this, DependentAuto{false}) + .TransformType(TypeWithAuto); +} + QualType Sema::ReplaceAutoType(QualType TypeWithAuto, QualType TypeToReplaceAuto) { return SubstituteDeducedTypeTransform(*this, TypeToReplaceAuto, @@ -5160,6 +5014,10 @@ Args2.resize(NumComparedArguments); if (Reversed) std::reverse(Args2.begin(), Args2.end()); + + auto TF = [&S](QualType T) { return S.Context.getCanonicalType(T); }; + llvm::transform(Args1, Args1.begin(), TF); + llvm::transform(Args2, Args2.begin(), TF); if (DeduceTemplateArguments(S, TemplateParams, Args2.data(), Args2.size(), Args1.data(), Args1.size(), Info, Deduced, TDF_None, /*PartialOrdering=*/true)) diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -1622,7 +1622,7 @@ Expr *E = DS.getRepAsExpr(); assert(E && "Didn't get an expression for typeof?"); // TypeQuals handled by caller. - Result = S.BuildTypeofExprType(E, DS.getTypeSpecTypeLoc()); + Result = S.BuildTypeofExprType(E); if (Result.isNull()) { Result = Context.IntTy; declarator.setInvalidType(true); @@ -1633,7 +1633,7 @@ Expr *E = DS.getRepAsExpr(); assert(E && "Didn't get an expression for decltype?"); // TypeQuals handled by caller. - Result = S.BuildDecltypeType(E, DS.getTypeSpecTypeLoc()); + Result = S.BuildDecltypeType(E); if (Result.isNull()) { Result = Context.IntTy; declarator.setInvalidType(true); @@ -8887,7 +8887,7 @@ return Context.getElaboratedType(Keyword, NNS, T, OwnedTagDecl); } -QualType Sema::BuildTypeofExprType(Expr *E, SourceLocation Loc) { +QualType Sema::BuildTypeofExprType(Expr *E) { assert(!E->hasPlaceholderType() && "unexpected placeholder"); if (!getLangOpts().CPlusPlus && E->refersToBitField()) @@ -8904,9 +8904,9 @@ /// getDecltypeForExpr - Given an expr, will return the decltype for /// that expression, according to the rules in C++11 /// [dcl.type.simple]p4 and C++11 [expr.lambda.prim]p18. -static QualType getDecltypeForExpr(Sema &S, Expr *E) { +QualType Sema::getDecltypeForExpr(Expr *E) { if (E->isTypeDependent()) - return S.Context.DependentTy; + return Context.DependentTy; Expr *IDExpr = E; if (auto *ImplCastExpr = dyn_cast(E)) @@ -8923,7 +8923,7 @@ // 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(S.Context); + return SNTTPE->getParameterType(Context); // - if e is an unparenthesized id-expression or an unparenthesized class // member access (5.2.5), decltype(e) is the type of the entity named @@ -8931,22 +8931,21 @@ // functions, the program is ill-formed; // // We apply the same rules for Objective-C ivar and property references. - if (const DeclRefExpr *DRE = dyn_cast(IDExpr)) { + if (const auto *DRE = dyn_cast(IDExpr)) { const ValueDecl *VD = DRE->getDecl(); - 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()) + QualType T = VD->getType(); + return isa(VD) ? T.getUnqualifiedType() : T; + } + if (const auto *ME = dyn_cast(IDExpr)) { + if (const auto *VD = ME->getMemberDecl()) if (isa(VD) || isa(VD)) return VD->getType(); - } else if (const ObjCIvarRefExpr *IR = dyn_cast(IDExpr)) { + } else if (const auto *IR = dyn_cast(IDExpr)) { return IR->getDecl()->getType(); - } else if (const ObjCPropertyRefExpr *PR = - dyn_cast(IDExpr)) { + } else if (const auto *PR = dyn_cast(IDExpr)) { if (PR->isExplicitProperty()) return PR->getExplicitProperty()->getType(); - } else if (auto *PE = dyn_cast(IDExpr)) { + } else if (const auto *PE = dyn_cast(IDExpr)) { return PE->getType(); } @@ -8957,24 +8956,20 @@ // access to a corresponding data member of the closure type that // would have been declared if x were an odr-use of the denoted // entity. - using namespace sema; - if (S.getCurLambda()) { - if (isa(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); - } + 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); } } } - return S.Context.getReferenceQualifiedType(E); + return Context.getReferenceQualifiedType(E); } -QualType Sema::BuildDecltypeType(Expr *E, SourceLocation Loc, - bool AsUnevaluated) { +QualType Sema::BuildDecltypeType(Expr *E, bool AsUnevaluated) { assert(!E->hasPlaceholderType() && "unexpected placeholder"); if (AsUnevaluated && CodeSynthesisContexts.empty() && @@ -8985,8 +8980,7 @@ // used to build SFINAE gadgets. Diag(E->getExprLoc(), diag::warn_side_effects_unevaluated_context); } - - return Context.getDecltypeType(E, getDecltypeForExpr(*this, E)); + return Context.getDecltypeType(E, getDecltypeForExpr(E)); } QualType Sema::BuildUnaryTransformType(QualType BaseType, diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -6561,7 +6561,7 @@ T->isDependentType() || T->isConstrained()) { // FIXME: Maybe don't rebuild if all template arguments are the same. llvm::SmallVector NewArgList; - NewArgList.reserve(NewArgList.size()); + NewArgList.reserve(NewTemplateArgs.size()); for (const auto &ArgLoc : NewTemplateArgs.arguments()) NewArgList.push_back(ArgLoc.getArgument()); Result = getDerived().RebuildAutoType(NewDeduced, T->getKeyword(), NewCD, @@ -14449,10 +14449,10 @@ return SemaRef.Context.getTypeDeclType(Ty); } -template +template QualType TreeTransform::RebuildTypeOfExprType(Expr *E, - SourceLocation Loc) { - return SemaRef.BuildTypeofExprType(E, Loc); + SourceLocation) { + return SemaRef.BuildTypeofExprType(E); } template @@ -14460,10 +14460,9 @@ return SemaRef.Context.getTypeOfType(Underlying); } -template -QualType TreeTransform::RebuildDecltypeType(Expr *E, - SourceLocation Loc) { - return SemaRef.BuildDecltypeType(E, Loc); +template +QualType TreeTransform::RebuildDecltypeType(Expr *E, SourceLocation) { + return SemaRef.BuildDecltypeType(E); } 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 --- 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 p0702r1 { template struct X { // expected-note {{candidate}} - X(std::initializer_list); // expected-note {{candidate template ignored: could not match 'initializer_list' against 'p0702r1::Z'}} + X(std::initializer_list); // expected-note {{candidate template ignored: could not match 'std::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 --- 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 NE { struct E { - void begin(); // expected-note {{member is not a candidate because range type 'p0962r1::NE::E' has no 'end' member}} + void begin(); // expected-note {{member is not a candidate because range type 'NE::E' has no 'end' member}} }; int *end(E); } namespace NF { struct F { - void end(); // expected-note {{member is not a candidate because range type 'p0962r1::NF::F' has no 'begin' member}} + void end(); // expected-note {{member is not a candidate because range type 'NF::F' has no 'begin' member}} }; int *begin(F); } @@ -336,9 +336,9 @@ void use(NA::A a, NB::B b, NC::C c, ND::D d, NE::E e, NF::F f) { for (auto x : a) {} for (auto x : b) {} - for (auto x : c) {} // expected-error {{invalid range expression of type 'p0962r1::NC::C'; no viable 'end' function available}} - for (auto x : d) {} // expected-error {{invalid range expression of type 'p0962r1::ND::D'; no viable 'begin' function available}} - for (auto x : e) {} // expected-error {{invalid range expression of type 'p0962r1::NE::E'; no viable 'begin' function available}} - for (auto x : f) {} // expected-error {{invalid range expression of type 'p0962r1::NF::F'; no viable 'end' function available}} + for (auto x : c) {} // expected-error {{invalid range expression of type 'NC::C'; no viable 'end' function available}} + for (auto x : d) {} // expected-error {{invalid range expression of type 'ND::D'; no viable 'begin' function available}} + for (auto x : e) {} // expected-error {{invalid range expression of type 'NE::E'; no viable 'begin' function available}} + for (auto x : f) {} // expected-error {{invalid range expression of type 'NF::F'; no viable 'end' function available}} } } 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 --- 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 @@ 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 --- 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,9 +53,8 @@ } -// 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 --- 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,6 +18,12 @@ 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 @@ -52,6 +58,4 @@ 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 --- a/clang/test/Index/print-type.cpp +++ b/clang/test/Index/print-type.cpp @@ -199,7 +199,7 @@ // 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=Record] +// CHECK: VarDecl=autoTemplPointer:78:6 (Definition) [type=Specialization &> *] [typekind=Auto] [canonicaltype=Specialization &> *] [canonicaltypekind=Pointer] [isPOD=1] [pointeetype=Specialization &>] [pointeekind=Auto] // 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 --- a/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp +++ b/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp @@ -569,6 +569,52 @@ 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 --- a/clang/test/SemaCXX/cxx1z-decomposition.cpp +++ b/clang/test/SemaCXX/cxx1z-decomposition.cpp @@ -9,7 +9,7 @@ int a1[1], a2[2]; auto [] = a0; // expected-warning {{does not allow a decomposition group to be empty}} - auto [v1] = a0; // expected-error {{type 'A0' decomposes into 0 elements, but 1 name was provided}} + auto [v1] = a0; // expected-error {{type 'struct A0' decomposes into 0 elements, but 1 name was provided}} auto [] = a1; // expected-error {{type 'int [1]' decomposes into 1 element, but no names were provided}} expected-warning {{empty}} auto [v2] = a1; auto [v3, v4] = a1; // expected-error {{type 'int [1]' decomposes into 1 element, but 2 names were provided}} @@ -70,7 +70,7 @@ void bitfield() { struct { int a : 3, : 4, b : 5; } a; auto &[x, y] = a; - auto &[p, q, r] = a; // expected-error-re {{type '(unnamed struct at {{.*}})' decomposes into 2 elements, but 3 names were provided}} + auto &[p, q, r] = a; // expected-error-re {{type 'struct (unnamed struct at {{.*}})' decomposes into 2 elements, but 3 names were provided}} } void for_range() { diff --git a/clang/test/SemaCXX/deduced-return-type-cxx14.cpp b/clang/test/SemaCXX/deduced-return-type-cxx14.cpp --- a/clang/test/SemaCXX/deduced-return-type-cxx14.cpp +++ b/clang/test/SemaCXX/deduced-return-type-cxx14.cpp @@ -300,7 +300,7 @@ } struct NonLiteral { ~NonLiteral(); } nl; // cxx14-note {{user-provided destructor}} // cxx20_2b-note@-1 {{'NonLiteral' is not literal because its destructor is not constexpr}} - constexpr auto f2(int n) { return nl; } // expected-error {{return type 'Constexpr::NonLiteral' is not a literal type}} + constexpr auto f2(int n) { return nl; } // expected-error {{return type 'struct NonLiteral' is not a literal type}} } // It's not really clear whether these are valid, but this matches g++. diff --git a/clang/test/SemaCXX/friend.cpp b/clang/test/SemaCXX/friend.cpp --- a/clang/test/SemaCXX/friend.cpp +++ b/clang/test/SemaCXX/friend.cpp @@ -415,7 +415,7 @@ namespace qualified_friend_no_match { void f(int); // expected-note {{type mismatch at 1st parameter}} - template void f(T*); // expected-note {{could not match 'type-parameter-0-0 *' against 'double'}} + template void f(T*); // expected-note {{could not match 'T *' against 'double'}} struct X { friend void qualified_friend_no_match::f(double); // expected-error {{friend declaration of 'f' does not match any declaration in namespace 'qualified_friend_no_match'}} friend void qualified_friend_no_match::g(); // expected-error {{friend declaration of 'g' does not match any declaration in namespace 'qualified_friend_no_match'}} @@ -423,7 +423,7 @@ struct Y { void f(int); // expected-note {{type mismatch at 1st parameter}} - template void f(T*); // expected-note {{could not match 'type-parameter-0-0 *' against 'double'}} + template void f(T*); // expected-note {{could not match 'T *' against 'double'}} }; struct Z { friend void Y::f(double); // expected-error {{friend declaration of 'f' does not match any declaration in 'qualified_friend_no_match::Y'}} diff --git a/clang/test/SemaCXX/recovery-expr-type.cpp b/clang/test/SemaCXX/recovery-expr-type.cpp --- a/clang/test/SemaCXX/recovery-expr-type.cpp +++ b/clang/test/SemaCXX/recovery-expr-type.cpp @@ -133,7 +133,7 @@ template S(T t) -> S; void baz() { - bar(S(123)); // expected-error {{no matching conversion for functional-style cast from 'int' to 'test11::S<>'}} + bar(S(123)); // expected-error {{no matching conversion for functional-style cast from 'int' to 'S'}} } } // namespace test11 diff --git a/clang/test/SemaCXX/sizeless-1.cpp b/clang/test/SemaCXX/sizeless-1.cpp --- a/clang/test/SemaCXX/sizeless-1.cpp +++ b/clang/test/SemaCXX/sizeless-1.cpp @@ -581,7 +581,7 @@ auto auto_int8 = local_int8; auto auto_int16 = local_int16; #if __cplusplus >= 201703L - auto [auto_int8_a] = local_int8; // expected-error {{cannot decompose non-class, non-array type '__SVInt8_t'}} + auto [auto_int8_a] = local_int8; // expected-error {{cannot decompose non-class, non-array type 'svint8_t' (aka '__SVInt8_t')}} #endif #endif @@ -600,7 +600,7 @@ auto fn1 = [&local_int8](svint8_t x) { local_int8 = x; }; auto fn2 = [&local_int8](svint8_t *ptr) { *ptr = local_int8; }; #if __cplusplus >= 201703L - auto fn3 = [a(return_int8())] {}; // expected-error {{field has sizeless type '__SVInt8_t'}} + auto fn3 = [a(return_int8())] {}; // expected-error {{field has sizeless type 'svint8_t' (aka '__SVInt8_t')}} #endif auto fn4 = [local_int8](svint8_t *ptr) { *ptr = local_int8; }; // expected-error {{by-copy capture of variable 'local_int8' with sizeless type 'svint8_t'}} diff --git a/clang/test/SemaCXX/sugared-auto.cpp b/clang/test/SemaCXX/sugared-auto.cpp new file mode 100644 --- /dev/null +++ b/clang/test/SemaCXX/sugared-auto.cpp @@ -0,0 +1,43 @@ +// 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 --- a/clang/test/SemaTemplate/attributes.cpp +++ b/clang/test/SemaTemplate/attributes.cpp @@ -124,7 +124,8 @@ struct [[clang::preferred_name(iterator), clang::preferred_name(const_iterator)]] Iter {}; }; - auto it = MemberTemplate::Iter(); + template T desugar(T); + auto it = desugar(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 --- a/clang/test/SemaTemplate/friend.cpp +++ b/clang/test/SemaTemplate/friend.cpp @@ -50,7 +50,7 @@ namespace qualified_friend { void f(int); // expected-note 2{{type mismatch at 1st parameter}} - template void f(T*); // expected-note 2{{could not match 'type-parameter-0-0 *' against 'double'}} + template void f(T*); // expected-note 2{{could not match 'T *' against 'double'}} template void nondep(); template struct X1 { @@ -66,7 +66,7 @@ struct Y { void f(int); // expected-note 2{{type mismatch at 1st parameter}} - template void f(T*); // expected-note 2{{could not match 'type-parameter-0-0 *' against 'double'}} + template void f(T*); // expected-note 2{{could not match 'T *' against 'double'}} template void nondep(); }; diff --git a/clang/test/SemaTemplate/operator-template.cpp b/clang/test/SemaTemplate/operator-template.cpp --- 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); }