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 @@ -995,7 +995,7 @@ HI.LocalScope = ""; HI.Kind = index::SymbolKind::TypeAlias; HI.Definition = "template using AA = A"; - HI.Type = {"A", "type-parameter-0-0"}; // FIXME: should be 'T' + HI.Type = {"A", "T"}; HI.TemplateParameters = {{{"typename"}, std::string("T"), llvm::None}}; }}, {// Constant array diff --git a/clang/include/clang/AST/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h --- a/clang/include/clang/AST/ASTNodeTraverser.h +++ b/clang/include/clang/AST/ASTNodeTraverser.h @@ -414,6 +414,10 @@ // FIXME: ElaboratedType, DependentNameType, // DependentTemplateSpecializationType, ObjCObjectType + void VisitTypedefType(const TypedefType *T) { + if (T->hasDifferentUnderlyingType()) + Visit(T->desugar()); + } void VisitTypedefDecl(const TypedefDecl *D) { Visit(D->getUnderlyingType()); } void VisitEnumConstantDecl(const EnumConstantDecl *D) { 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 @@ -1734,6 +1734,15 @@ unsigned NumArgs; }; + class TypedefBitfields { + friend class TypedefType; + + unsigned : NumTypeBits; + + /// True if this typedef has underlying type different from decl. + unsigned hasDifferentUnderlyingType : 1; + }; + class SubstTemplateTypeParmPackTypeBitfields { friend class SubstTemplateTypeParmPackType; @@ -1808,6 +1817,7 @@ ConstantArrayTypeBitfields ConstantArrayTypeBits; AttributedTypeBitfields AttributedTypeBits; AutoTypeBitfields AutoTypeBits; + TypedefBitfields TypedefBits; BuiltinTypeBitfields BuiltinTypeBits; FunctionTypeBitfields FunctionTypeBits; ObjCObjectTypeBitfields ObjCObjectTypeBits; @@ -4416,6 +4426,14 @@ public: TypedefNameDecl *getDecl() const { return Decl; } + bool hasDifferentUnderlyingType() const { + return TypedefBits.hasDifferentUnderlyingType; + } + QualType getUnderlyingTypeIfDifferent() { + return hasDifferentUnderlyingType() + ? *reinterpret_cast(this + 1) + : QualType(); + } bool isSugared() const { return true; } QualType desugar() const; @@ -4917,10 +4935,13 @@ // The original type parameter. const TemplateTypeParmType *Replaced; + QualType Replacement; - SubstTemplateTypeParmType(const TemplateTypeParmType *Param, QualType Canon) - : Type(SubstTemplateTypeParm, Canon, Canon->getDependence()), - Replaced(Param) {} + SubstTemplateTypeParmType(const TemplateTypeParmType *Param, + QualType Replacement) + : Type(SubstTemplateTypeParm, Replacement.getCanonicalType(), + Replacement->getDependence()), + Replaced(Param), Replacement(Replacement) {} public: /// Gets the template parameter that was substituted for. @@ -4930,9 +4951,7 @@ /// Gets the type that was substituted for the template /// parameter. - QualType getReplacementType() const { - return getCanonicalTypeInternal(); - } + QualType getReplacementType() const { return Replacement; } bool isSugared() const { return true; } QualType desugar() const { return getReplacementType(); } diff --git a/clang/include/clang/AST/TypeProperties.td b/clang/include/clang/AST/TypeProperties.td --- a/clang/include/clang/AST/TypeProperties.td +++ b/clang/include/clang/AST/TypeProperties.td @@ -379,16 +379,12 @@ def : Property<"declaration", DeclRef> { let Read = [{ node->getDecl() }]; } - def : Property<"canonicalType", Optional> { - let Read = [{ makeOptionalFromNullable(node->getCanonicalTypeInternal()) }]; + def : Property<"underlyingType", QualType> { + let Read = [{ node->desugar() }]; } def : Creator<[{ - QualType finalCanonicalType = - canonicalType ? ctx.getCanonicalType(*canonicalType) - : QualType(); - return ctx.getTypedefType(cast(declaration), - finalCanonicalType); + return ctx.getTypedefType(cast(declaration), underlyingType); }]>; } diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -469,6 +469,9 @@ /// forward slash (/) elsewhere. bool UseTargetPathSeparator = false; + /// Resugar template specializations. + bool Resugar = true; + LangOptions(); /// Set language defaults for the given input language and diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -5744,6 +5744,9 @@ LangOpts<"RecoveryASTType">, DefaultTrue, NegFlag, PosFlag>; +def fno_resugar : Flag<["-"], "fno-resugar">, + HelpText<"Do not resugar template specializations">, + MarshallingInfoNegativeFlag>; let Group = Action_Group in { 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 @@ -7838,9 +7838,9 @@ void NoteAllFoundTemplates(TemplateName Name); - QualType CheckTemplateIdType(TemplateName Template, + QualType CheckTemplateIdType(NestedNameSpecifier *NNS, TemplateName Template, SourceLocation TemplateLoc, - TemplateArgumentListInfo &TemplateArgs); + TemplateArgumentListInfo &TemplateArgs); TypeResult ActOnTemplateIdType(Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, @@ -8655,6 +8655,23 @@ TDK_CUDATargetMismatch }; + TemplateDeductionResult DeduceTemplateArguments( + TemplateParameterList *TemplateParams, ArrayRef Ps, + ArrayRef As, sema::TemplateDeductionInfo &Info, + SmallVectorImpl &Deduced, + bool NumberOfArgumentsMustMatch); + + TemplateDeductionResult + DeduceTemplateArguments(TemplateParameterList *TemplateParams, + const TemplateArgumentList &ParamList, + const TemplateArgumentList &ArgList, + sema::TemplateDeductionInfo &Info, + SmallVectorImpl &Deduced) { + return DeduceTemplateArguments(TemplateParams, ParamList.asArray(), + ArgList.asArray(), Info, Deduced, + /*NumberOfArgumentsMustMatch=*/false); + } + TemplateDeductionResult DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, const TemplateArgumentList &TemplateArgs, @@ -9530,6 +9547,11 @@ } }; + QualType resugar(const NestedNameSpecifier *NNS, QualType T); + QualType getResugaredDependentTemplateSpecializationType( + NestedNameSpecifier *NNS, ElaboratedTypeKeyword Keyword, + const IdentifierInfo *Name, const TemplateArgumentListInfo &Args); + void PerformPendingInstantiations(bool LocalOnly = false); TypeSourceInfo *SubstType(TypeSourceInfo *T, 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 @@ -2358,12 +2358,12 @@ return getTypeInfo(cast(T)->desugar().getTypePtr()); case Type::Typedef: { - const TypedefNameDecl *Typedef = cast(T)->getDecl(); - TypeInfo Info = getTypeInfo(Typedef->getUnderlyingType().getTypePtr()); + const auto *TT = cast(T); + TypeInfo Info = getTypeInfo(TT->desugar().getTypePtr()); // If the typedef has an aligned attribute on it, it overrides any computed // alignment we have. This violates the GCC documentation (which says that // attribute(aligned) can only round up) but matches its implementation. - if (unsigned AttrAlign = Typedef->getMaxAlignment()) { + if (unsigned AttrAlign = TT->getDecl()->getMaxAlignment()) { Align = AttrAlign; AlignRequirement = AlignRequirementKind::RequiredByTypedef; } else { @@ -4618,14 +4618,24 @@ /// specified typedef name decl. QualType ASTContext::getTypedefType(const TypedefNameDecl *Decl, QualType Underlying) const { - if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); - + if (!Decl->TypeForDecl) { + if (Underlying.isNull()) + Underlying = Decl->getUnderlyingType(); + auto *newType = new (*this, TypeAlignment) TypedefType( + Type::Typedef, Decl, QualType(), getCanonicalType(Underlying)); + Decl->TypeForDecl = newType; + Types.push_back(newType); + return QualType(newType, 0); + } if (Underlying.isNull()) - Underlying = Decl->getUnderlyingType(); - QualType Canonical = getCanonicalType(Underlying); - auto *newType = new (*this, TypeAlignment) - TypedefType(Type::Typedef, Decl, Underlying, Canonical); - Decl->TypeForDecl = newType; + return QualType(Decl->TypeForDecl, 0); + if (Decl->getUnderlyingType() == Underlying) + return QualType(Decl->TypeForDecl, 0); + + // FIXME: Unique + void *Mem = Allocate(sizeof(TypedefType) + sizeof(QualType), TypeAlignment); + auto *newType = new (Mem) TypedefType(Type::Typedef, Decl, Underlying, + getCanonicalType(Underlying)); Types.push_back(newType); return QualType(newType, 0); } @@ -4737,9 +4747,6 @@ QualType ASTContext::getSubstTemplateTypeParmType(const TemplateTypeParmType *Parm, QualType Replacement) const { - assert(Replacement.isCanonical() - && "replacement types must always be canonical"); - llvm::FoldingSetNodeID ID; SubstTemplateTypeParmType::Profile(ID, Parm, Replacement); void *InsertPos = nullptr; @@ -4869,6 +4876,25 @@ } #endif +static bool isTypeAlias(const TemplateDecl *TD) { + if (!TD) + return false; + switch (TD->getKind()) { + case TemplateDecl::TypeAliasTemplate: + return true; + case TemplateDecl::BuiltinTemplate: { + const auto *BT = cast(TD); + if (BT->getBuiltinTemplateKind() == + BuiltinTemplateKind::BTK__make_integer_seq) + return true; + return false; + } + default: + return false; + }; + llvm_unreachable("unknown template kind"); +} + QualType ASTContext::getTemplateSpecializationType(TemplateName Template, ArrayRef Args, @@ -4879,8 +4905,7 @@ if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) Template = QTN->getUnderlyingTemplate(); - bool IsTypeAlias = - isa_and_nonnull(Template.getAsTemplateDecl()); + bool IsTypeAlias = isTypeAlias(Template.getAsTemplateDecl()); QualType CanonType; if (!Underlying.isNull()) CanonType = getCanonicalType(Underlying); @@ -7194,8 +7219,7 @@ void ASTContext::setCFConstantStringType(QualType T) { const auto *TD = T->castAs(); CFConstantStringTypeDecl = cast(TD->getDecl()); - const auto *TagType = - CFConstantStringTypeDecl->getUnderlyingType()->castAs(); + const auto *TagType = TD->castAs(); CFConstantStringTagDecl = TagType->getDecl(); } 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 @@ -1361,8 +1361,12 @@ Expected ToDeclOrErr = import(T->getDecl()); if (!ToDeclOrErr) return ToDeclOrErr.takeError(); + ExpectedType ToUnderlyingTypeOrErr = import(T->desugar()); + if (!ToUnderlyingTypeOrErr) + return ToUnderlyingTypeOrErr.takeError(); - return Importer.getToContext().getTypeDeclType(*ToDeclOrErr); + return Importer.getToContext().getTypedefType(*ToDeclOrErr, + *ToUnderlyingTypeOrErr); } ExpectedType ASTNodeImporter::VisitTypeOfExprType(const TypeOfExprType *T) { diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp --- a/clang/lib/AST/ASTStructuralEquivalence.cpp +++ b/clang/lib/AST/ASTStructuralEquivalence.cpp @@ -961,7 +961,9 @@ case Type::Typedef: if (!IsStructurallyEquivalent(Context, cast(T1)->getDecl(), - cast(T2)->getDecl())) + cast(T2)->getDecl()) || + !IsStructurallyEquivalent(Context, cast(T1)->desugar(), + cast(T2)->desugar())) return false; break; diff --git a/clang/lib/AST/FormatString.cpp b/clang/lib/AST/FormatString.cpp --- a/clang/lib/AST/FormatString.cpp +++ b/clang/lib/AST/FormatString.cpp @@ -976,10 +976,10 @@ bool FormatSpecifier::namedTypeToLengthModifier(QualType QT, LengthModifier &LM) { assert(isa(QT) && "Expected a TypedefType"); - const TypedefNameDecl *Typedef = cast(QT)->getDecl(); + const auto *TT = cast(QT); - for (;;) { - const IdentifierInfo *Identifier = Typedef->getIdentifier(); + do { + const IdentifierInfo *Identifier = TT->getDecl()->getIdentifier(); if (Identifier->getName() == "size_t") { LM.setKind(LengthModifier::AsSizeT); return true; @@ -997,12 +997,6 @@ LM.setKind(LengthModifier::AsPtrDiff); return true; } - - QualType T = Typedef->getUnderlyingType(); - if (!isa(T)) - break; - - Typedef = cast(T)->getDecl(); - } + } while (TT = TT->desugar()->getAs()); return false; } diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp --- a/clang/lib/AST/JSONNodeDumper.cpp +++ b/clang/lib/AST/JSONNodeDumper.cpp @@ -530,6 +530,8 @@ void JSONNodeDumper::VisitTypedefType(const TypedefType *TT) { JOS.attribute("decl", createBareDeclRef(TT->getDecl())); + if (TT->hasDifferentUnderlyingType()) + JOS.attribute("type", createQualType(TT->desugar())); } void JSONNodeDumper::VisitFunctionType(const FunctionType *T) { diff --git a/clang/lib/AST/QualTypeNames.cpp b/clang/lib/AST/QualTypeNames.cpp --- a/clang/lib/AST/QualTypeNames.cpp +++ b/clang/lib/AST/QualTypeNames.cpp @@ -253,6 +253,8 @@ true /*FullyQualified*/, WithGlobalNsPrefix); } else if (const auto *TDD = dyn_cast(Type)) { + if (TDD->hasDifferentUnderlyingType()) + return Scope; return TypeName::createNestedNameSpecifier(Ctx, TDD->getDecl(), true /*FullyQualified*/, WithGlobalNsPrefix); @@ -325,7 +327,10 @@ Decl *Decl = nullptr; // There are probably other cases ... if (const auto *TDT = dyn_cast(TypePtr)) { - Decl = TDT->getDecl(); + if (TDT->hasDifferentUnderlyingType()) + Decl = TypePtr->getAsCXXRecordDecl(); + else + Decl = TDT->getDecl(); } else if (const auto *TagDeclType = dyn_cast(TypePtr)) { Decl = TagDeclType->getDecl(); } else if (const auto *TST = dyn_cast(TypePtr)) { diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -1546,7 +1546,10 @@ } void TextNodeDumper::VisitTypedefType(const TypedefType *T) { - dumpDeclRef(T->getDecl()); + const TypedefNameDecl *D = T->getDecl(); + dumpDeclRef(D); + if (T->hasDifferentUnderlyingType()) + dumpType(T->desugar()); } void TextNodeDumper::VisitUnaryTransformType(const UnaryTransformType *T) { 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 @@ -3434,14 +3434,19 @@ } TypedefType::TypedefType(TypeClass tc, const TypedefNameDecl *D, - QualType underlying, QualType can) - : Type(tc, can, toSemanticDependence(underlying->getDependence())), + QualType Underlying, QualType can) + : Type(tc, can, toSemanticDependence(can->getDependence())), Decl(const_cast(D)) { assert(!isa(can) && "Invalid canonical type"); + TypedefBits.hasDifferentUnderlyingType = !Underlying.isNull(); + if (hasDifferentUnderlyingType()) + *reinterpret_cast(this + 1) = Underlying; } QualType TypedefType::desugar() const { - return getDecl()->getUnderlyingType(); + return hasDifferentUnderlyingType() + ? *reinterpret_cast(this + 1) + : Decl->getUnderlyingType(); } UsingType::UsingType(const UsingShadowDecl *Found, QualType Underlying, diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -1264,10 +1264,11 @@ assert(Ty->isTypeAlias()); llvm::DIType *Src = getOrCreateType(Ty->getAliasedType(), Unit); - auto *AliasDecl = - cast(Ty->getTemplateName().getAsTemplateDecl()) - ->getTemplatedDecl(); + const TemplateDecl *TD = Ty->getTemplateName().getAsTemplateDecl(); + if (isa(TD)) + return Src; + const auto *AliasDecl = cast(TD)->getTemplatedDecl(); if (AliasDecl->hasAttr()) return Src; 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 @@ -736,6 +736,7 @@ QualType T = Context.getTypeDeclType(cast(SD->getUnderlyingDecl())); + T = resugar(SS.getScopeRep(), T); if (T->isEnumeralType()) Diag(IdInfo.IdentifierLoc, diag::warn_cxx98_compat_enum_nested_name_spec); @@ -875,17 +876,19 @@ QualType T = BuildDecltypeType(DS.getRepAsExpr()); if (T.isNull()) return true; + T = resugar(SS.getScopeRep(), T); + + TypeLocBuilder TLB; + DecltypeTypeLoc DecltypeTL = TLB.push(T); + DecltypeTL.setDecltypeLoc(DS.getTypeSpecTypeLoc()); + DecltypeTL.setRParenLoc(DS.getTypeofParensRange().getEnd()); if (!T->isDependentType() && !T->getAs()) { Diag(DS.getTypeSpecTypeLoc(), diag::err_expected_class_or_namespace) - << T << getLangOpts().CPlusPlus; + << T << getLangOpts().CPlusPlus; return true; } - TypeLocBuilder TLB; - DecltypeTypeLoc DecltypeTL = TLB.push(T); - DecltypeTL.setDecltypeLoc(DS.getTypeSpecTypeLoc()); - DecltypeTL.setRParenLoc(DS.getTypeofParensRange().getEnd()); SS.Extend(Context, SourceLocation(), TLB.getTypeLocInContext(Context, T), ColonColonLoc); return false; @@ -975,18 +978,11 @@ // We were able to resolve the template name to an actual template. // Build an appropriate nested-name-specifier. - QualType T = CheckTemplateIdType(Template, TemplateNameLoc, TemplateArgs); + QualType T = CheckTemplateIdType(SS.getScopeRep(), Template, TemplateNameLoc, + TemplateArgs); if (T.isNull()) return true; - // Alias template specializations can produce types which are not valid - // nested name specifiers. - if (!T->isDependentType() && !T->getAs()) { - Diag(TemplateNameLoc, diag::err_nested_name_spec_non_tag) << T; - NoteAllFoundTemplates(Template); - return true; - } - // Provide source-location information for the template specialization type. TypeLocBuilder Builder; TemplateSpecializationTypeLoc SpecTL @@ -998,6 +994,13 @@ for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I) SpecTL.setArgLocInfo(I, TemplateArgs[I].getLocInfo()); + // Alias template specializations can produce types which are not valid + // nested name specifiers. + if (!T->isDependentType() && !T->getAs()) { + Diag(TemplateNameLoc, diag::err_nested_name_spec_non_tag) << T; + NoteAllFoundTemplates(Template); + return true; + } SS.Extend(Context, TemplateKWLoc, Builder.getTypeLocInContext(Context, T), CCLoc); diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp --- a/clang/lib/Sema/SemaCoroutine.cpp +++ b/clang/lib/Sema/SemaCoroutine.cpp @@ -92,7 +92,7 @@ // Build the template-id. QualType CoroTrait = - S.CheckTemplateIdType(TemplateName(CoroTraits), KwLoc, Args); + S.CheckTemplateIdType(nullptr, TemplateName(CoroTraits), KwLoc, Args); if (CoroTrait.isNull()) return QualType(); if (S.RequireCompleteType(KwLoc, CoroTrait, @@ -170,7 +170,7 @@ // Build the template-id. QualType CoroHandleType = - S.CheckTemplateIdType(TemplateName(CoroHandle), Loc, Args); + S.CheckTemplateIdType(nullptr, TemplateName(CoroHandle), Loc, Args); if (CoroHandleType.isNull()) return QualType(); if (S.RequireCompleteType(Loc, CoroHandleType, 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 @@ -491,6 +491,8 @@ DiagnoseUseOfDecl(IIDecl, NameLoc); T = Context.getTypeDeclType(TD); + if (SS && SS->isValid()) + T = resugar(SS->getScopeRep(), T); MarkAnyDeclReferenced(TD->getLocation(), TD, /*OdrUse=*/false); } else if (ObjCInterfaceDecl *IDecl = dyn_cast(IIDecl)) { (void)DiagnoseUseOfDecl(IDecl, NameLoc); 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 @@ -1031,7 +1031,8 @@ } // Build the template-id. - QualType TraitTy = S.CheckTemplateIdType(TemplateName(TraitTD), Loc, Args); + QualType TraitTy = + S.CheckTemplateIdType(nullptr, TemplateName(TraitTD), Loc, Args); if (TraitTy.isNull()) return true; if (!S.isCompleteType(Loc, TraitTy)) { @@ -11563,8 +11564,8 @@ Args.addArgument(TemplateArgumentLoc(TemplateArgument(Element), Context.getTrivialTypeSourceInfo(Element, Loc))); - return Context.getCanonicalType( - CheckTemplateIdType(TemplateName(StdInitializerList), Loc, Args)); + return Context.getCanonicalType(CheckTemplateIdType( + nullptr, TemplateName(StdInitializerList), Loc, Args)); } bool Sema::isInitListConstructor(const FunctionDecl *Ctor) { diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -5685,9 +5685,6 @@ Sema::CCEKind CCE, bool RequireInt, NamedDecl *Dest) { - assert(S.getLangOpts().CPlusPlus11 && - "converted constant expression outside C++11"); - if (checkPlaceholderForOverload(S, From)) return ExprError(); 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 @@ -11,6 +11,7 @@ #include "TreeTransform.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/ASTLambda.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclFriend.h" #include "clang/AST/DeclTemplate.h" @@ -90,6 +91,741 @@ return Depth; } +namespace { +class Resugarer : public TreeTransform { + using inherited = TreeTransform; + + MultiLevelTemplateArgumentList *MLTAL = nullptr; + + using DCToArgsMap = + llvm::DenseMap>; + DCToArgsMap *DCToArgs = nullptr; + SmallVector, 4> DeducedArgsBuf; + +public: + struct BuildMLTALRAII { + BuildMLTALRAII(Resugarer &R, const DeclContext *DC) + : BuildMLTALRAII(R, DC, nullptr){}; + BuildMLTALRAII(Resugarer &R, const DeclContext *DC, + const ArrayRef &Args) + : BuildMLTALRAII(R, DC, &Args){}; + ~BuildMLTALRAII() { R->MLTAL = OldMLTAL; } + + private: + BuildMLTALRAII(Resugarer &R, const DeclContext *DC, + const ArrayRef *Args) + : R(&R), OldMLTAL(std::exchange(R.MLTAL, &MLTAL)) { + if (Args) + MLTAL.addOuterTemplateArguments(*Args); + auto addDC = [&](const DeclContext *DC) { + MLTAL.addOuterTemplateArguments( + R.DCToArgs ? R.DCToArgs->lookup(DC) + : None); // FIXME: add trailing retained outer + }; + while(DC) { + switch (Decl::Kind DK = DC->getDeclKind()) { + case Decl::Kind::ClassTemplatePartialSpecialization: + case Decl::Kind::ClassTemplateSpecialization: { + const auto *CTS = cast(DC); + if (!CTS->isClassScopeExplicitSpecialization()) { + if (CTS->getSpecializationKind() == TSK_ExplicitSpecialization && + DK != Decl::Kind::ClassTemplatePartialSpecialization) + return; + addDC(DC); + if (CTS->getSpecializedTemplate()->isMemberSpecialization()) + return; + break; + } + LLVM_FALLTHROUGH; + } + case Decl::Kind::CXXRecord: { + const auto *RD = cast(DC); + if (const auto *CT = RD->getDescribedClassTemplate()) { + addDC(DC); + if (CT->isMemberSpecialization()) + return; + } + break; + } + case Decl::Kind::CXXConstructor: + case Decl::Kind::CXXDestructor: + case Decl::Kind::CXXConversion: + case Decl::Kind::CXXMethod: + case Decl::Kind::CXXDeductionGuide: + case Decl::Kind::Function: { + const auto *FD = cast(DC); + if (FD->getTemplateSpecializationKindForInstantiation() == + TSK_ExplicitSpecialization) + return; + + if (FD->getTemplateSpecializationKind() == + TSK_ExplicitSpecialization) { + } else if (const TemplateArgumentList *TemplateArgs = + FD->getTemplateSpecializationArgs()) { + addDC(DC); + if (FD->getPrimaryTemplate()->isMemberSpecialization() || + isGenericLambdaCallOperatorOrStaticInvokerSpecialization(FD)) + return; + } else if (FD->getDescribedFunctionTemplate()) { + addDC(DC); + } + if (FD->getFriendObjectKind() && + FD->getDeclContext()->isFileContext()) { + DC = FD->getLexicalDeclContext(); + continue; + } + break; + } + case Decl::Kind::TranslationUnit: + case Decl::Kind::Namespace: + case Decl::Kind::Export: + return; + case Decl::Kind::LinkageSpec: + break; + default: + cast(DC)->dumpColor(); + llvm_unreachable("Unexpected Decl Kind"); + } + DC = DC->getParent(); + } + } + + Resugarer *R; + MultiLevelTemplateArgumentList MLTAL, *OldMLTAL; + }; + + // FIXME: very incomplete, this should go in CheckTemplateArgument + TemplateArgument ConvertTemplateArgument(const TemplateArgument &Old) { + switch (Old.getKind()) { + case TemplateArgument::Type: { + QualType T = Old.getAsType(); + + // FIXME: copypasta + if (SemaRef.getLangOpts().ObjCAutoRefCount && T->isObjCLifetimeType() && + !T.getObjCLifetime()) { + Qualifiers Qs; + Qs.setObjCLifetime(Qualifiers::OCL_Strong); + T = SemaRef.Context.getQualifiedType(T, Qs); + } + + return TemplateArgument(T); + } + default: + return Old; + } + llvm_unreachable("unexpected template kind"); + } + + struct NamingContextRAII { + NamingContextRAII(Resugarer &R, const NestedNameSpecifier *NNS) + : R(&R), OldDCToArgs(std::exchange(R.DCToArgs, &DCToArgs)), + OldDeducedArgsBufSize(R.DeducedArgsBuf.size()) { + auto addDC = [&](const DeclContext *DC, + ArrayRef Args = {}) { + SmallVector ConvertedArgs(Args.size()); + bool Changed = false; + for (unsigned I = 0; I < Args.size(); ++I) { + TemplateArgument Old = Args[I]; + TemplateArgument New = R.ConvertTemplateArgument(Old); + Changed |= !New.structurallyEquals(Old); + ConvertedArgs[I] = New; + } + if (Changed) { + R.DeducedArgsBuf.emplace_back(std::move(ConvertedArgs)); + DCToArgs.try_emplace(DC, R.DeducedArgsBuf.back()); + } else { + DCToArgs.try_emplace(DC, Args); + } + }; + bool InheritOldNamingContext = true; + for (/**/; NNS; NNS = NNS->getPrefix()) { + auto NK = NNS->getKind(); + if (NK == NestedNameSpecifier::Global || + NK == NestedNameSpecifier::Namespace || + NK == NestedNameSpecifier::NamespaceAlias) { + InheritOldNamingContext = false; + break; + } + switch (NK) { + case NestedNameSpecifier::Identifier: + case NestedNameSpecifier::Super: + break; + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: { + const DeclContext *IDC; + const TemplateSpecializationType *TST; + { + const clang::Type *NT = NNS->getAsType(); + QualType NTCanon = NT->getCanonicalTypeInternal(); + switch (NTCanon->getTypeClass()) { + case Type::Record: { + IDC = NT->getAsRecordDecl(); + TST = NT->getAs(); + while (TST && TST->isTypeAlias()) + TST = + TST->getAliasedType()->getAs(); + break; + } + case Type::InjectedClassName: { + const auto *ICN = cast(NTCanon); + IDC = ICN->getDecl(); + TST = ICN->getInjectedTST(); + break; + } + case Type::TemplateSpecialization: + case Type::DependentTemplateSpecialization: + case Type::TemplateTypeParm: + case Type::DependentName: + continue; + default: + NTCanon.dump(); + llvm_unreachable(""); + } + } + switch (auto RDK = IDC->getDeclKind()) { + case Decl::CXXRecord: + continue; + case Decl::ClassTemplateSpecialization: + case Decl::ClassTemplatePartialSpecialization: { + if (!TST) { + DCToArgs.try_emplace(IDC); + continue; + } + assert(!TST->isTypeAlias()); + ArrayRef Args = TST->template_arguments(); + if (RDK == Decl::ClassTemplatePartialSpecialization) { + deduceClassTemplatePartialSpecialization( + cast(IDC), Args, IDC); + continue; + } + if (auto *CTPSD = + cast(IDC) + ->getSpecializedTemplateOrPartial() + .dyn_cast()) + deduceClassTemplatePartialSpecialization(CTPSD, Args, IDC); + else + addDC(IDC, Args); + continue; + } + default: + llvm_unreachable(""); + } + } + default: + llvm_unreachable(""); + } + } + if (InheritOldNamingContext && OldDCToArgs) { + for (auto &&I : *OldDCToArgs) { + auto &R = DCToArgs[I.first]; + if (R.empty()) + R = I.second; + } + } + } + ~NamingContextRAII() { + R->DCToArgs = OldDCToArgs; + R->DeducedArgsBuf.resize(OldDeducedArgsBufSize); + } + + private: + Resugarer *R; + DCToArgsMap DCToArgs, *OldDCToArgs; + size_t OldDeducedArgsBufSize; + + void deduceClassTemplatePartialSpecialization( + const ClassTemplatePartialSpecializationDecl *D, + ArrayRef Args, const DeclContext *DC) { +#if 1 + DCToArgs.try_emplace(DC); +#else + TemplateDeductionInfo Info(SourceLocation{}); + TemplateParameterList *TPL = D->getTemplateParameters(); + SmallVector Deduced(TPL->size()); + Sema::TemplateDeductionResult Res = R->SemaRef.DeduceTemplateArguments( + TPL, D->getTemplateArgs(), + TemplateArgumentList(TemplateArgumentList::OnStackType{}, Args), Info, + Deduced); + if (Res != Sema::TDK_Success) + llvm_unreachable("Unexpected deduction failure"); + DCToArgs.try_emplace( + DC, R->DeducedArgsBuf.emplace_back(Deduced.begin(), Deduced.end())); +#endif + } + }; + + Resugarer(Sema &SemaRef) : inherited(SemaRef) {} + + bool AlwaysRebuild() { return false; } + bool ReplacingOriginal() { return false; } + + QualType TransformElaboratedType(TypeLocBuilder &TLB, ElaboratedTypeLoc TL) { + const ElaboratedType *T = TL.getTypePtr(); + NestedNameSpecifierLoc QualifierLoc; + QualifierLoc = TransformNestedNameSpecifierLoc(TL.getQualifierLoc()); + + NestedNameSpecifier *NNS = QualifierLoc.getNestedNameSpecifier(); + QualType NamedT; + { + NamingContextRAII _(*this, NNS); + NamedT = TransformType(TLB, TL.getNamedTypeLoc()); + } + + QualType Result = + QualifierLoc != TL.getQualifierLoc() || NamedT != T->getNamedType() + ? SemaRef.Context.getElaboratedType(T->getKeyword(), NNS, NamedT) + : TL.getType(); + + ElaboratedTypeLoc NewTL = TLB.push(Result); + NewTL.setElaboratedKeywordLoc(TL.getElaboratedKeywordLoc()); + NewTL.setQualifierLoc(QualifierLoc); + return Result; + } + + Decl *TransformDecl(SourceLocation Loc, Decl *D) const { return D; } + + QualType TransformSubstTemplateTypeParmType(TypeLocBuilder &TLB, + SubstTemplateTypeParmTypeLoc TL) { + const SubstTemplateTypeParmType *T = TL.getTypePtr(); + const TemplateTypeParmType *Replaced = T->getReplacedParameter(); + + unsigned Depth = Replaced->getDepth(), Index = Replaced->getIndex(); + if (!MLTAL || !MLTAL->hasTemplateArgument(Depth, Index)) { + auto NewTL = TLB.push(TL.getType()); + NewTL.setNameLoc(TL.getNameLoc()); + return TL.getType(); + } + + QualType Replacement = + (*MLTAL)(Depth, Index).getAsType().getNonPackExpansionType(); + if (!SemaRef.Context.hasSameType(Replacement, T->getReplacementType())) { + if (Replacement->getTypeClass() != Type::Decltype && + T->getReplacementType()->getTypeClass() != Type::Decltype) { + Replacement.dump(); + T->getReplacementType().dump(); + assert(false); + } + } + QualType Result = + SemaRef.Context.getSubstTemplateTypeParmType(Replaced, Replacement); + auto NewTL = TLB.push(Result); + NewTL.setNameLoc(TL.getNameLoc()); + return Result; + } + + using inherited::TransformTemplateSpecializationType; + + QualType TransformTemplateSpecializationType(TypeLocBuilder &TLB, + TemplateSpecializationTypeLoc TL, + TemplateName N) { + const TemplateSpecializationType *T = TL.getTypePtr(); + + TemplateArgumentListInfo NewArgs; + NewArgs.setLAngleLoc(TL.getLAngleLoc()); + NewArgs.setRAngleLoc(TL.getRAngleLoc()); + using Iter = + TemplateArgumentLocContainerIterator; + if (TransformTemplateArguments(Iter(TL, 0), Iter(TL, TL.getNumArgs()), + NewArgs)) + llvm_unreachable(""); + + TemplateDecl *TD = N.getAsTemplateDecl(); + QualType Result; + if (T->isTypeAlias()) { + QualType Underlying; + { + SmallVector Args(NewArgs.size()); + for (int I = 0; I < Args.size(); ++I) + Args[I] = NewArgs[I].getArgument(); + BuildMLTALRAII _(*this, TD->getDeclContext(), Args); + Underlying = TransformType(T->getAliasedType()); + } + Result = + SemaRef.Context.getTemplateSpecializationType(N, NewArgs, Underlying); + } else { + Result = SemaRef.Context.getTemplateSpecializationType(N, NewArgs, + TL.getType()); + } + TemplateSpecializationTypeLoc NewTL = + TLB.push(Result); + NewTL.setTemplateKeywordLoc(TL.getTemplateKeywordLoc()); + NewTL.setTemplateNameLoc(TL.getTemplateNameLoc()); + NewTL.setLAngleLoc(TL.getLAngleLoc()); + NewTL.setRAngleLoc(TL.getRAngleLoc()); + for (unsigned i = 0, e = NewArgs.size(); i != e; ++i) + NewTL.setArgLocInfo(i, NewArgs[i].getLocInfo()); + return Result; + } + + QualType TransformDependentTemplateSpecializationType( + TypeLocBuilder &TLB, DependentTemplateSpecializationTypeLoc TL) { + const DependentTemplateSpecializationType *T = TL.getTypePtr(); + TemplateArgumentListInfo NewTemplateArgs; + NewTemplateArgs.setLAngleLoc(TL.getLAngleLoc()); + NewTemplateArgs.setRAngleLoc(TL.getRAngleLoc()); + typedef TemplateArgumentLocContainerIterator< + DependentTemplateSpecializationTypeLoc> + ArgIterator; + if (getDerived().TransformTemplateArguments( + ArgIterator(TL, 0), ArgIterator(TL, TL.getNumArgs()), + NewTemplateArgs)) + return QualType(); + + // FIXME: don't rebuild if all the template arguments are the same. + + QualType Result = SemaRef.Context.getDependentTemplateSpecializationType( + T->getKeyword(), T->getQualifier(), T->getIdentifier(), + NewTemplateArgs); + + DependentTemplateSpecializationTypeLoc NewTL = + TLB.push(Result); + NewTL.setElaboratedKeywordLoc(TL.getElaboratedKeywordLoc()); + NewTL.setQualifierLoc(TL.getQualifierLoc()); + NewTL.setTemplateKeywordLoc(TL.getTemplateKeywordLoc()); + NewTL.setTemplateNameLoc(TL.getTemplateNameLoc()); + NewTL.setLAngleLoc(TL.getLAngleLoc()); + NewTL.setRAngleLoc(TL.getRAngleLoc()); + for (unsigned i = 0, e = NewTemplateArgs.size(); i != e; ++i) + NewTL.setArgLocInfo(i, NewTemplateArgs[i].getLocInfo()); + return Result; + } + + TypeSourceInfo *TransformTSIInObjectScope(TypeLoc TL, QualType, NamedDecl *, + CXXScopeSpec &) { + TypeLocBuilder TLB; + QualType Result = getDerived().TransformType(TLB, TL); + return !Result.isNull() ? TLB.getTypeSourceInfo(SemaRef.Context, Result) + : nullptr; + } + + QualType TransformDependentTemplateSpecializationType( + TypeLocBuilder&, DependentTemplateSpecializationTypeLoc, TemplateName, + CXXScopeSpec&) { + llvm_unreachable("unused"); + } + + TemplateName TransformTemplateName(CXXScopeSpec &SS, TemplateName Name, + SourceLocation NameLoc, + QualType ObjectType = QualType(), + NamedDecl *FirstQualifierInScope = nullptr, + bool AllowInjectedClassName = false) { + if (Name.getKind() == TemplateName::NameKind::SubstTemplateTemplateParm) + return Name; + return inherited::TransformTemplateName(SS, Name, NameLoc, ObjectType, + FirstQualifierInScope, + AllowInjectedClassName); + } + + QualType TransformDependentNameType(TypeLocBuilder &TLB, + DependentNameTypeLoc TL, + bool DeducedTSTContext = false) { + const DependentNameType *T = TL.getTypePtr(); + + NestedNameSpecifierLoc QualifierLoc = + TransformNestedNameSpecifierLoc(TL.getQualifierLoc()); + assert(QualifierLoc); + assert(QualifierLoc.getNestedNameSpecifier()->isDependent()); + QualType Result = SemaRef.Context.getDependentNameType( + T->getKeyword(), QualifierLoc.getNestedNameSpecifier(), + T->getIdentifier()); + DependentNameTypeLoc NewTL = TLB.push(Result); + NewTL.setElaboratedKeywordLoc(TL.getElaboratedKeywordLoc()); + NewTL.setQualifierLoc(QualifierLoc); + NewTL.setNameLoc(TL.getNameLoc()); + return Result; + } + + QualType TransformTypedefType(TypeLocBuilder &TLB, TypedefTypeLoc TL) { + const TypedefType *T = TL.getTypePtr(); + const TypedefNameDecl *D = T->getDecl(); + QualType Underlying = D->getUnderlyingType(); + BuildMLTALRAII DCScope(*this, D->getDeclContext()); + QualType NewUnderlying = TransformType(D->getUnderlyingType()); + QualType Result = TL.getType(); + if (NewUnderlying != Underlying) + Result = SemaRef.Context.getTypedefType(D, NewUnderlying); + TypedefTypeLoc NewTL = TLB.push(Result); + NewTL.setNameLoc(TL.getNameLoc()); + return Result; + } + + ExprResult TransformExpr(Expr *E) { return E; } + + bool TransformTemplateArgument(const TemplateArgumentLoc &Input, + TemplateArgumentLoc &Output, bool) { + const TemplateArgument &Arg = Input.getArgument(); + switch (Arg.getKind()) { + case TemplateArgument::Null: + llvm_unreachable("Unexpected Null TemplateArgument"); + case TemplateArgument::Pack: { + ArrayRef Args = Arg.getPackAsArray(); + TemplateArgumentListInfo Ins; + for (auto &&I : Arg.getPackAsArray()) { + TemplateArgumentLocInfo Info; + switch (I.getKind()) { + case TemplateArgument::Type: + Info = (TypeSourceInfo *)nullptr; + break; + case TemplateArgument::Template: + case TemplateArgument::TemplateExpansion: + Info = + TemplateArgumentLocInfo(SemaRef.Context, NestedNameSpecifierLoc(), + SourceLocation(), SourceLocation()); + break; + default: + break; + } + Ins.addArgument(TemplateArgumentLoc(I, Info)); + } + TemplateArgumentListInfo Outs; + TransformTemplateArguments(Ins.arguments().begin(), Ins.arguments().end(), + Outs); + SmallVector ROuts(Outs.size()); + for (unsigned I = 0; I < Outs.size(); ++I) + ROuts[I] = Outs[I].getArgument(); + Output = TemplateArgumentLoc( + TemplateArgument::CreatePackCopy(SemaRef.Context, ROuts), + Input.getLocInfo()); + return false; + } + case TemplateArgument::Integral: + case TemplateArgument::NullPtr: + case TemplateArgument::Declaration: { + // Transform a resolved template argument straight to a resolved template + // argument. We get here when substituting into an already-substituted + // template type argument during concept satisfaction checking. + QualType T = Arg.getNonTypeTemplateArgumentType(); + QualType NewT = TransformType(T); + assert(!NewT.isNull()); + if (NewT == T) + Output = Input; + else if (Arg.getKind() == TemplateArgument::Integral) + Output = TemplateArgumentLoc( + TemplateArgument(SemaRef.Context, Arg.getAsIntegral(), NewT), + Input.getLocInfo()); + else if (Arg.getKind() == TemplateArgument::NullPtr) + Output = TemplateArgumentLoc(TemplateArgument(NewT, /*IsNullPtr=*/true), + Input.getLocInfo()); + else + Output = TemplateArgumentLoc(TemplateArgument(Arg.getAsDecl(), NewT), + Input.getLocInfo()); + return false; + } + + case TemplateArgument::Type: { + if (Arg.isPackExpansion()) { + QualType T = TransformType(Arg.getAsType()); + assert(!T.isNull()); + Output = TemplateArgumentLoc(TemplateArgument(T), Input.getLocInfo()); + return false; + } + TypeSourceInfo *DI = Input.getTypeSourceInfo(); + if (!DI) + DI = InventTypeSourceInfo(Arg.getAsType()); + + DI = TransformType(DI); + if (!DI) + return true; + + Output = TemplateArgumentLoc(TemplateArgument(DI->getType()), DI); + return false; + } + + case TemplateArgument::Template: { + NestedNameSpecifierLoc QualifierLoc = Input.getTemplateQualifierLoc(); + if (QualifierLoc) { + QualifierLoc = + TransformNestedNameSpecifierLoc(QualifierLoc); + assert(QualifierLoc); + } + + // FIXME: kill this + CXXScopeSpec SS; + SS.Adopt(QualifierLoc); + TemplateName Template = TransformTemplateName( + SS, Arg.getAsTemplate(), Input.getTemplateNameLoc()); + assert(!Template.isNull()); + + Output = TemplateArgumentLoc(SemaRef.Context, TemplateArgument(Template), + QualifierLoc, Input.getTemplateNameLoc()); + return false; + } + + case TemplateArgument::TemplateExpansion: { + Output = TemplateArgumentLoc( + TemplateArgument(Arg.getAsTemplateOrTemplatePattern(), + Arg.getNumTemplateExpansions()), + Input.getLocInfo()); + return false; + } + case TemplateArgument::Expression: { + // FIXME: convert the type of these. + Output = Input; + return false; + } + } + llvm_unreachable("Unexpected TemplateArgument kind"); + } + + template + bool TransformTemplateArguments( + InputIterator First, InputIterator Last, + TemplateArgumentListInfo &Outputs, bool Uneval = true) { + for (; First != Last; ++First) { + TemplateArgumentLoc Out; + if (TransformTemplateArgument(*First, Out, Uneval)) + llvm_unreachable(""); + Outputs.addArgument(Out); + } + return false; + } + + QualType TransformPackExpansionType(TypeLocBuilder &TLB, + PackExpansionTypeLoc TL) { + QualType Pattern = TransformType(TLB, TL.getPatternLoc()); + assert(!Pattern.isNull()); + + QualType Result = TL.getType(); + if (Pattern != TL.getPatternLoc().getType()) { + Result = SemaRef.Context.getPackExpansionType( + Pattern, TL.getTypePtr()->getNumExpansions(), + /*ExpectPackInType=*/false); + } + + PackExpansionTypeLoc NewT = TLB.push(Result); + NewT.setEllipsisLoc(TL.getEllipsisLoc()); + return Result; + } + + bool TransformTypes(llvm::ArrayRef In, + SmallVectorImpl& Out) { + bool Changed = false; + for (unsigned i = 0; i != In.size(); ++i) { + QualType OldType = In[i]; + QualType NewType = TransformType(OldType); + assert(!NewType.isNull()); + Changed |= NewType != OldType; + Out[i] = NewType; + } + return Changed; + } + + QualType TransformFunctionProtoType(TypeLocBuilder &TLB, + FunctionProtoTypeLoc TL) { + const FunctionProtoType *T = TL.getTypePtr(); + + QualType ResultType = TransformType(TLB, TL.getReturnLoc()); + assert(!ResultType.isNull()); + + bool Changed = ResultType != TL.getReturnLoc().getType(); + + SmallVector ParamTypes(T->getNumParams()); + Changed |= TransformTypes(llvm::ArrayRef(T->param_types().begin(), + T->param_types().end()), + ParamTypes); + + FunctionProtoType::ExtProtoInfo EPI = T->getExtProtoInfo(); + + assert(EPI.ExceptionSpec.Type != EST_Uninstantiated && + EPI.ExceptionSpec.Type != EST_Unevaluated); + SmallVector ExceptionStorage( + EPI.ExceptionSpec.Exceptions.size()); + Changed |= TransformTypes(EPI.ExceptionSpec.Exceptions, ParamTypes); + EPI.ExceptionSpec.Exceptions = ExceptionStorage; + + QualType Result = + Changed ? SemaRef.Context.getFunctionType(ResultType, ParamTypes, EPI) + : TL.getType(); + + FunctionProtoTypeLoc NewTL = TLB.push(Result); + NewTL.setLocalRangeBegin(TL.getLocalRangeBegin()); + NewTL.setLParenLoc(TL.getLParenLoc()); + NewTL.setRParenLoc(TL.getRParenLoc()); + NewTL.setExceptionSpecRange(TL.getExceptionSpecRange()); + NewTL.setLocalRangeEnd(TL.getLocalRangeEnd()); + for (unsigned i = 0, e = NewTL.getNumParams(); i != e; ++i) + NewTL.setParam(i, TL.getParam(i)); + return Result; + } + + bool TransformFunctionTypeParams(ArrayRef ParamTypes, + SmallVectorImpl &OutParamTypes) { + for (unsigned i = 0; i != ParamTypes.size(); ++i) { + QualType NewType = TransformType(ParamTypes[i]); + assert(!NewType.isNull()); + OutParamTypes.push_back(NewType); + } + return false; + } + + QualType TransformAttributedType(TypeLocBuilder &TLB, AttributedTypeLoc TL) { + const AttributedType *T = TL.getTypePtr(); + QualType MT = TransformType(TLB, TL.getModifiedLoc()); + assert(!MT.isNull()); + + const Attr *OldAttr = TL.getAttr(); + const Attr *NewAttr = OldAttr ? TransformAttr(OldAttr) : nullptr; + assert(!OldAttr == !NewAttr); + + // FIXME: Rebuild if Attr changes? + QualType Result = TL.getType(); + if (MT != T->getModifiedType()) { + Result = SemaRef.Context.getAttributedType(TL.getAttrKind(), MT, + T->getEquivalentType()); + } + + AttributedTypeLoc newTL = TLB.push(Result); + newTL.setAttr(NewAttr); + return Result; + } +}; +} // namespace + +QualType Sema::resugar(const NestedNameSpecifier *NNS, QualType T) { + if (!getLangOpts().Resugar) + return T; + Resugarer R(*this); + Resugarer::NamingContextRAII NamingScope(R, NNS); + return R.TransformType(T); +} + +QualType Sema::getResugaredDependentTemplateSpecializationType( + NestedNameSpecifier *NNS, ElaboratedTypeKeyword Keyword, + const IdentifierInfo *Name, const TemplateArgumentListInfo &Args) { + if (!getLangOpts().Resugar) + return Context.getDependentTemplateSpecializationType(Keyword, NNS, Name, + Args); + Resugarer R(*this); + Resugarer::NamingContextRAII SNamingScope(R, NNS); + TemplateArgumentListInfo NewArgs; + if (R.TransformTemplateArguments(Args.arguments().begin(), + Args.arguments().end(), NewArgs)) + llvm_unreachable(""); + return Context.getDependentTemplateSpecializationType(Keyword, NNS, Name, + NewArgs); +} + +static QualType getResugaredTemplateSpecializationType( + Sema &S, NestedNameSpecifier *NNS, TemplateName Template, + const TemplateArgumentListInfo &Args, QualType Underlying = QualType()) { + if (!S.getLangOpts().Resugar) + return S.Context.getTemplateSpecializationType(Template, Args, Underlying); + Resugarer R(S); + Resugarer::NamingContextRAII NamingScope(R, NNS); + TemplateArgumentListInfo NewArgs; + if (R.TransformTemplateArguments(Args.arguments().begin(), + Args.arguments().end(), NewArgs)) + llvm_unreachable(""); + SmallVector RArgs(NewArgs.size()); + for (unsigned I = 0; I < NewArgs.size(); ++I) + RArgs[I] = NewArgs[I].getArgument(); + const TemplateDecl *TD = Template.getAsTemplateDecl(); + Resugarer::BuildMLTALRAII SubstitutionScope( + R, TD ? TD->getDeclContext() : nullptr, RArgs); + Underlying = R.TransformType(Underlying); + return S.Context.getTemplateSpecializationType(Template, NewArgs, Underlying); +} + /// \brief Determine whether the declaration found is acceptable as the name /// of a template and, if so, return that template declaration. Otherwise, /// returns null. @@ -3442,7 +4178,8 @@ } static QualType -checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD, +checkBuiltinTemplateIdType(Sema &SemaRef, NestedNameSpecifier *NNS, + TemplateName Name, BuiltinTemplateDecl *BTD, const SmallVectorImpl &Converted, SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs) { @@ -3474,7 +4211,17 @@ TemplateArgumentListInfo SyntheticTemplateArgs; // The type argument gets reused as the first template argument in the // synthetic template argument list. - SyntheticTemplateArgs.addArgument(TemplateArgs[1]); + auto *TTPD = + cast(BTD->getTemplateParameters()->getParam(1)); + const auto *TTP = cast( + SemaRef.Context.getTemplateTypeParmType(0, 1, false, TTPD)); + QualType OrigType = TemplateArgs[1].getArgument().getAsType(); + QualType SyntheticType = + SemaRef.Context.getSubstTemplateTypeParmType(TTP, OrigType); + SyntheticTemplateArgs.addArgument( + TemplateArgumentLoc(TemplateArgument(SyntheticType), + SemaRef.Context.getTrivialTypeSourceInfo( + SyntheticType, TemplateArgs[1].getLocation()))); // Expand N into 0 ... N-1. for (llvm::APSInt I(NumArgs.getBitWidth(), NumArgs.isUnsigned()); I < NumArgs; ++I) { @@ -3484,8 +4231,11 @@ } // The first template argument will be reused as the template decl that // our synthetic template arguments will be applied to. - return SemaRef.CheckTemplateIdType(Converted[0].getAsTemplate(), - TemplateLoc, SyntheticTemplateArgs); + TemplateName Template = Converted[0].getAsTemplate(); + QualType Result = SemaRef.CheckTemplateIdType( + NNS, Converted[0].getAsTemplate(), TemplateLoc, SyntheticTemplateArgs); + return SemaRef.Context.getTemplateSpecializationType(Name, TemplateArgs, + Result); } case BTK__type_pack_element: @@ -3507,8 +4257,10 @@ } // We simply return the type at index `Index`. + // FIXME: test this auto Nth = std::next(Ts.pack_begin(), Index.getExtValue()); - return Nth->getAsType(); + return getResugaredTemplateSpecializationType( + SemaRef, NNS, Name, TemplateArgs, Nth->getAsType()); } llvm_unreachable("unexpected BuiltinTemplateDecl!"); } @@ -3652,7 +4404,7 @@ return { FailedCond, Description }; } -QualType Sema::CheckTemplateIdType(TemplateName Name, +QualType Sema::CheckTemplateIdType(NestedNameSpecifier *NNS, TemplateName Name, SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs) { DependentTemplateName *DTN @@ -3677,7 +4429,8 @@ // We might have a substituted template template parameter pack. If so, // build a template specialization type for it. if (Name.getAsSubstTemplateTemplateParmPack()) - return Context.getTemplateSpecializationType(Name, TemplateArgs); + return getResugaredTemplateSpecializationType(*this, NNS, Name, + TemplateArgs); Diag(TemplateLoc, diag::err_template_id_not_a_type) << Name; @@ -3843,14 +4596,15 @@ assert(isa(CanonType) && "type of non-dependent specialization is not a RecordType"); } else if (auto *BTD = dyn_cast(Template)) { - CanonType = checkBuiltinTemplateIdType(*this, BTD, Converted, TemplateLoc, - TemplateArgs); + return checkBuiltinTemplateIdType(*this, NNS, Name, BTD, Converted, + TemplateLoc, TemplateArgs); } // Build the fully-sugared type for this class template // specialization, which refers back to the class template // specialization we created or found. - return Context.getTemplateSpecializationType(Name, TemplateArgs, CanonType); + return getResugaredTemplateSpecializationType(*this, NNS, Name, TemplateArgs, + CanonType); } void Sema::ActOnUndeclaredTypeTemplateName(Scope *S, TemplateTy &ParsedName, @@ -3915,9 +4669,9 @@ if (SS.isInvalid()) return true; - if (!IsCtorOrDtorName && !IsClassName && SS.isSet()) { - DeclContext *LookupCtx = computeDeclContext(SS, /*EnteringContext*/false); + const auto *LookupCtx = computeDeclContext(SS, /*EnteringContext*/ false); + if (!IsCtorOrDtorName && !IsClassName && SS.isSet()) { // C++ [temp.res]p3: // A qualified-id that refers to a type and in which the // nested-name-specifier depends on a template-parameter (14.6.2) @@ -3981,14 +4735,15 @@ return CreateParsedType(T, TLB.getTypeSourceInfo(Context, T)); } - QualType Result = CheckTemplateIdType(Template, TemplateIILoc, TemplateArgs); - if (Result.isNull()) + QualType T = CheckTemplateIdType(SS.getScopeRep(), Template, TemplateIILoc, + TemplateArgs); + if (T.isNull()) return true; // Build type-source information. TypeLocBuilder TLB; TemplateSpecializationTypeLoc SpecTL - = TLB.push(Result); + = TLB.push(T); SpecTL.setTemplateKeywordLoc(TemplateKWLoc); SpecTL.setTemplateNameLoc(TemplateIILoc); SpecTL.setLAngleLoc(LAngleLoc); @@ -4000,14 +4755,12 @@ // constructor or destructor name (in such a case, the scope specifier // will be attached to the enclosing Decl or Expr node). if (SS.isNotEmpty() && !IsCtorOrDtorName) { - // Create an elaborated-type-specifier containing the nested-name-specifier. - Result = Context.getElaboratedType(ETK_None, SS.getScopeRep(), Result); - ElaboratedTypeLoc ElabTL = TLB.push(Result); + T = Context.getElaboratedType(ETK_None, SS.getScopeRep(), T); + ElaboratedTypeLoc ElabTL = TLB.push(T); ElabTL.setElaboratedKeywordLoc(SourceLocation()); ElabTL.setQualifierLoc(SS.getWithLocInContext(Context)); } - - return CreateParsedType(Result, TLB.getTypeSourceInfo(Context, Result)); + return CreateParsedType(T, TLB.getTypeSourceInfo(Context, T)); } TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK, @@ -4066,30 +4819,15 @@ Diag(TAT->getLocation(), diag::note_declared_at); } - QualType Result = CheckTemplateIdType(Template, TemplateLoc, TemplateArgs); - if (Result.isNull()) + QualType T = CheckTemplateIdType(SS.getScopeRep(), Template, TemplateLoc, + TemplateArgs); + if (T.isNull()) return TypeResult(true); - // Check the tag kind - if (const RecordType *RT = Result->getAs()) { - RecordDecl *D = RT->getDecl(); - - IdentifierInfo *Id = D->getIdentifier(); - assert(Id && "templated class must have an identifier"); - - if (!isAcceptableTagRedeclaration(D, TagKind, TUK == TUK_Definition, - TagLoc, Id)) { - Diag(TagLoc, diag::err_use_with_wrong_tag) - << Result - << FixItHint::CreateReplacement(SourceRange(TagLoc), D->getKindName()); - Diag(D->getLocation(), diag::note_previous_use); - } - } - // Provide source-location information for the template specialization. TypeLocBuilder TLB; - TemplateSpecializationTypeLoc SpecTL - = TLB.push(Result); + TemplateSpecializationTypeLoc SpecTL = + TLB.push(T); SpecTL.setTemplateKeywordLoc(TemplateKWLoc); SpecTL.setTemplateNameLoc(TemplateLoc); SpecTL.setLAngleLoc(LAngleLoc); @@ -4099,11 +4837,29 @@ // Construct an elaborated type containing the nested-name-specifier (if any) // and tag keyword. - Result = Context.getElaboratedType(Keyword, SS.getScopeRep(), Result); - ElaboratedTypeLoc ElabTL = TLB.push(Result); + T = Context.getElaboratedType(Keyword, SS.getScopeRep(), T); + ElaboratedTypeLoc ElabTL = TLB.push(T); ElabTL.setElaboratedKeywordLoc(TagLoc); ElabTL.setQualifierLoc(SS.getWithLocInContext(Context)); - return CreateParsedType(Result, TLB.getTypeSourceInfo(Context, Result)); + + // Check the tag kind + if (const RecordType *RT = T->getAs()) { + RecordDecl *D = RT->getDecl(); + + IdentifierInfo *Id = D->getIdentifier(); + assert(Id && "templated class must have an identifier"); + + if (!isAcceptableTagRedeclaration(D, TagKind, TUK == TUK_Definition, TagLoc, + Id)) { + Diag(TagLoc, diag::err_use_with_wrong_tag) + << T + << FixItHint::CreateReplacement(SourceRange(TagLoc), + D->getKindName()); + Diag(D->getLocation(), diag::note_previous_use); + } + } + + return CreateParsedType(T, TLB.getTypeSourceInfo(Context, T)); } static bool CheckTemplateSpecializationScope(Sema &S, NamedDecl *Specialized, @@ -10401,6 +11157,7 @@ /*DeducedTSTContext=*/true); if (T.isNull()) return true; + // T.dump(); return CreateParsedType(T, TSI); } @@ -10422,11 +11179,11 @@ diag::ext_typename_outside_of_template) << FixItHint::CreateRemoval(TypenameLoc); + const auto *DC = computeDeclContext(SS, false); // Strangely, non-type results are not ignored by this lookup, so the // program is ill-formed if it finds an injected-class-name. if (TypenameLoc.isValid()) { - auto *LookupRD = - dyn_cast_or_null(computeDeclContext(SS, false)); + const auto *LookupRD = dyn_cast_or_null(DC); if (LookupRD && LookupRD->getIdentifier() == TemplateII) { Diag(TemplateIILoc, diag::ext_out_of_line_qualified_id_type_names_constructor) @@ -10464,7 +11221,8 @@ return CreateParsedType(T, Builder.getTypeSourceInfo(Context, T)); } - QualType T = CheckTemplateIdType(Template, TemplateIILoc, TemplateArgs); + QualType T = CheckTemplateIdType(SS.getScopeRep(), Template, TemplateIILoc, + TemplateArgs); if (T.isNull()) return true; @@ -10484,8 +11242,7 @@ TL.setElaboratedKeywordLoc(TypenameLoc); TL.setQualifierLoc(SS.getWithLocInContext(Context)); - TypeSourceInfo *TSI = Builder.getTypeSourceInfo(Context, T); - return CreateParsedType(T, TSI); + return CreateParsedType(T, Builder.getTypeSourceInfo(Context, T)); } @@ -10691,9 +11448,9 @@ // We found a type. Build an ElaboratedType, since the // typename-specifier was just sugar. MarkAnyDeclReferenced(Type->getLocation(), Type, /*OdrUse=*/false); - return Context.getElaboratedType(Keyword, - QualifierLoc.getNestedNameSpecifier(), - Context.getTypeDeclType(Type)); + return Context.getElaboratedType( + Keyword, QualifierLoc.getNestedNameSpecifier(), + resugar(SS.getScopeRep(), Context.getTypeDeclType(Type))); } // C++ [dcl.type.simple]p2: 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 @@ -137,14 +137,6 @@ SmallVectorImpl &Deduced, unsigned TDF, bool PartialOrdering = false, bool DeducedFromArrayBound = false); -static Sema::TemplateDeductionResult -DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, - ArrayRef Ps, - ArrayRef As, - TemplateDeductionInfo &Info, - SmallVectorImpl &Deduced, - bool NumberOfArgumentsMustMatch); - static void MarkUsedTemplateParameters(ASTContext &Ctx, const TemplateArgument &TemplateArg, bool OnlyDeduced, unsigned Depth, @@ -574,9 +566,9 @@ // Perform template argument deduction on each template // argument. Ignore any missing/extra arguments, since they could be // filled in by default arguments. - return DeduceTemplateArguments(S, TemplateParams, PResolved, - SA->template_arguments(), Info, Deduced, - /*NumberOfArgumentsMustMatch=*/false); + return S.DeduceTemplateArguments(TemplateParams, TP->template_arguments(), + SA->template_arguments(), Info, Deduced, + /*NumberOfArgumentsMustMatch=*/false); } // If the argument type is a class template specialization, we @@ -598,9 +590,9 @@ return Result; // Perform template argument deduction for the template arguments. - return DeduceTemplateArguments(S, TemplateParams, PResolved, - SA->getTemplateArgs().asArray(), Info, Deduced, - /*NumberOfArgumentsMustMatch=*/true); + return S.DeduceTemplateArguments( + TemplateParams, PResolved, SA->getTemplateArgs().asArray(), Info, Deduced, + /*NumberOfArgumentsMustMatch=*/true); } static bool IsPossiblyOpaquelyQualifiedTypeInternal(const Type *T) { @@ -2243,9 +2235,51 @@ return Sema::TDK_NonDeducedMismatch; case TemplateArgument::Integral: - if (A.getKind() == TemplateArgument::Integral) { + switch (A.getKind()) { + case TemplateArgument::Integral: if (hasSameExtendedValue(P.getAsIntegral(), A.getAsIntegral())) return Sema::TDK_Success; + break; + case TemplateArgument::Expression: { + TemplateArgument Resolved; + Expr *AE = A.getAsExpr(); + QualType AT = AE->getType(); + // FIXME: Copypasta from CheckTemplateArgument + + APValue Value; + if (auto *CE = dyn_cast(AE)) { + Value = CE->getAPValueResult(); + } else { + ExprResult ArgResult = S.CheckConvertedConstantExpression( + AE, AT, Value, Sema::CCEK_TemplateArg); + if (ArgResult.isInvalid()) + break; + + // For a value-dependent argument, CheckConvertedConstantExpression is + // permitted (and expected) to be unable to determine a value. + if (ArgResult.get()->isValueDependent()) + break; + } + // Convert the APValue to a TemplateArgument. + switch (Value.getKind()) { + case APValue::None: + assert(AT->isNullPtrType()); + Resolved = TemplateArgument(AT, /*isNullPtr*/ true); + break; + case APValue::Indeterminate: + llvm_unreachable("result of constant evaluation should be initialized"); + case APValue::Int: + assert(AT->isIntegralOrEnumerationType()); + Resolved = TemplateArgument(S.Context, Value.getInt(), AT); + break; + default: + llvm_unreachable("unhandled"); + } + return DeduceTemplateArguments(S, TemplateParams, P, Resolved, Info, + Deduced); + } + default: + break; } Info.FirstArg = P; Info.SecondArg = A; @@ -2326,13 +2360,11 @@ return false; } -static Sema::TemplateDeductionResult -DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, - ArrayRef Ps, - ArrayRef As, - TemplateDeductionInfo &Info, - SmallVectorImpl &Deduced, - bool NumberOfArgumentsMustMatch) { +Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( + TemplateParameterList *TemplateParams, ArrayRef Ps, + ArrayRef As, TemplateDeductionInfo &Info, + SmallVectorImpl &Deduced, + bool NumberOfArgumentsMustMatch) { // C++0x [temp.deduct.type]p9: // 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 @@ -2363,8 +2395,8 @@ return Sema::TDK_MiscellaneousDeductionFailure; // Perform deduction for this Pi/Ai pair. - if (auto Result = DeduceTemplateArguments(S, TemplateParams, P, - As[ArgIdx], Info, Deduced)) + if (auto Result = ::DeduceTemplateArguments(*this, TemplateParams, P, + As[ArgIdx], Info, Deduced)) return Result; // Move to the next argument. @@ -2382,7 +2414,7 @@ TemplateArgument Pattern = P.getPackExpansionPattern(); // Prepare to deduce the packs within the pattern. - PackDeductionScope PackScope(S, TemplateParams, Deduced, Info, Pattern); + PackDeductionScope PackScope(*this, TemplateParams, Deduced, Info, Pattern); // Keep track of the deduced template arguments for each parameter pack // expanded by this pack expansion (the outer index) and for each @@ -2391,8 +2423,8 @@ PackScope.hasNextElement(); ++ArgIdx) { // Deduce template arguments from the pattern. - if (auto Result = DeduceTemplateArguments(S, TemplateParams, Pattern, - As[ArgIdx], Info, Deduced)) + if (auto Result = ::DeduceTemplateArguments( + *this, TemplateParams, Pattern, As[ArgIdx], Info, Deduced)) return Result; PackScope.nextPackElement(); @@ -2407,17 +2439,6 @@ return Sema::TDK_Success; } -static Sema::TemplateDeductionResult -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); -} - /// Determine whether two template arguments are the same. static bool isSameTemplateArg(ASTContext &Context, TemplateArgument X, @@ -2960,11 +2981,9 @@ SmallVector Deduced; Deduced.resize(Partial->getTemplateParameters()->size()); - if (TemplateDeductionResult Result - = ::DeduceTemplateArguments(*this, - Partial->getTemplateParameters(), - Partial->getTemplateArgs(), - TemplateArgs, Info, Deduced)) + if (TemplateDeductionResult Result = DeduceTemplateArguments( + Partial->getTemplateParameters(), Partial->getTemplateArgs(), + TemplateArgs, Info, Deduced)) return Result; SmallVector DeducedArgs(Deduced.begin(), Deduced.end()); @@ -3012,8 +3031,8 @@ SmallVector Deduced; Deduced.resize(Partial->getTemplateParameters()->size()); - if (TemplateDeductionResult Result = ::DeduceTemplateArguments( - *this, Partial->getTemplateParameters(), Partial->getTemplateArgs(), + if (TemplateDeductionResult Result = DeduceTemplateArguments( + Partial->getTemplateParameters(), Partial->getTemplateArgs(), TemplateArgs, Info, Deduced)) return Result; diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -1839,9 +1839,18 @@ QualType Replacement = Arg.getAsType(); - // TODO: only do this uniquing once, at the start of instantiation. - QualType Result - = getSema().Context.getSubstTemplateTypeParmType(T, Replacement); + QualType Result; + if (T->isParameterPack()) { + QualType NewT = getSema().Context.getTemplateTypeParmType( + T->getDepth(), + T->getIndex() + getSema().ArgumentPackSubstitutionIndex, false); + Result = getSema().Context.getSubstTemplateTypeParmType( + cast(NewT), Replacement); + } else { + // TODO: only do this uniquing once, at the start of instantiation. + Result = getSema().Context.getSubstTemplateTypeParmType(T, Replacement); + } + SubstTemplateTypeParmTypeLoc NewTL = TLB.push(Result); NewTL.setNameLoc(TL.getNameLoc()); diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -6162,7 +6162,8 @@ Args.addArgument( getTrivialTemplateArgumentLoc(UnpackedArg, QualType(), Loc)); } - QualType T = CheckTemplateIdType(TemplateName(TD), Loc, Args); + QualType T = + CheckTemplateIdType(nullptr, TemplateName(TD), Loc, Args); if (T.isNull()) return nullptr; auto *SubstRecord = T->getAsCXXRecordDecl(); 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 @@ -1009,7 +1009,8 @@ /// By default, performs semantic analysis when building the template /// specialization type. Subclasses may override this routine to provide /// different behavior. - QualType RebuildTemplateSpecializationType(TemplateName Template, + QualType RebuildTemplateSpecializationType(NestedNameSpecifier *NNS, + TemplateName Template, SourceLocation TemplateLoc, TemplateArgumentListInfo &Args); @@ -1068,8 +1069,8 @@ // Otherwise, make an elaborated type wrapping a non-dependent // specialization. - QualType T = - getDerived().RebuildTemplateSpecializationType(InstName, NameLoc, Args); + QualType T = getDerived().RebuildTemplateSpecializationType( + SS.getScopeRep(), InstName, NameLoc, Args); if (T.isNull()) return QualType(); if (Keyword == ETK_None && QualifierLoc.getNestedNameSpecifier() == nullptr) @@ -4894,7 +4895,7 @@ return TL; TypeSourceInfo *TSI = - TransformTSIInObjectScope(TL, ObjectType, UnqualLookup, SS); + getDerived().TransformTSIInObjectScope(TL, ObjectType, UnqualLookup, SS); if (TSI) return TSI->getTypeLoc(); return TypeLoc(); @@ -4909,7 +4910,7 @@ if (getDerived().AlreadyTransformed(TSInfo->getType())) return TSInfo; - return TransformTSIInObjectScope(TSInfo->getTypeLoc(), ObjectType, + return getDerived().TransformTSIInObjectScope(TSInfo->getTypeLoc(), ObjectType, UnqualLookup, SS); } @@ -6694,10 +6695,8 @@ // FIXME: maybe don't rebuild if all the template arguments are the same. - QualType Result = - getDerived().RebuildTemplateSpecializationType(Template, - TL.getTemplateNameLoc(), - NewTemplateArgs); + QualType Result = getDerived().RebuildTemplateSpecializationType( + nullptr, Template, TL.getTemplateNameLoc(), NewTemplateArgs); if (!Result.isNull()) { // Specializations of template template parameters are represented as @@ -6770,10 +6769,8 @@ return Result; } - QualType Result - = getDerived().RebuildTemplateSpecializationType(Template, - TL.getTemplateNameLoc(), - NewTemplateArgs); + QualType Result = getDerived().RebuildTemplateSpecializationType( + SS.getScopeRep(), Template, TL.getTemplateNameLoc(), NewTemplateArgs); if (!Result.isNull()) { /// FIXME: Wrap this in an elaborated-type-specifier? @@ -14709,10 +14706,10 @@ template QualType TreeTransform::RebuildTemplateSpecializationType( - TemplateName Template, - SourceLocation TemplateNameLoc, - TemplateArgumentListInfo &TemplateArgs) { - return SemaRef.CheckTemplateIdType(Template, TemplateNameLoc, TemplateArgs); + NestedNameSpecifier *NNS, TemplateName Template, + SourceLocation TemplateNameLoc, TemplateArgumentListInfo &TemplateArgs) { + return SemaRef.CheckTemplateIdType(NNS, Template, TemplateNameLoc, + TemplateArgs); } template diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp @@ -38,7 +38,7 @@ void b1(struct B); void b2(class B); -void b3(union B); // expected-error {{use of 'B' with tag type that does not match previous declaration}} +void b3(union B); // expected-error {{use of 'union B' with tag type that does not match previous declaration}} //void b4(enum B); // this just doesn't parse; you can't template an enum directly void c1(struct B::Member); diff --git a/clang/test/CXX/temp/temp.deduct.guide/p3.cpp b/clang/test/CXX/temp/temp.deduct.guide/p3.cpp --- a/clang/test/CXX/temp/temp.deduct.guide/p3.cpp +++ b/clang/test/CXX/temp/temp.deduct.guide/p3.cpp @@ -33,7 +33,7 @@ }; A(int) -> int; // expected-error {{deduced type 'int' of deduction guide is not a specialization of template 'A'}} -template A(T) -> B; // expected-error {{deduced type 'B' (aka 'A') of deduction guide is not written as a specialization of template 'A'}} +template A(T)->B; // expected-error {{deduced type 'B' (aka 'A') of deduction guide is not written as a specialization of template 'A'}} template A(T*) -> const A; // expected-error {{deduced type 'const A' of deduction guide is not a specialization of template 'A'}} // A deduction-guide shall be declared in the same scope as the corresponding diff --git a/clang/test/CodeGenCXX/mangle-ms-back-references-pr13207.cpp b/clang/test/CodeGenCXX/mangle-ms-back-references-pr13207.cpp --- a/clang/test/CodeGenCXX/mangle-ms-back-references-pr13207.cpp +++ b/clang/test/CodeGenCXX/mangle-ms-back-references-pr13207.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-win32 | FileCheck %s +// RUN: %clang_cc1 -fno-resugar -emit-llvm %s -o - -triple=i386-pc-win32 | FileCheck %s template class A {}; @@ -220,6 +220,7 @@ class T20> struct Food {}; +// FIXME: Should implement resugaring cache for this. using B0 = Food; using B1 = Food; using B2 = Food; diff --git a/clang/test/CodeGenCXX/pr29160.cpp b/clang/test/CodeGenCXX/pr29160.cpp --- a/clang/test/CodeGenCXX/pr29160.cpp +++ b/clang/test/CodeGenCXX/pr29160.cpp @@ -1,8 +1,9 @@ -// RUN: %clang_cc1 -std=c++11 -triple i686-linux-gnu %s -o /dev/null -S -emit-llvm +// RUN: %clang_cc1 -std=c++11 -fno-resugar -triple i686-linux-gnu %s -o /dev/null -S -emit-llvm // // This test's failure mode is running ~forever. (For some value of "forever" // that's greater than 25 minutes on my machine) +// FIXME: Should implement resugaring cache for this. template struct Foo { template diff --git a/clang/test/Misc/diag-template-diffing.cpp b/clang/test/Misc/diag-template-diffing.cpp --- a/clang/test/Misc/diag-template-diffing.cpp +++ b/clang/test/Misc/diag-template-diffing.cpp @@ -257,24 +257,21 @@ int k9 = f9(V9()); // CHECK-ELIDE-NOTREE: no matching function for call to 'f9' -// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'S9<[2 * ...], S9<[2 * ...], double>>' to 'S9<[2 * ...], S9<[2 * ...], const double>>' for 1st argument +// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'S9<[2 * ...], U9>' to 'S9<[2 * ...], U9>' for 1st argument // CHECK-NOELIDE-NOTREE: no matching function for call to 'f9' -// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'S9>' to 'S9>' for 1st argument +// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'S9>' to 'S9>' for 1st argument // CHECK-ELIDE-TREE: no matching function for call to 'f9' // CHECK-ELIDE-TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument // CHECK-ELIDE-TREE: S9< -// CHECK-ELIDE-TREE: [2 * ...], -// CHECK-ELIDE-TREE: S9< -// CHECK-ELIDE-TREE: [2 * ...], +// CHECK-ELIDE-TREE: [2 * ...], +// CHECK-ELIDE-TREE: U9< // CHECK-ELIDE-TREE: [double != const double]>> // CHECK-NOELIDE-TREE: no matching function for call to 'f9' // CHECK-NOELIDE-TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument // CHECK-NOELIDE-TREE: S9< -// CHECK-NOELIDE-TREE: int, -// CHECK-NOELIDE-TREE: char, -// CHECK-NOELIDE-TREE: S9< -// CHECK-NOELIDE-TREE: int, -// CHECK-NOELIDE-TREE: char, +// CHECK-NOELIDE-TREE: int, +// CHECK-NOELIDE-TREE: char, +// CHECK-NOELIDE-TREE: U9< // CHECK-NOELIDE-TREE: [double != const double]>> template class class_types {}; diff --git a/clang/test/Sema/resugar.cpp b/clang/test/Sema/resugar.cpp new file mode 100644 --- /dev/null +++ b/clang/test/Sema/resugar.cpp @@ -0,0 +1,163 @@ +// RUN: %clang_cc1 -std=c++2b -verify %s +// expected-no-diagnostics + +static constexpr int alignment = 64; // Suitable large alignment. + +struct Baz {}; +using Bar [[gnu::aligned(alignment)]] = Baz; +using Int [[gnu::aligned(alignment)]] = int; + +#define TEST(X) static_assert(alignof(X) == alignment) +#define TEST_NOT(X) static_assert(alignof(X) != alignment) + +// Sanity checks. +TEST_NOT(Baz); +TEST(Bar); + +namespace t1 { +template struct foo { using type = T; }; +template struct foo { using type = U; }; + +TEST(typename foo::type); +TEST_NOT(typename foo::type); // FIXME +} // namespace t1 + +namespace t2 { +template struct foo1 { using type = T; }; +template struct foo2 { using type = typename foo1<1, T>::type; }; +TEST(typename foo2::type); +} // namespace t2 + +namespace t3 { +template struct foo1 { + template struct foo2 { using type1 = T; }; + using type2 = typename foo2<1, int>::type1; +}; +TEST(typename foo1::type2); +} // namespace t3 + +namespace t4 { +template struct foo { + template using type1 = T; + using type2 = type1; +}; +TEST(typename foo::type2); +} // namespace t4 + +namespace t5 { +template struct foo { + template using type1 = U; + using type2 = type1<1, T>; +}; +TEST(typename foo::type2); +} // namespace t5 + +namespace t6 { +template struct foo1 { + template struct foo2 { using type = U; }; + using type2 = typename foo2<1, T>::type; +}; +TEST(typename foo1::type2); +}; // namespace t6 + +namespace t7 { +template struct foo { + template using type1 = U; +}; +using type2 = typename foo::template type1<1, Bar>; +TEST(type2); +} // namespace t7 + +namespace t8 { +template struct foo { + using type1 = T; +}; +template using type2 = T; +using type3 = typename type2, int>::type1; +TEST(type3); +} // namespace t8 + +namespace t9 { +template struct Y { + using type1 = A; + using type2 = B; +}; +template using Z = Y; +template struct foo { + template using apply = Z; +}; +using T1 = foo::apply; +TEST_NOT(T1::type1); +TEST(T1::type2); + +using T2 = foo::apply; +TEST(T2::type1); +TEST_NOT(T2::type2); +} // namespace t9 + +namespace t10 { +template struct Y { + using type1 = A1; + using type2 = A2; +}; +template using Z = Y; +template struct foo { + template using bind = Z; +}; +using T1 = foo::bind; +TEST_NOT(T1::type1); +TEST(T1::type2); + +using T2 = foo::bind; +TEST(T2::type1); +TEST_NOT(T2::type2); +} // namespace t10 + +namespace t11 { +template