diff --git a/clang-tools-extra/clang-tidy/hicpp/ExceptionBaseclassCheck.cpp b/clang-tools-extra/clang-tidy/hicpp/ExceptionBaseclassCheck.cpp --- a/clang-tools-extra/clang-tidy/hicpp/ExceptionBaseclassCheck.cpp +++ b/clang-tools-extra/clang-tidy/hicpp/ExceptionBaseclassCheck.cpp @@ -52,7 +52,7 @@ diag(BadThrow->getSubExpr()->getBeginLoc(), "type %0 is a template instantiation of %1", DiagnosticIDs::Note) << BadThrow->getSubExpr()->getType() - << Template->getReplacedParameter()->getDecl(); + << Template->getReplacedTemplateParam(); if (const auto *TypeDecl = Result.Nodes.getNodeAs("decl")) diag(TypeDecl->getBeginLoc(), "type defined here", DiagnosticIDs::Note); diff --git a/clang-tools-extra/clang-tidy/modernize/UseTransparentFunctorsCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseTransparentFunctorsCheck.cpp --- a/clang-tools-extra/clang-tidy/modernize/UseTransparentFunctorsCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseTransparentFunctorsCheck.cpp @@ -96,8 +96,9 @@ unsigned ArgNum = 0; const auto *FunctorParentType = FunctorParentLoc.getType()->castAs(); - for (; ArgNum < FunctorParentType->getNumArgs(); ++ArgNum) { - const TemplateArgument &Arg = FunctorParentType->getArg(ArgNum); + for (; ArgNum < FunctorParentType->getSpecifiedArguments().size(); ++ArgNum) { + const TemplateArgument &Arg = + FunctorParentType->getSpecifiedArguments()[ArgNum]; if (Arg.getKind() != TemplateArgument::Type) continue; QualType ParentArgType = Arg.getAsType(); @@ -107,7 +108,7 @@ break; } // Functor is a default template argument. - if (ArgNum == FunctorParentType->getNumArgs()) + if (ArgNum == FunctorParentType->getSpecifiedArguments().size()) return; TemplateArgumentLoc FunctorLoc = FunctorParentLoc.getArgLoc(ArgNum); auto FunctorTypeLoc = getInnerTypeLocAs( diff --git a/clang-tools-extra/clang-tidy/mpi/TypeMismatchCheck.cpp b/clang-tools-extra/clang-tidy/mpi/TypeMismatchCheck.cpp --- a/clang-tools-extra/clang-tidy/mpi/TypeMismatchCheck.cpp +++ b/clang-tools-extra/clang-tidy/mpi/TypeMismatchCheck.cpp @@ -183,8 +183,10 @@ if (Template->getAsCXXRecordDecl()->getName() != "complex") return true; - const auto *Builtin = - Template->getArg(0).getAsType().getTypePtr()->getAs(); + const auto *Builtin = Template->getSpecifiedArguments()[0] + .getAsType() + .getTypePtr() + ->getAs(); if (Builtin && !isMPITypeMatching(ComplexCXXMatches, Builtin->getKind(), MPIDatatype)) { diff --git a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp --- a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp +++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp @@ -191,12 +191,13 @@ getSubstitutedType(VarType, Context)) { if (const SubstTemplateTypeParmType *InitializerTmplType = getSubstitutedType(InitializerType, Context)) { - return VarTmplType->getReplacedParameter() - ->desugar() - .getCanonicalType() != - InitializerTmplType->getReplacedParameter() - ->desugar() - .getCanonicalType(); + const TemplateTypeParmDecl *VarTTP = + VarTmplType->getReplacedTemplateParam(); + const TemplateTypeParmDecl *InitTTP = + InitializerTmplType->getReplacedTemplateParam(); + return (VarTTP->getDepth() != InitTTP->getDepth() || + VarTTP->getIndex() != InitTTP->getIndex() || + VarTTP->isParameterPack() != InitTTP->isParameterPack()); } } return false; 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 @@ -128,7 +128,7 @@ auto UnlessFunctionType = unless(hasUnqualifiedDesugaredType(functionType())); auto IsAutoDeducedToPointer = [](const auto &...InnerMatchers) { return autoType(hasDeducedType( - hasUnqualifiedDesugaredType(pointerType(pointee(InnerMatchers...))))); + hasCanonicalType(pointerType(pointee(InnerMatchers...))))); }; Finder->addMatcher( diff --git a/clang-tools-extra/clangd/AST.cpp b/clang-tools-extra/clangd/AST.cpp --- a/clang-tools-extra/clangd/AST.cpp +++ b/clang-tools-extra/clangd/AST.cpp @@ -724,10 +724,10 @@ if (auto *RT = dyn_cast(PlainType)) PlainType = RT->getPointeeTypeAsWritten().getTypePtr(); if (const auto *SubstType = dyn_cast(PlainType)) { - const auto *ReplacedParameter = SubstType->getReplacedParameter(); + const auto *ReplacedParameter = SubstType->getReplacedTemplateParam(); if (ReplacedParameter->isParameterPack()) { - return dyn_cast( - ReplacedParameter->getCanonicalTypeUnqualified()->getTypePtr()); + return ReplacedParameter->getTypeForDecl() + ->castAs(); } } return nullptr; diff --git a/clang-tools-extra/clangd/HeuristicResolver.cpp b/clang-tools-extra/clangd/HeuristicResolver.cpp --- a/clang-tools-extra/clangd/HeuristicResolver.cpp +++ b/clang-tools-extra/clangd/HeuristicResolver.cpp @@ -80,9 +80,9 @@ auto *TST = T->getAs(); if (!TST) return nullptr; - if (TST->getNumArgs() == 0) + if (TST->getSpecifiedArguments().size() == 0) return nullptr; - const TemplateArgument &FirstArg = TST->getArg(0); + const TemplateArgument &FirstArg = TST->getSpecifiedArguments()[0]; if (FirstArg.getKind() != TemplateArgument::Type) return nullptr; return FirstArg.getAsType().getTypePtrOrNull(); 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/ASTContext.h b/clang/include/clang/AST/ASTContext.h --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -1614,11 +1614,10 @@ QualType getBTFTagAttributedType(const BTFTypeTagAttr *BTFAttr, QualType Wrapped); - QualType getSubstTemplateTypeParmType(const TemplateTypeParmType *Replaced, - QualType Replacement, + QualType getSubstTemplateTypeParmType(QualType Replacement, + Decl *ReplacedDecl, unsigned Index, Optional PackIndex) const; - QualType getSubstTemplateTypeParmPackType( - const TemplateTypeParmType *Replaced, + QualType getSubstTemplateTypeParmPackType(Decl *ReplacedDecl, unsigned Index, const TemplateArgument &ArgPack); QualType @@ -1626,22 +1625,27 @@ bool ParameterPack, TemplateTypeParmDecl *ParmDecl = nullptr) const; - QualType getTemplateSpecializationType(TemplateName T, - ArrayRef Args, - QualType Canon = QualType()) const; + QualType getTemplateSpecializationType( + TemplateName T, ArrayRef SpecifiedArgs, + ArrayRef SugaredConvertedArgs, + ArrayRef CanonicalConvertedArgs, + QualType Canon = QualType()) const; - QualType - getCanonicalTemplateSpecializationType(TemplateName T, - ArrayRef Args) const; + QualType getCanonicalTemplateSpecializationType( + TemplateName T, ArrayRef ConvertedArgs) const; - QualType getTemplateSpecializationType(TemplateName T, - const TemplateArgumentListInfo &Args, - QualType Canon = QualType()) const; + QualType getTemplateSpecializationType( + TemplateName T, ArrayRef SpecifiedArgs, + ArrayRef SugaredConvertedArgs, + ArrayRef CanonicalConvertedArgs, + QualType Canon = QualType()) const; - TypeSourceInfo * - getTemplateSpecializationTypeInfo(TemplateName T, SourceLocation TLoc, - const TemplateArgumentListInfo &Args, - QualType Canon = QualType()) const; + TypeSourceInfo *getTemplateSpecializationTypeInfo( + TemplateName T, SourceLocation TLoc, + const TemplateArgumentListInfo &SpecifiedArgs, + ArrayRef SugaredConvertedArgs, + ArrayRef CanonicalConvertedArgs, + QualType Canon = QualType()) const; QualType getParenType(QualType NamedType) const; @@ -1656,10 +1660,9 @@ const IdentifierInfo *Name, QualType Canon = QualType()) const; - QualType getDependentTemplateSpecializationType(ElaboratedTypeKeyword Keyword, - NestedNameSpecifier *NNS, - const IdentifierInfo *Name, - const TemplateArgumentListInfo &Args) const; + QualType getDependentTemplateSpecializationType( + ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, + const IdentifierInfo *Name, ArrayRef Args) const; QualType getDependentTemplateSpecializationType( ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, const IdentifierInfo *Name, ArrayRef Args) const; @@ -2701,6 +2704,13 @@ TemplateArgument getCanonicalTemplateArgument(const TemplateArgument &Arg) const; + /// Retrieve the "canonical" template argument list. + /// + /// Returns true if any arguments were non-canonical. + bool getCanonicalTemplateArguments( + ArrayRef OrigArgs, + SmallVectorImpl &CanonArgs) const; + /// Type Query functions. If the type is an instance of the specified class, /// return the Type pointer for the underlying maximally pretty type. This /// is a member of ASTContext because this may need to do some amount of diff --git a/clang/include/clang/AST/ASTImporter.h b/clang/include/clang/AST/ASTImporter.h --- a/clang/include/clang/AST/ASTImporter.h +++ b/clang/include/clang/AST/ASTImporter.h @@ -480,6 +480,13 @@ /// error. llvm::Expected Import(const APValue &FromValue); + /// Import the given C++ TemplateArgumentList from the "from" + /// context into the "to" context. + /// + /// \returns The equivalent initializer in the "to" context, or the import + /// error. + llvm::Expected Import(const TemplateArgumentList *); + /// Import the definition of the given declaration, including all of /// the declarations it contains. LLVM_NODISCARD llvm::Error ImportDefinition(Decl *From); 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 @@ -389,16 +389,13 @@ void VisitBTFTagAttributedType(const BTFTagAttributedType *T) { Visit(T->getWrappedType()); } - void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T) { - Visit(T->getReplacedParameter()); - } + void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *) {} void VisitSubstTemplateTypeParmPackType(const SubstTemplateTypeParmPackType *T) { - Visit(T->getReplacedParameter()); Visit(T->getArgumentPack()); } void VisitTemplateSpecializationType(const TemplateSpecializationType *T) { - for (const auto &Arg : *T) + for (const auto &Arg : T->getSpecifiedArguments()) Visit(Arg); } void VisitObjCObjectPointerType(const ObjCObjectPointerType *T) { diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -452,6 +452,8 @@ TemplatedDecl->getSourceRange().getEnd()); } + bool isTypeAlias() const; + protected: NamedDecl *TemplatedDecl; TemplateParameterList *TemplateParams; @@ -2138,11 +2140,9 @@ static ClassTemplatePartialSpecializationDecl * Create(ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, - TemplateParameterList *Params, - ClassTemplateDecl *SpecializedTemplate, + TemplateParameterList *Params, ClassTemplateDecl *SpecializedTemplate, ArrayRef Args, - const TemplateArgumentListInfo &ArgInfos, - QualType CanonInjectedType, + const TemplateArgumentListInfo &ArgInfos, QualType InjectedType, ClassTemplatePartialSpecializationDecl *PrevDecl); static ClassTemplatePartialSpecializationDecl * diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -3179,6 +3179,8 @@ /// In X.F, this is the decl referenced by F. ValueDecl *MemberDecl; + const TemplateArgumentList *Deduced; + /// MemberDNLoc - Provides source/type location info for the /// declaration name embedded in MemberDecl. DeclarationNameLoc MemberDNLoc; @@ -3204,21 +3206,20 @@ MemberExpr(Expr *Base, bool IsArrow, SourceLocation OperatorLoc, ValueDecl *MemberDecl, const DeclarationNameInfo &NameInfo, - QualType T, ExprValueKind VK, ExprObjectKind OK, - NonOdrUseReason NOUR); + const TemplateArgumentList *Deduced, QualType T, ExprValueKind VK, + ExprObjectKind OK, NonOdrUseReason NOUR); MemberExpr(EmptyShell Empty) : Expr(MemberExprClass, Empty), Base(), MemberDecl() {} public: - static MemberExpr *Create(const ASTContext &C, Expr *Base, bool IsArrow, - SourceLocation OperatorLoc, - NestedNameSpecifierLoc QualifierLoc, - SourceLocation TemplateKWLoc, ValueDecl *MemberDecl, - DeclAccessPair FoundDecl, - DeclarationNameInfo MemberNameInfo, - const TemplateArgumentListInfo *TemplateArgs, - QualType T, ExprValueKind VK, ExprObjectKind OK, - NonOdrUseReason NOUR); + static MemberExpr * + Create(const ASTContext &C, Expr *Base, bool IsArrow, + SourceLocation OperatorLoc, NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateKWLoc, ValueDecl *MemberDecl, + DeclAccessPair FoundDecl, DeclarationNameInfo MemberNameInfo, + const TemplateArgumentListInfo *TemplateArgs, + const TemplateArgumentList *Deduced, QualType T, ExprValueKind VK, + ExprObjectKind OK, NonOdrUseReason NOUR); /// Create an implicit MemberExpr, with no location, qualifier, template /// arguments, and so on. Suitable only for non-static member access. @@ -3229,7 +3230,8 @@ return Create(C, Base, IsArrow, SourceLocation(), NestedNameSpecifierLoc(), SourceLocation(), MemberDecl, DeclAccessPair::make(MemberDecl, MemberDecl->getAccess()), - DeclarationNameInfo(), nullptr, T, VK, OK, NOUR_None); + DeclarationNameInfo(), nullptr, nullptr, T, VK, OK, + NOUR_None); } static MemberExpr *CreateEmpty(const ASTContext &Context, bool HasQualifier, @@ -3255,6 +3257,8 @@ return getTrailingObjects()->FoundDecl; } + const TemplateArgumentList *getDeduced() const { return Deduced; } + /// Determines whether this member expression actually had /// a C++ nested-name-specifier prior to the name of the member, e.g., /// x->Base::foo. diff --git a/clang/include/clang/AST/JSONNodeDumper.h b/clang/include/clang/AST/JSONNodeDumper.h --- a/clang/include/clang/AST/JSONNodeDumper.h +++ b/clang/include/clang/AST/JSONNodeDumper.h @@ -221,6 +221,8 @@ void VisitTagType(const TagType *TT); void VisitTemplateTypeParmType(const TemplateTypeParmType *TTPT); void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *STTPT); + void + VisitSubstTemplateTypeParmPackType(const SubstTemplateTypeParmPackType *T); void VisitAutoType(const AutoType *AT); void VisitTemplateSpecializationType(const TemplateSpecializationType *TST); void VisitInjectedClassNameType(const InjectedClassNameType *ICNT); diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -289,8 +289,7 @@ /// /// \returns false if the visitation was terminated early, true otherwise. // FIXME: take a TemplateArgumentLoc* (or TemplateArgumentListInfo) instead. - bool TraverseTemplateArguments(const TemplateArgument *Args, - unsigned NumArgs); + bool TraverseTemplateArguments(ArrayRef Args); /// Recursively visit a base specifier. This can be overridden by a /// subclass. @@ -886,8 +885,7 @@ return getDerived().TraverseStmt(Arg.getAsExpr()); case TemplateArgument::Pack: - return getDerived().TraverseTemplateArguments(Arg.pack_begin(), - Arg.pack_size()); + return getDerived().TraverseTemplateArguments(Arg.pack_elements()); } return true; @@ -927,8 +925,7 @@ return getDerived().TraverseStmt(ArgLoc.getSourceExpression()); case TemplateArgument::Pack: - return getDerived().TraverseTemplateArguments(Arg.pack_begin(), - Arg.pack_size()); + return getDerived().TraverseTemplateArguments(Arg.pack_elements()); } return true; @@ -936,10 +933,9 @@ template bool RecursiveASTVisitor::TraverseTemplateArguments( - const TemplateArgument *Args, unsigned NumArgs) { - for (unsigned I = 0; I != NumArgs; ++I) { - TRY_TO(TraverseTemplateArgument(Args[I])); - } + ArrayRef Args) { + for (const TemplateArgument &Arg : Args) + TRY_TO(TraverseTemplateArgument(Arg)); return true; } @@ -1096,7 +1092,7 @@ DEF_TRAVERSE_TYPE(AutoType, { TRY_TO(TraverseType(T->getDeducedType())); if (T->isConstrained()) { - TRY_TO(TraverseTemplateArguments(T->getArgs(), T->getNumArgs())); + TRY_TO(TraverseTemplateArguments(T->getTypeConstraintArguments())); } }) DEF_TRAVERSE_TYPE(DeducedTemplateSpecializationType, { @@ -1116,7 +1112,10 @@ DEF_TRAVERSE_TYPE(TemplateSpecializationType, { TRY_TO(TraverseTemplateName(T->getTemplateName())); - TRY_TO(TraverseTemplateArguments(T->getArgs(), T->getNumArgs())); + if (T->isCanonicalUnqualified()) + TRY_TO(TraverseTemplateArguments(T->getConvertedArguments())); + else + TRY_TO(TraverseTemplateArguments(T->getSpecifiedArguments())); }) DEF_TRAVERSE_TYPE(InjectedClassNameType, {}) @@ -1144,7 +1143,7 @@ DEF_TRAVERSE_TYPE(DependentTemplateSpecializationType, { TRY_TO(TraverseNestedNameSpecifier(T->getQualifier())); - TRY_TO(TraverseTemplateArguments(T->getArgs(), T->getNumArgs())); + TRY_TO(TraverseTemplateArguments(T->template_arguments())); }) DEF_TRAVERSE_TYPE(PackExpansionType, { TRY_TO(TraverseType(T->getPattern())); }) diff --git a/clang/include/clang/AST/TemplateBase.h b/clang/include/clang/AST/TemplateBase.h --- a/clang/include/clang/AST/TemplateBase.h +++ b/clang/include/clang/AST/TemplateBase.h @@ -572,6 +572,12 @@ SourceLocation RAngleLoc) : LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc) {} + TemplateArgumentListInfo(TemplateArgumentListInfo &&) = default; + TemplateArgumentListInfo &operator=(TemplateArgumentListInfo &&) = default; + TemplateArgumentListInfo(const TemplateArgumentListInfo &) = default; + TemplateArgumentListInfo & + operator=(const TemplateArgumentListInfo &) = default; + // This can leak if used in an AST node, use ASTTemplateArgumentListInfo // instead. void *operator new(size_t bytes, ASTContext &C) = delete; @@ -588,9 +594,8 @@ return Arguments.data(); } - llvm::ArrayRef arguments() const { - return Arguments; - } + llvm::ArrayRef arguments() const { return Arguments; } + llvm::MutableArrayRef arguments() { return Arguments; } const TemplateArgumentLoc &operator[](unsigned I) const { return Arguments[I]; @@ -698,22 +703,6 @@ const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, const TemplateArgument &Arg); -inline TemplateSpecializationType::iterator - TemplateSpecializationType::end() const { - return getArgs() + getNumArgs(); -} - -inline DependentTemplateSpecializationType::iterator - DependentTemplateSpecializationType::end() const { - return getArgs() + getNumArgs(); -} - -inline const TemplateArgument & - TemplateSpecializationType::getArg(unsigned Idx) const { - assert(Idx < getNumArgs() && "Template argument out of range"); - return getArgs()[Idx]; -} - inline const TemplateArgument & DependentTemplateSpecializationType::getArg(unsigned Idx) const { assert(Idx < getNumArgs() && "Template argument out of range"); diff --git a/clang/include/clang/AST/TextNodeDumper.h b/clang/include/clang/AST/TextNodeDumper.h --- a/clang/include/clang/AST/TextNodeDumper.h +++ b/clang/include/clang/AST/TextNodeDumper.h @@ -318,6 +318,8 @@ void VisitTagType(const TagType *T); void VisitTemplateTypeParmType(const TemplateTypeParmType *T); void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T); + void + VisitSubstTemplateTypeParmPackType(const SubstTemplateTypeParmPackType *T); void VisitAutoType(const AutoType *T); void VisitDeducedTemplateSpecializationType( const DeducedTemplateSpecializationType *T); 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 @@ -1790,16 +1790,37 @@ unsigned NumArgs; }; + class UsingBitfields { + friend class UsingType; + + unsigned : NumTypeBits; + + /// True if this UsingType has underlying type different from decl. + unsigned hasDifferentUnderlyingType : 1; + }; + + class TypedefBitfields { + friend class TypedefType; + + unsigned : NumTypeBits; + + /// True if this typedef has underlying type different from decl. + unsigned hasDifferentUnderlyingType : 1; + }; + class SubstTemplateTypeParmTypeBitfields { friend class SubstTemplateTypeParmType; unsigned : NumTypeBits; + // The index of the template parameter this substitution represents. + unsigned Index : 16; + /// Represents the index within a pack if this represents a substitution /// from a pack expansion. /// Positive non-zero number represents the index + 1. /// Zero means this is not substituted from an expansion. - unsigned PackIndex; + unsigned PackIndex : 16; }; class SubstTemplateTypeParmPackTypeBitfields { @@ -1807,14 +1828,14 @@ unsigned : NumTypeBits; + // The index of the template parameter this substitution represents. + unsigned Index : 16; + /// The number of template arguments in \c Arguments, which is /// expected to be able to hold at least 1024 according to [implimits]. /// However as this limit is somewhat easy to hit with template /// metaprogramming we'd prefer to keep it as large as possible. - /// At the moment it has been left as a non-bitfield since this type - /// safely fits in 64 bits as an unsigned, so there is no reason to - /// introduce the performance impact of a bitfield. - unsigned NumArgs; + unsigned NumArgs : 16; }; class TemplateSpecializationTypeBitfields { @@ -1829,10 +1850,9 @@ /// specialization, which is expected to be able to hold at least 1024 /// according to [implimits]. However, as this limit is somewhat easy to /// hit with template metaprogramming we'd prefer to keep it as large - /// as possible. At the moment it has been left as a non-bitfield since - /// this type safely fits in 64 bits as an unsigned, so there is no reason - /// to introduce the performance impact of a bitfield. - unsigned NumArgs; + /// as possible. + unsigned NumSpecifiedArgs : 16; + unsigned NumConvertedArgs : 16; }; class DependentTemplateSpecializationTypeBitfields { @@ -1876,6 +1896,8 @@ ConstantArrayTypeBitfields ConstantArrayTypeBits; AttributedTypeBitfields AttributedTypeBits; AutoTypeBitfields AutoTypeBits; + TypedefBitfields TypedefBits; + UsingBitfields UsingBits; BuiltinTypeBitfields BuiltinTypeBits; FunctionTypeBitfields FunctionTypeBits; ObjCObjectTypeBitfields ObjCObjectTypeBits; @@ -2376,6 +2398,18 @@ /// immediately following this class. template const T *getAs() const; + /// Look through sugar for an instance of TemplateSpecializationType which + /// is not a type alias. + const TemplateSpecializationType * + getAsNonAliasTemplateSpecializationType() const; + + const TemplateSpecializationType * + castAsNonAliasTemplateSpecializationType() const { + auto TST = getAsNonAliasTemplateSpecializationType(); + assert(TST && "not a TemplateSpecializationType"); + return TST; + } + /// Member-template getAsAdjusted. Look through specific kinds /// of sugar (parens, attributes, etc) for an instance of \. /// This is used when you need to walk over sugar nodes that represent some @@ -4460,15 +4494,21 @@ public: UsingShadowDecl *getFoundDecl() const { return Found; } + bool hasDifferentUnderlyingType() const { + return UsingBits.hasDifferentUnderlyingType; + } QualType getUnderlyingType() const; bool isSugared() const { return true; } QualType desugar() const { return getUnderlyingType(); } - void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, Found); } - static void Profile(llvm::FoldingSetNodeID &ID, - const UsingShadowDecl *Found) { + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, Found, getUnderlyingType()); + } + static void Profile(llvm::FoldingSetNodeID &ID, const UsingShadowDecl *Found, + QualType Underlying) { ID.AddPointer(Found); + Underlying.Profile(ID); } static bool classof(const Type *T) { return T->getTypeClass() == Using; } }; @@ -4484,6 +4524,9 @@ public: TypedefNameDecl *getDecl() const { return Decl; } + bool hasDifferentUnderlyingType() const { + return TypedefBits.hasDifferentUnderlyingType; + } bool isSugared() const { return true; } QualType desugar() const; @@ -4984,26 +5027,25 @@ friend class ASTContext; // The original type parameter. - const TemplateTypeParmType *Replaced; + QualType Replacement; - SubstTemplateTypeParmType(const TemplateTypeParmType *Param, QualType Canon, - Optional PackIndex) - : Type(SubstTemplateTypeParm, Canon, Canon->getDependence()), - Replaced(Param) { - SubstTemplateTypeParmTypeBits.PackIndex = PackIndex ? *PackIndex + 1 : 0; - } + // The templated entity which owned the substituted type parameter. + Decl *ReplacedDecl; -public: - /// Gets the template parameter that was substituted for. - const TemplateTypeParmType *getReplacedParameter() const { - return Replaced; - } + SubstTemplateTypeParmType(QualType Replacement, Decl *ReplacedDecl, + unsigned Index, Optional PackIndex); +public: /// Gets the type that was substituted for the template /// parameter. - QualType getReplacementType() const { - return getCanonicalTypeInternal(); - } + QualType getReplacementType() const { return Replacement; } + + /// Gets the template specialization that was substituted. + Decl *getReplacedDecl() const { return ReplacedDecl; } + + const TemplateTypeParmDecl *getReplacedTemplateParam() const; + + unsigned getIndex() const { return SubstTemplateTypeParmTypeBits.Index; } Optional getPackIndex() const { if (SubstTemplateTypeParmTypeBits.PackIndex == 0) @@ -5015,14 +5057,16 @@ QualType desugar() const { return getReplacementType(); } void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getReplacedParameter(), getReplacementType(), getPackIndex()); + Profile(ID, getReplacementType(), getReplacedDecl(), getIndex(), + getPackIndex()); } - static void Profile(llvm::FoldingSetNodeID &ID, - const TemplateTypeParmType *Replaced, - QualType Replacement, Optional PackIndex) { - ID.AddPointer(Replaced); + static void Profile(llvm::FoldingSetNodeID &ID, QualType Replacement, + const Decl *ReplacedDecl, unsigned Index, + Optional PackIndex) { + ID.AddPointer(ReplacedDecl); ID.AddPointer(Replacement.getAsOpaquePtr()); + ID.AddInteger(Index); ID.AddInteger(PackIndex ? *PackIndex - 1 : 0); } @@ -5046,24 +5090,26 @@ class SubstTemplateTypeParmPackType : public Type, public llvm::FoldingSetNode { friend class ASTContext; - /// The original type parameter. - const TemplateTypeParmType *Replaced; - /// A pointer to the set of template arguments that this /// parameter pack is instantiated with. const TemplateArgument *Arguments; - SubstTemplateTypeParmPackType(const TemplateTypeParmType *Param, - QualType Canon, + // The template specialization which owned the substituted type parameter. + Decl *ReplacedDecl; + + SubstTemplateTypeParmPackType(QualType Canon, Decl *ReplacedDecl, + unsigned Index, const TemplateArgument &ArgPack); public: - IdentifierInfo *getIdentifier() const { return Replaced->getIdentifier(); } + IdentifierInfo *getIdentifier() const; - /// Gets the template parameter that was substituted for. - const TemplateTypeParmType *getReplacedParameter() const { - return Replaced; - } + /// Gets the template specialization that was substituted. + Decl *getReplacedDecl() const { return ReplacedDecl; } + + const TemplateTypeParmDecl *getReplacedTemplateParam() const; + + unsigned getIndex() const { return SubstTemplateTypeParmPackTypeBits.Index; } unsigned getNumArgs() const { return SubstTemplateTypeParmPackTypeBits.NumArgs; @@ -5075,9 +5121,8 @@ TemplateArgument getArgumentPack() const; void Profile(llvm::FoldingSetNodeID &ID); - static void Profile(llvm::FoldingSetNodeID &ID, - const TemplateTypeParmType *Replaced, - const TemplateArgument &ArgPack); + static void Profile(llvm::FoldingSetNodeID &ID, const Decl *ReplacedDecl, + unsigned Index, const TemplateArgument &ArgPack); static bool classof(const Type *T) { return T->getTypeClass() == SubstTemplateTypeParmPack; @@ -5272,9 +5317,12 @@ TemplateName Template; TemplateSpecializationType(TemplateName T, - ArrayRef Args, - QualType Canon, - QualType Aliased); + ArrayRef SpecifiedArgs, + ArrayRef ConvertedArgs, + QualType Canon, QualType Aliased); + + TemplateSpecializationType(TemplateName T, + ArrayRef ConvertedArgs); public: /// Determine whether any of the given template arguments are dependent. @@ -5320,38 +5368,19 @@ /// \endcode bool isTypeAlias() const { return TemplateSpecializationTypeBits.TypeAlias; } - /// Get the aliased type, if this is a specialization of a type alias - /// template. - QualType getAliasedType() const { - assert(isTypeAlias() && "not a type alias template specialization"); - return *reinterpret_cast(end()); - } - - using iterator = const TemplateArgument *; - - iterator begin() const { return getArgs(); } - iterator end() const; // defined inline in TemplateBase.h - /// Retrieve the name of the template that we are specializing. TemplateName getTemplateName() const { return Template; } - /// Retrieve the template arguments. - const TemplateArgument *getArgs() const { - return reinterpret_cast(this + 1); + ArrayRef getSpecifiedArguments() const { + return {reinterpret_cast(this + 1), + TemplateSpecializationTypeBits.NumSpecifiedArgs}; } - /// Retrieve the number of template arguments. - unsigned getNumArgs() const { - return TemplateSpecializationTypeBits.NumArgs; - } - - /// Retrieve a specific template argument as a type. - /// \pre \c isArgType(Arg) - const TemplateArgument &getArg(unsigned Idx) const; // in TemplateBase.h + ArrayRef getConvertedArguments() const; - ArrayRef template_arguments() const { - return {getArgs(), getNumArgs()}; - } + /// Get the aliased type, if this is a specialization of a type alias + /// template. + QualType getAliasedType() const; bool isSugared() const { return !isDependentType() || isCurrentInstantiation() || isTypeAlias(); @@ -5362,13 +5391,14 @@ } void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx) { - Profile(ID, Template, template_arguments(), Ctx); - if (isTypeAlias()) - getAliasedType().Profile(ID); + assert(getSpecifiedArguments().size() == 0); + assert(!isTypeAlias()); + assert(isCanonicalUnqualified()); + Profile(ID, Template, getConvertedArguments(), Ctx); } static void Profile(llvm::FoldingSetNodeID &ID, TemplateName T, - ArrayRef Args, + ArrayRef ConvertedArgs, const ASTContext &Context); static bool classof(const Type *T) { diff --git a/clang/include/clang/AST/TypeLoc.h b/clang/include/clang/AST/TypeLoc.h --- a/clang/include/clang/AST/TypeLoc.h +++ b/clang/include/clang/AST/TypeLoc.h @@ -901,7 +901,7 @@ } }; -struct BTFTagAttributedLocInfo {}; // Nothing. +struct alignas(4) BTFTagAttributedLocInfo {}; // Nothing. /// Type source information for an btf_tag attributed type. class BTFTagAttributedTypeLoc @@ -1634,7 +1634,7 @@ } unsigned getNumArgs() const { - return getTypePtr()->getNumArgs(); + return getTypePtr()->getSpecifiedArguments().size(); } void setArgLocInfo(unsigned i, TemplateArgumentLocInfo AI) { @@ -1646,7 +1646,8 @@ } TemplateArgumentLoc getArgLoc(unsigned i) const { - return TemplateArgumentLoc(getTypePtr()->getArg(i), getArgLocInfo(i)); + return TemplateArgumentLoc(getTypePtr()->getSpecifiedArguments()[i], + getArgLocInfo(i)); } SourceLocation getTemplateNameLoc() const { @@ -1681,12 +1682,12 @@ setTemplateNameLoc(Loc); setLAngleLoc(Loc); setRAngleLoc(Loc); - initializeArgLocs(Context, getNumArgs(), getTypePtr()->getArgs(), + initializeArgLocs(Context, getTypePtr()->getSpecifiedArguments(), getArgInfos(), Loc); } - static void initializeArgLocs(ASTContext &Context, unsigned NumArgs, - const TemplateArgument *Args, + static void initializeArgLocs(ASTContext &Context, + ArrayRef Args, TemplateArgumentLocInfo *ArgInfos, SourceLocation Loc); 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); }]>; } @@ -656,29 +652,27 @@ def : Property<"templateName", TemplateName> { let Read = [{ node->getTemplateName() }]; } - def : Property<"templateArguments", Array> { - let Read = [{ node->template_arguments() }]; + def : Property<"specifiedArguments", Array> { + let Read = [{ node->getSpecifiedArguments() }]; } - def : Property<"underlyingType", Optional> { + def : Property<"convertedArguments", Array> { + let Read = [{ node->getConvertedArguments() }]; + } + def : Property<"underlyingType", QualType> { let Read = [{ node->isTypeAlias() - ? llvm::Optional(node->getAliasedType()) + ? node->getAliasedType() : node->isCanonicalUnqualified() - ? llvm::None - : llvm::Optional(node->getCanonicalTypeInternal()) + ? QualType() : node->getCanonicalTypeInternal() }]; } def : Creator<[{ - QualType result; - if (!underlyingType) { - result = ctx.getCanonicalTemplateSpecializationType(templateName, - templateArguments); - } else { - result = ctx.getTemplateSpecializationType(templateName, - templateArguments, - *underlyingType); - } + QualType result = ctx.getTemplateSpecializationType(templateName, + specifiedArguments, + convertedArguments, + /*CanonicalConvertedArguments=*/{}, + underlyingType); if (dependent) const_cast(result.getTypePtr()) ->addDependence(TypeDependence::DependentInstantiation); @@ -728,21 +722,22 @@ } let Class = SubstTemplateTypeParmType in { - def : Property<"replacedParameter", QualType> { - let Read = [{ QualType(node->getReplacedParameter(), 0) }]; - } def : Property<"replacementType", QualType> { let Read = [{ node->getReplacementType() }]; } + def : Property<"replacedDecl", DeclRef> { + let Read = [{ node->getReplacedDecl() }]; + } + def : Property<"Index", UInt32> { + let Read = [{ node->getIndex() }]; + } def : Property<"PackIndex", Optional> { let Read = [{ node->getPackIndex() }]; } def : Creator<[{ - // The call to getCanonicalType here existed in ASTReader.cpp, too. return ctx.getSubstTemplateTypeParmType( - cast(replacedParameter), - ctx.getCanonicalType(replacementType), PackIndex); + replacementType, replacedDecl, Index, PackIndex); }]>; } @@ -761,8 +756,11 @@ } let Class = SubstTemplateTypeParmPackType in { - def : Property<"replacedParameter", QualType> { - let Read = [{ QualType(node->getReplacedParameter(), 0) }]; + def : Property<"replacedDecl", DeclRef> { + let Read = [{ node->getReplacedDecl() }]; + } + def : Property<"Index", UInt32> { + let Read = [{ node->getIndex() }]; } def : Property<"replacementPack", TemplateArgument> { let Read = [{ node->getArgumentPack() }]; @@ -770,8 +768,7 @@ def : Creator<[{ return ctx.getSubstTemplateTypeParmPackType( - cast(replacedParameter), - replacementPack); + replacedDecl, Index, replacementPack); }]>; } 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 @@ -1957,7 +1957,7 @@ inline ArrayRef getTemplateSpecializationArgs(const TemplateSpecializationType &T) { - return llvm::makeArrayRef(T.getArgs(), T.getNumArgs()); + return T.getSpecifiedArguments(); } inline ArrayRef 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 @@ -467,6 +467,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 @@ -5800,6 +5800,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/Overload.h b/clang/include/clang/Sema/Overload.h --- a/clang/include/clang/Sema/Overload.h +++ b/clang/include/clang/Sema/Overload.h @@ -885,6 +885,9 @@ StandardConversionSequence FinalConversion; }; + /// Deduced Arguments for Function Templates. + const TemplateArgumentList *Deduced; + /// Get RewriteKind value in OverloadCandidateRewriteKind type (This /// function is to workaround the spurious GCC bitfield enum warning) OverloadCandidateRewriteKind getRewriteKind() const { 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 @@ -3855,7 +3855,8 @@ bool AllowExplicitConversion = false, ADLCallKind IsADLCandidate = ADLCallKind::NotADL, ConversionSequenceList EarlyConversions = None, - OverloadCandidateParamOrder PO = {}); + OverloadCandidateParamOrder PO = {}, + const TemplateArgumentList *Deduced = nullptr); void AddFunctionCandidates(const UnresolvedSetImpl &Functions, ArrayRef Args, OverloadCandidateSet &CandidateSet, @@ -3870,16 +3871,16 @@ OverloadCandidateSet& CandidateSet, bool SuppressUserConversion = false, OverloadCandidateParamOrder PO = {}); - void AddMethodCandidate(CXXMethodDecl *Method, - DeclAccessPair FoundDecl, + void AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, QualType ObjectType, Expr::Classification ObjectClassification, ArrayRef Args, - OverloadCandidateSet& CandidateSet, + OverloadCandidateSet &CandidateSet, bool SuppressUserConversions = false, bool PartialOverloading = false, ConversionSequenceList EarlyConversions = None, - OverloadCandidateParamOrder PO = {}); + OverloadCandidateParamOrder PO = {}, + const TemplateArgumentList *Deduced = nullptr); void AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, @@ -4015,10 +4016,9 @@ bool resolveAndFixAddressOfSingleOverloadCandidate( ExprResult &SrcExpr, bool DoFunctionPointerConversion = false); - FunctionDecl * - ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl, - bool Complain = false, - DeclAccessPair *Found = nullptr); + FunctionDecl *ResolveSingleFunctionTemplateSpecialization( + OverloadExpr *ovl, TemplateArgumentListInfo &ExplicitTemplateArgs, + bool Complain = false, DeclAccessPair *Found = nullptr); bool ResolveAndFixSingleFunctionTemplateSpecialization( ExprResult &SrcExpr, @@ -4028,13 +4028,13 @@ QualType DestTypeForComplaining = QualType(), unsigned DiagIDForComplaining = 0); - - Expr *FixOverloadedFunctionReference(Expr *E, - DeclAccessPair FoundDecl, - FunctionDecl *Fn); - ExprResult FixOverloadedFunctionReference(ExprResult, - DeclAccessPair FoundDecl, - FunctionDecl *Fn); + Expr *FixOverloadedFunctionReference(Expr *E, DeclAccessPair FoundDecl, + FunctionDecl *Fn, + const TemplateArgumentList *Deduced); + ExprResult + FixOverloadedFunctionReference(ExprResult, DeclAccessPair FoundDecl, + FunctionDecl *Fn, + const TemplateArgumentList *Deduced); void AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE, ArrayRef Args, @@ -5452,13 +5452,11 @@ SourceLocation TemplateKWLoc = SourceLocation(), const TemplateArgumentListInfo *TemplateArgs = nullptr); - ExprResult - BuildAnonymousStructUnionMemberReference( - const CXXScopeSpec &SS, - SourceLocation nameLoc, + ExprResult BuildAnonymousStructUnionMemberReference( + const CXXScopeSpec &SS, SourceLocation nameLoc, IndirectFieldDecl *indirectField, DeclAccessPair FoundDecl = DeclAccessPair::make(nullptr, AS_none), - Expr *baseObjectExpr = nullptr, + Expr *baseObjectExpr = nullptr, const Type *BaseType = nullptr, SourceLocation opLoc = SourceLocation()); ExprResult BuildPossibleImplicitMemberExpr( @@ -5649,7 +5647,8 @@ ExprResult BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow, SourceLocation OpLoc, - const CXXScopeSpec &SS, FieldDecl *Field, + const NestedNameSpecifierLoc &NNS, + FieldDecl *Field, QualType FieldType, DeclAccessPair FoundDecl, const DeclarationNameInfo &MemberNameInfo); @@ -5675,22 +5674,20 @@ UnqualifiedId &Member, Decl *ObjCImpDecl); - MemberExpr * - BuildMemberExpr(Expr *Base, bool IsArrow, SourceLocation OpLoc, - const CXXScopeSpec *SS, SourceLocation TemplateKWLoc, - ValueDecl *Member, DeclAccessPair FoundDecl, - bool HadMultipleCandidates, - const DeclarationNameInfo &MemberNameInfo, QualType Ty, - ExprValueKind VK, ExprObjectKind OK, - const TemplateArgumentListInfo *TemplateArgs = nullptr); - MemberExpr * - BuildMemberExpr(Expr *Base, bool IsArrow, SourceLocation OpLoc, - NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc, - ValueDecl *Member, DeclAccessPair FoundDecl, - bool HadMultipleCandidates, - const DeclarationNameInfo &MemberNameInfo, QualType Ty, - ExprValueKind VK, ExprObjectKind OK, - const TemplateArgumentListInfo *TemplateArgs = nullptr); + MemberExpr *BuildMemberExpr( + Expr *Base, bool IsArrow, SourceLocation OpLoc, const CXXScopeSpec *SS, + SourceLocation TemplateKWLoc, ValueDecl *Member, DeclAccessPair FoundDecl, + bool HadMultipleCandidates, const DeclarationNameInfo &MemberNameInfo, + QualType Ty, ExprValueKind VK, ExprObjectKind OK, + const TemplateArgumentListInfo *TemplateArgs = nullptr, + const TemplateArgumentList *Deduced = nullptr); + MemberExpr *BuildMemberExpr( + Expr *Base, bool IsArrow, SourceLocation OpLoc, + NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc, + ValueDecl *Member, DeclAccessPair FoundDecl, bool HadMultipleCandidates, + const DeclarationNameInfo &MemberNameInfo, QualType Ty, ExprValueKind VK, + ExprObjectKind OK, const TemplateArgumentListInfo *TemplateArgs = nullptr, + const TemplateArgumentList *Deduced = nullptr); void ActOnDefaultCtorInitializers(Decl *CDtorDecl); bool ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, @@ -7927,9 +7924,9 @@ void NoteAllFoundTemplates(TemplateName Name); - QualType CheckTemplateIdType(TemplateName Template, + QualType CheckTemplateIdType(const CXXScopeSpec &SS, TemplateName Template, SourceLocation TemplateLoc, - TemplateArgumentListInfo &TemplateArgs); + TemplateArgumentListInfo &TemplateArgs); TypeResult ActOnTemplateIdType(Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, @@ -8080,14 +8077,13 @@ CTAK_DeducedFromArrayBound }; - bool CheckTemplateArgument(NamedDecl *Param, - TemplateArgumentLoc &Arg, - NamedDecl *Template, - SourceLocation TemplateLoc, - SourceLocation RAngleLoc, - unsigned ArgumentPackIndex, - SmallVectorImpl &Converted, - CheckTemplateArgumentKind CTAK = CTAK_Specified); + bool + CheckTemplateArgument(NamedDecl *Param, TemplateArgumentLoc &Arg, + NamedDecl *Template, SourceLocation TemplateLoc, + SourceLocation RAngleLoc, unsigned ArgumentPackIndex, + SmallVectorImpl &SugaredConverted, + SmallVectorImpl &CanonicalConverted, + CheckTemplateArgumentKind CTAK); /// Check that the given template arguments can be be provided to /// the given template, converting the arguments along the way. @@ -8118,23 +8114,25 @@ /// the template not being satisfied by the template arguments. /// /// \returns true if an error occurred, false otherwise. - bool CheckTemplateArgumentList(TemplateDecl *Template, - SourceLocation TemplateLoc, - TemplateArgumentListInfo &TemplateArgs, - bool PartialTemplateArgs, - SmallVectorImpl &Converted, - bool UpdateArgsWithConversions = true, - bool *ConstraintsNotSatisfied = nullptr); - - bool CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, - TemplateArgumentLoc &Arg, - SmallVectorImpl &Converted); + bool CheckTemplateArgumentList( + TemplateDecl *Template, SourceLocation TemplateLoc, + TemplateArgumentListInfo &TemplateArgs, bool PartialTemplateArgs, + SmallVectorImpl &SugaredConverted, + SmallVectorImpl &CanonicalConverted, + bool UpdateArgsWithConversions = true, + bool *ConstraintsNotSatisfied = nullptr); + + bool CheckTemplateTypeArgument( + TemplateTypeParmDecl *Param, TemplateArgumentLoc &Arg, + SmallVectorImpl &SugaredConverted, + SmallVectorImpl &CanonicalConverted); bool CheckTemplateArgument(TypeSourceInfo *Arg); ExprResult CheckTemplateArgument(NonTypeTemplateParmDecl *Param, QualType InstantiatedParamType, Expr *Arg, - TemplateArgument &Converted, - CheckTemplateArgumentKind CTAK = CTAK_Specified); + TemplateArgument &SugaredConverted, + TemplateArgument &CanonicalConverted, + CheckTemplateArgumentKind CTAK); bool CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param, TemplateParameterList *Params, TemplateArgumentLoc &Arg); @@ -9614,6 +9612,29 @@ } }; + QualType resugar(const CXXScopeSpec &SS, QualType T); + + QualType resugar(const CXXScopeSpec &SS, NamedDecl *ND, + ArrayRef Args, QualType T); + QualType resugar(const CXXScopeSpec &SS, NamedDecl *ND, + ArrayRef Args, QualType T); + + QualType resugar(const Type *Base, NestedNameSpecifierLoc &FieldNNS, + QualType T); + + QualType resugar(const Type *Base, NestedNameSpecifierLoc &FieldNNS, + NamedDecl *ND, ArrayRef Args, + QualType T); + QualType resugar(const Type *Base, NestedNameSpecifierLoc &FieldNNS, + NamedDecl *ND, ArrayRef Args, QualType T); + + QualType resugar(const Type *Base, QualType T); + + QualType resugar(const Type *Base, NamedDecl *ND, + ArrayRef Args, QualType T); + QualType resugar(const Type *Base, NamedDecl *ND, + ArrayRef Args, QualType T); + void PerformPendingInstantiations(bool LocalOnly = false); TypeSourceInfo *SubstType(TypeSourceInfo *T, diff --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h --- a/clang/include/clang/Sema/Template.h +++ b/clang/include/clang/Sema/Template.h @@ -74,13 +74,20 @@ /// template argument list (17) at depth 1. class MultiLevelTemplateArgumentList { /// The template argument list at a certain template depth + using ArgList = ArrayRef; - using ArgListsIterator = SmallVector::iterator; - using ConstArgListsIterator = SmallVector::const_iterator; + struct ArgumentListLevel { + Decl *ReplacedDecl; + ArgList Args; + }; + using ContainerType = SmallVector; + + using ArgListsIterator = ContainerType::iterator; + using ConstArgListsIterator = ContainerType::const_iterator; /// The template argument lists, stored from the innermost template /// argument list (first) to the outermost template argument list (last). - SmallVector TemplateArgumentLists; + ContainerType TemplateArgumentLists; /// The number of outer levels of template arguments that are not /// being substituted. @@ -94,9 +101,8 @@ MultiLevelTemplateArgumentList() = default; /// Construct a single-level template argument list. - explicit - MultiLevelTemplateArgumentList(const TemplateArgumentList &TemplateArgs) { - addOuterTemplateArguments(&TemplateArgs); + explicit MultiLevelTemplateArgumentList(Decl *D, ArgList Args) { + addOuterTemplateArguments(D, Args); } void setKind(TemplateSubstitutionKind K) { Kind = K; } @@ -126,7 +132,7 @@ // Determine the number of substituted args at 'Depth'. unsigned getNumSubsitutedArgs(unsigned Depth) const { assert(NumRetainedOuterLevels <= Depth && Depth < getNumLevels()); - return TemplateArgumentLists[getNumLevels() - Depth - 1].size(); + return TemplateArgumentLists[getNumLevels() - Depth - 1].Args.size(); } unsigned getNumRetainedOuterLevels() const { @@ -146,8 +152,14 @@ /// Retrieve the template argument at a given depth and index. const TemplateArgument &operator()(unsigned Depth, unsigned Index) const { assert(NumRetainedOuterLevels <= Depth && Depth < getNumLevels()); - assert(Index < TemplateArgumentLists[getNumLevels() - Depth - 1].size()); - return TemplateArgumentLists[getNumLevels() - Depth - 1][Index]; + assert(Index < + TemplateArgumentLists[getNumLevels() - Depth - 1].Args.size()); + return TemplateArgumentLists[getNumLevels() - Depth - 1].Args[Index]; + } + + Decl *getReplacedDecl(unsigned Depth) const { + assert(NumRetainedOuterLevels <= Depth && Depth < getNumLevels()); + return TemplateArgumentLists[getNumLevels() - Depth - 1].ReplacedDecl; } /// Determine whether there is a non-NULL template argument at the @@ -160,15 +172,16 @@ if (Depth < NumRetainedOuterLevels) return false; - if (Index >= TemplateArgumentLists[getNumLevels() - Depth - 1].size()) + if (Index >= + TemplateArgumentLists[getNumLevels() - Depth - 1].Args.size()) return false; return !(*this)(Depth, Index).isNull(); } bool isAnyArgInstantiationDependent() const { - for (ArgList List : TemplateArgumentLists) - for (const TemplateArgument &TA : List) + for (ArgumentListLevel ListLevel : TemplateArgumentLists) + for (const TemplateArgument &TA : ListLevel.Args) if (TA.isInstantiationDependent()) return true; return false; @@ -178,25 +191,34 @@ void setArgument(unsigned Depth, unsigned Index, TemplateArgument Arg) { assert(NumRetainedOuterLevels <= Depth && Depth < getNumLevels()); - assert(Index < TemplateArgumentLists[getNumLevels() - Depth - 1].size()); - const_cast( - TemplateArgumentLists[getNumLevels() - Depth - 1][Index]) - = Arg; + assert(Index < + TemplateArgumentLists[getNumLevels() - Depth - 1].Args.size()); + const_cast( + TemplateArgumentLists[getNumLevels() - Depth - 1].Args[Index]) = Arg; } - /// Add a new outermost level to the multi-level template argument + /// Add a new outmost level to the multi-level template argument /// list. - void addOuterTemplateArguments(const TemplateArgumentList *TemplateArgs) { - addOuterTemplateArguments(ArgList(TemplateArgs->data(), - TemplateArgs->size())); + void addOuterTemplateArguments(Decl *ReplacedDecl, ArgList Args) { + assert(!NumRetainedOuterLevels && + "substituted args outside retained args?"); + assert(getKind() == TemplateSubstitutionKind::Specialization); + assert(ReplacedDecl != nullptr || Args.size() == 0); + TemplateArgumentLists.push_back( + {ReplacedDecl ? ReplacedDecl->getCanonicalDecl() : nullptr, Args}); } - /// Add a new outmost level to the multi-level template argument - /// list. void addOuterTemplateArguments(ArgList Args) { assert(!NumRetainedOuterLevels && "substituted args outside retained args?"); - TemplateArgumentLists.push_back(Args); + assert(getKind() == TemplateSubstitutionKind::Rewrite); + TemplateArgumentLists.push_back({nullptr, Args}); + } + + void addOuterTemplateArguments(llvm::NoneType) { + assert(!NumRetainedOuterLevels && + "substituted args outside retained args?"); + TemplateArgumentLists.push_back({}); } /// Replaces the current 'innermost' level with the provided argument list. @@ -204,7 +226,7 @@ /// list from the AST, but then add the deduced innermost list. void replaceInnermostTemplateArguments(ArgList Args) { assert(TemplateArgumentLists.size() > 0 && "Replacing in an empty list?"); - TemplateArgumentLists[0] = Args; + TemplateArgumentLists[0].Args = Args; } /// Add an outermost level that we are not substituting. We have no @@ -219,11 +241,11 @@ /// Retrieve the innermost template argument list. const ArgList &getInnermost() const { - return TemplateArgumentLists.front(); + return TemplateArgumentLists.front().Args; } /// Retrieve the outermost template argument list. const ArgList &getOutermost() const { - return TemplateArgumentLists.back(); + return TemplateArgumentLists.back().Args; } ArgListsIterator begin() { return TemplateArgumentLists.begin(); } ConstArgListsIterator begin() const { diff --git a/clang/include/clang/Sema/TemplateDeduction.h b/clang/include/clang/Sema/TemplateDeduction.h --- a/clang/include/clang/Sema/TemplateDeduction.h +++ b/clang/include/clang/Sema/TemplateDeduction.h @@ -41,7 +41,7 @@ /// TemplateDeductionResult value. class TemplateDeductionInfo { /// The deduced template argument list. - TemplateArgumentList *Deduced = nullptr; + TemplateArgumentList *DeducedSugared = nullptr, *DeducedCanonical = nullptr; /// The source location at which template argument /// deduction is occurring. @@ -71,8 +71,8 @@ /// Create temporary template deduction info for speculatively deducing /// against a base class of an argument's type. TemplateDeductionInfo(ForBaseTag, const TemplateDeductionInfo &Info) - : Deduced(Info.Deduced), Loc(Info.Loc), DeducedDepth(Info.DeducedDepth), - ExplicitArgs(Info.ExplicitArgs) {} + : DeducedSugared(Info.DeducedSugared), Loc(Info.Loc), + DeducedDepth(Info.DeducedDepth), ExplicitArgs(Info.ExplicitArgs) {} /// Returns the location at which template argument is /// occurring. @@ -91,10 +91,15 @@ return ExplicitArgs; } - /// Take ownership of the deduced template argument list. - TemplateArgumentList *take() { - TemplateArgumentList *Result = Deduced; - Deduced = nullptr; + /// Take ownership of the deduced template argument lists. + TemplateArgumentList *takeSugared() { + TemplateArgumentList *Result = DeducedSugared; + DeducedSugared = nullptr; + return Result; + } + TemplateArgumentList *takeCanonical() { + TemplateArgumentList *Result = DeducedCanonical; + DeducedCanonical = nullptr; return Result; } @@ -120,15 +125,20 @@ /// Provide an initial template argument list that contains the /// explicitly-specified arguments. - void setExplicitArgs(TemplateArgumentList *NewDeduced) { - Deduced = NewDeduced; - ExplicitArgs = Deduced->size(); + void setExplicitArgs(TemplateArgumentList *NewDeducedSugared, + TemplateArgumentList *NewDeducedCanonical) { + assert(NewDeducedSugared->size() == NewDeducedCanonical->size()); + DeducedSugared = NewDeducedSugared; + DeducedCanonical = NewDeducedCanonical; + ExplicitArgs = DeducedSugared->size(); } /// Provide a new template argument list that contains the /// results of template argument deduction. - void reset(TemplateArgumentList *NewDeduced) { - Deduced = NewDeduced; + void reset(TemplateArgumentList *NewDeducedSugared, + TemplateArgumentList *NewDeducedCanonical) { + DeducedSugared = NewDeducedSugared; + DeducedCanonical = NewDeducedCanonical; } /// Is a SFINAE diagnostic available? diff --git a/clang/include/clang/Serialization/ASTRecordReader.h b/clang/include/clang/Serialization/ASTRecordReader.h --- a/clang/include/clang/Serialization/ASTRecordReader.h +++ b/clang/include/clang/Serialization/ASTRecordReader.h @@ -249,6 +249,10 @@ void readTemplateArgumentList(SmallVectorImpl &TemplArgs, bool Canonicalize = false); + /// Read a template argument list. + const TemplateArgumentList * + readTemplateArgumentList(bool Canonicalize = false); + /// Read a UnresolvedSet structure, advancing Idx. void readUnresolvedSet(LazyASTUnresolvedSet &Set); 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 @@ -2367,12 +2367,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 { @@ -4630,14 +4630,22 @@ /// specified typedef name decl. QualType ASTContext::getTypedefType(const TypedefNameDecl *Decl, QualType Underlying) const { - if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 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; + 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() || Decl->getUnderlyingType() == Underlying) + return QualType(Decl->TypeForDecl, 0); + assert(hasSameType(Decl->getUnderlyingType(), Underlying)); + // 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); } @@ -4645,19 +4653,26 @@ QualType ASTContext::getUsingType(const UsingShadowDecl *Found, QualType Underlying) const { llvm::FoldingSetNodeID ID; - UsingType::Profile(ID, Found); + UsingType::Profile(ID, Found, Underlying); void *InsertPos = nullptr; UsingType *T = UsingTypes.FindNodeOrInsertPos(ID, InsertPos); if (T) return QualType(T, 0); + const Type *TypeForDecl = + cast(Found->getTargetDecl())->getTypeForDecl(); + assert(!Underlying.hasLocalQualifiers()); - assert(Underlying == getTypeDeclType(cast(Found->getTargetDecl()))); - QualType Canon = Underlying.getCanonicalType(); + QualType Canon = Underlying->getCanonicalTypeInternal(); + assert(TypeForDecl->getCanonicalTypeInternal() == Canon); - UsingType *NewType = - new (*this, TypeAlignment) UsingType(Found, Underlying, Canon); + if (Underlying.getTypePtr() == TypeForDecl) + Underlying = QualType(); + void *Mem = Allocate(sizeof(UsingType) + + (!Underlying.isNull() ? sizeof(QualType) : 0), + TypeAlignment); + UsingType *NewType = new (Mem) UsingType(Found, Underlying, Canon); Types.push_back(NewType); UsingTypes.InsertNode(NewType, InsertPos); return QualType(NewType, 0); @@ -4747,21 +4762,19 @@ /// Retrieve a substitution-result type. QualType -ASTContext::getSubstTemplateTypeParmType(const TemplateTypeParmType *Parm, - QualType Replacement, +ASTContext::getSubstTemplateTypeParmType(QualType Replacement, + Decl *ReplacedDecl, unsigned Index, Optional PackIndex) const { - assert(Replacement.isCanonical() - && "replacement types must always be canonical"); - llvm::FoldingSetNodeID ID; - SubstTemplateTypeParmType::Profile(ID, Parm, Replacement, PackIndex); + SubstTemplateTypeParmType::Profile(ID, Replacement, ReplacedDecl, Index, + PackIndex); void *InsertPos = nullptr; - SubstTemplateTypeParmType *SubstParm - = SubstTemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos); + SubstTemplateTypeParmType *SubstParm = + SubstTemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos); if (!SubstParm) { SubstParm = new (*this, TypeAlignment) - SubstTemplateTypeParmType(Parm, Replacement, PackIndex); + SubstTemplateTypeParmType(Replacement, ReplacedDecl, Index, PackIndex); Types.push_back(SubstParm); SubstTemplateTypeParmTypes.InsertNode(SubstParm, InsertPos); } @@ -4770,34 +4783,34 @@ } /// Retrieve a -QualType ASTContext::getSubstTemplateTypeParmPackType( - const TemplateTypeParmType *Parm, - const TemplateArgument &ArgPack) { +QualType +ASTContext::getSubstTemplateTypeParmPackType(Decl *ReplacedDecl, unsigned Index, + const TemplateArgument &ArgPack) { + // FIXME: Allow non-canonical argument pack. #ifndef NDEBUG for (const auto &P : ArgPack.pack_elements()) { - assert(P.getKind() == TemplateArgument::Type &&"Pack contains a non-type"); + assert(P.getKind() == TemplateArgument::Type && "Pack contains a non-type"); assert(P.getAsType().isCanonical() && "Pack contains non-canonical type"); } #endif llvm::FoldingSetNodeID ID; - SubstTemplateTypeParmPackType::Profile(ID, Parm, ArgPack); + SubstTemplateTypeParmPackType::Profile(ID, ReplacedDecl, Index, ArgPack); void *InsertPos = nullptr; - if (SubstTemplateTypeParmPackType *SubstParm - = SubstTemplateTypeParmPackTypes.FindNodeOrInsertPos(ID, InsertPos)) + if (SubstTemplateTypeParmPackType *SubstParm = + SubstTemplateTypeParmPackTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(SubstParm, 0); QualType Canon; - if (!Parm->isCanonicalUnqualified()) { - Canon = getCanonicalType(QualType(Parm, 0)); - Canon = getSubstTemplateTypeParmPackType(cast(Canon), - ArgPack); + // FIXME: handle non-canonical pack. + if (!ReplacedDecl->isCanonicalDecl()) { + Canon = getSubstTemplateTypeParmPackType(ReplacedDecl->getCanonicalDecl(), + Index, ArgPack); SubstTemplateTypeParmPackTypes.FindNodeOrInsertPos(ID, InsertPos); } - auto *SubstParm - = new (*this, TypeAlignment) SubstTemplateTypeParmPackType(Parm, Canon, - ArgPack); + auto *SubstParm = new (*this, TypeAlignment) + SubstTemplateTypeParmPackType(Canon, ReplacedDecl, Index, ArgPack); Types.push_back(SubstParm); SubstTemplateTypeParmPackTypes.InsertNode(SubstParm, InsertPos); return QualType(SubstParm, 0); @@ -4836,40 +4849,46 @@ return QualType(TypeParm, 0); } -TypeSourceInfo * -ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name, - SourceLocation NameLoc, - const TemplateArgumentListInfo &Args, - QualType Underlying) const { +TypeSourceInfo *ASTContext::getTemplateSpecializationTypeInfo( + TemplateName Name, SourceLocation NameLoc, + const TemplateArgumentListInfo &SpecifiedArgs, + ArrayRef SugaredConvertedArgs, + ArrayRef CanonicalConvertedArgs, + QualType Underlying) const { assert(!Name.getAsDependentTemplateName() && "No dependent template names here!"); - QualType TST = getTemplateSpecializationType(Name, Args, Underlying); + QualType TST = getTemplateSpecializationType( + Name, SpecifiedArgs.arguments(), SugaredConvertedArgs, + CanonicalConvertedArgs, Underlying); TypeSourceInfo *DI = CreateTypeSourceInfo(TST); TemplateSpecializationTypeLoc TL = DI->getTypeLoc().castAs(); TL.setTemplateKeywordLoc(SourceLocation()); TL.setTemplateNameLoc(NameLoc); - TL.setLAngleLoc(Args.getLAngleLoc()); - TL.setRAngleLoc(Args.getRAngleLoc()); + TL.setLAngleLoc(SpecifiedArgs.getLAngleLoc()); + TL.setRAngleLoc(SpecifiedArgs.getRAngleLoc()); for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) - TL.setArgLocInfo(i, Args[i].getLocInfo()); + TL.setArgLocInfo(i, SpecifiedArgs[i].getLocInfo()); return DI; } -QualType -ASTContext::getTemplateSpecializationType(TemplateName Template, - const TemplateArgumentListInfo &Args, - QualType Underlying) const { +QualType ASTContext::getTemplateSpecializationType( + TemplateName Template, ArrayRef SpecifiedArgs, + ArrayRef SugaredConvertedArgs, + ArrayRef CanonicalConvertedArgs, + QualType Underlying) const { assert(!Template.getAsDependentTemplateName() && "No dependent template names here!"); - SmallVector ArgVec; - ArgVec.reserve(Args.size()); - for (const TemplateArgumentLoc &Arg : Args.arguments()) - ArgVec.push_back(Arg.getArgument()); + SmallVector SpecifiedArgVec; + SpecifiedArgVec.reserve(SpecifiedArgs.size()); + for (const TemplateArgumentLoc &Arg : SpecifiedArgs) + SpecifiedArgVec.push_back(Arg.getArgument()); - return getTemplateSpecializationType(Template, ArgVec, Underlying); + return getTemplateSpecializationType(Template, SpecifiedArgVec, + SugaredConvertedArgs, + CanonicalConvertedArgs, Underlying); } #ifndef NDEBUG @@ -4882,66 +4901,80 @@ } #endif -QualType -ASTContext::getTemplateSpecializationType(TemplateName Template, - ArrayRef Args, - QualType Underlying) const { +bool ASTContext::getCanonicalTemplateArguments( + ArrayRef OrigArgs, + SmallVectorImpl &CanonArgs) const { + bool AnyNonCanonArgs = false; + unsigned NumArgs = OrigArgs.size(); + CanonArgs.resize(NumArgs); + for (unsigned I = 0; I != NumArgs; ++I) { + TemplateArgument OrigArg = OrigArgs[I]; + TemplateArgument &CanonArg = CanonArgs[I]; + CanonArg = getCanonicalTemplateArgument(OrigArg); + if (!CanonArg.structurallyEquals(OrigArg)) + AnyNonCanonArgs = true; + } + return AnyNonCanonArgs; +} + +QualType ASTContext::getTemplateSpecializationType( + TemplateName Template, ArrayRef SpecifiedArgs, + ArrayRef SugaredConvertedArgs, + ArrayRef CanonicalConvertedArgs, + QualType Underlying) const { assert(!Template.getAsDependentTemplateName() && "No dependent template names here!"); + assert(SugaredConvertedArgs.size() != 0); // Look through qualified template names. if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) Template = QTN->getUnderlyingTemplate(); - bool IsTypeAlias = - isa_and_nonnull(Template.getAsTemplateDecl()); + const auto *TD = Template.getAsTemplateDecl(); + bool IsTypeAlias = TD && TD->isTypeAlias(); QualType CanonType; if (!Underlying.isNull()) CanonType = getCanonicalType(Underlying); else { // We can get here with an alias template when the specialization contains // a pack expansion that does not match up with a parameter pack. - assert((!IsTypeAlias || hasAnyPackExpansions(Args)) && + assert((!IsTypeAlias || hasAnyPackExpansions(SpecifiedArgs)) && "Caller must compute aliased type"); IsTypeAlias = false; - CanonType = getCanonicalTemplateSpecializationType(Template, Args); + SmallVector CanonArgsVec; + if (CanonicalConvertedArgs.size() == 0) { + getCanonicalTemplateArguments(SugaredConvertedArgs, CanonArgsVec); + CanonicalConvertedArgs = CanonArgsVec; + } + CanonType = getCanonicalTemplateSpecializationType(Template, + CanonicalConvertedArgs); } // Allocate the (non-canonical) template specialization type, but don't // try to unique it: these types typically have location information that // we don't unique and don't want to lose. - void *Mem = Allocate(sizeof(TemplateSpecializationType) + - sizeof(TemplateArgument) * Args.size() + - (IsTypeAlias? sizeof(QualType) : 0), - TypeAlignment); - auto *Spec - = new (Mem) TemplateSpecializationType(Template, Args, CanonType, - IsTypeAlias ? Underlying : QualType()); + void *Mem = + Allocate(sizeof(TemplateSpecializationType) + + sizeof(TemplateArgument) * + (SpecifiedArgs.size() + SugaredConvertedArgs.size()) + + (IsTypeAlias ? sizeof(QualType) : 0), + TypeAlignment); + auto *Spec = new (Mem) TemplateSpecializationType( + Template, SpecifiedArgs, SugaredConvertedArgs, CanonType, + IsTypeAlias ? Underlying : QualType()); Types.push_back(Spec); 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 { + TemplateName Template, ArrayRef ConvertedArgs) const { assert(!Template.getAsDependentTemplateName() && "No dependent template names here!"); + assert(ConvertedArgs.size() != 0); +#ifndef NDEBUG + for (const TemplateArgument &A : ConvertedArgs) + assert(A.structurallyEquals(getCanonicalTemplateArgument(A))); +#endif // Look through qualified template names. if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) @@ -4949,27 +4982,22 @@ // Build the canonical template specialization type. TemplateName CanonTemplate = getCanonicalTemplateName(Template); - SmallVector CanonArgs; - ::getCanonicalTemplateArguments(*this, Args, CanonArgs); // Determine whether this canonical template specialization type already // exists. llvm::FoldingSetNodeID ID; - TemplateSpecializationType::Profile(ID, CanonTemplate, - CanonArgs, *this); + TemplateSpecializationType::Profile(ID, CanonTemplate, ConvertedArgs, *this); void *InsertPos = nullptr; - TemplateSpecializationType *Spec - = TemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos); + TemplateSpecializationType *Spec = + TemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos); if (!Spec) { // Allocate a new canonical template specialization type. void *Mem = Allocate((sizeof(TemplateSpecializationType) + - sizeof(TemplateArgument) * CanonArgs.size()), + sizeof(TemplateArgument) * ConvertedArgs.size()), TypeAlignment); - Spec = new (Mem) TemplateSpecializationType(CanonTemplate, - CanonArgs, - QualType(), QualType()); + Spec = new (Mem) TemplateSpecializationType(CanonTemplate, ConvertedArgs); Types.push_back(Spec); TemplateSpecializationTypes.InsertNode(Spec, InsertPos); } @@ -5070,12 +5098,9 @@ return QualType(T, 0); } -QualType -ASTContext::getDependentTemplateSpecializationType( - ElaboratedTypeKeyword Keyword, - NestedNameSpecifier *NNS, - const IdentifierInfo *Name, - const TemplateArgumentListInfo &Args) const { +QualType ASTContext::getDependentTemplateSpecializationType( + ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, + const IdentifierInfo *Name, ArrayRef Args) const { // TODO: avoid this copy SmallVector ArgCopy; for (unsigned I = 0, E = Args.size(); I != E; ++I) @@ -5108,8 +5133,7 @@ if (Keyword == ETK_None) CanonKeyword = ETK_Typename; SmallVector CanonArgs; - bool AnyNonCanonArgs = - ::getCanonicalTemplateArguments(*this, Args, CanonArgs); + bool AnyNonCanonArgs = getCanonicalTemplateArguments(Args, CanonArgs); QualType Canon; if (AnyNonCanonArgs || CanonNNS != NNS || CanonKeyword != Keyword) { @@ -5728,7 +5752,7 @@ if (DeducedType.isNull()) { SmallVector CanonArgs; bool AnyNonCanonArgs = - ::getCanonicalTemplateArguments(*this, TypeConstraintArgs, CanonArgs); + getCanonicalTemplateArguments(TypeConstraintArgs, CanonArgs); if (AnyNonCanonArgs) { Canon = getAutoTypeInternal(QualType(), Keyword, IsDependent, IsPack, TypeConstraintConcept, CanonArgs, true); @@ -7268,8 +7292,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(); } @@ -12599,12 +12622,15 @@ case Type::TemplateSpecialization: { const auto *TX = cast(X), *TY = cast(Y); - auto As = getCommonTemplateArguments(Ctx, TX->template_arguments(), - TY->template_arguments()); + auto SpecAs = getCommonTemplateArguments(Ctx, TX->getSpecifiedArguments(), + TY->getSpecifiedArguments()); + auto ConvAs = getCommonTemplateArguments(Ctx, TX->getConvertedArguments(), + TY->getConvertedArguments()); return Ctx.getTemplateSpecializationType( ::getCommonTemplateNameChecked(Ctx, TX->getTemplateName(), TY->getTemplateName()), - As, X->getCanonicalTypeInternal()); + SpecAs, ConvAs, /*CanonicalConvertedArgs=*/{}, + X->getCanonicalTypeInternal()); } case Type::DependentName: { const auto *NX = cast(X), @@ -12777,16 +12803,15 @@ case Type::SubstTemplateTypeParm: { const auto *SX = cast(X), *SY = cast(Y); + unsigned Index = SX->getIndex(); auto PackIndex = SX->getPackIndex(); - if (PackIndex != SY->getPackIndex()) + if (Index != SY->getIndex() || PackIndex != SY->getPackIndex()) return QualType(); - - const TemplateTypeParmType *PX = SX->getReplacedParameter(); - if (PX != SY->getReplacedParameter()) + Decl *CD = ::getCommonDecl(SX->getReplacedDecl(), SY->getReplacedDecl()); + if (!CD) return QualType(); - - return Ctx.getSubstTemplateTypeParmType( - PX, Ctx.getQualifiedType(Underlying), PackIndex); + return Ctx.getSubstTemplateTypeParmType(Ctx.getQualifiedType(Underlying), + CD, Index, PackIndex); } case Type::ObjCTypeParam: // FIXME: Try to merge these. @@ -12801,11 +12826,14 @@ TY->getTemplateName()); if (!CTN.getAsVoidPointer()) return QualType(); - SmallVector As; - if (getCommonTemplateArguments(Ctx, As, TX->template_arguments(), - TY->template_arguments())) + SmallVector SpecAs; + if (getCommonTemplateArguments(Ctx, SpecAs, TX->getSpecifiedArguments(), + TY->getSpecifiedArguments())) return QualType(); - return Ctx.getTemplateSpecializationType(CTN, As, + auto ConvAs = getCommonTemplateArguments(Ctx, TX->getConvertedArguments(), + TY->getConvertedArguments()); + return Ctx.getTemplateSpecializationType(CTN, SpecAs, ConvAs, + /*CanonicalConvertedArgs=*/{}, Ctx.getQualifiedType(Underlying)); } case Type::Typedef: { diff --git a/clang/lib/AST/ASTDiagnostic.cpp b/clang/lib/AST/ASTDiagnostic.cpp --- a/clang/lib/AST/ASTDiagnostic.cpp +++ b/clang/lib/AST/ASTDiagnostic.cpp @@ -118,8 +118,7 @@ if (!TST->isTypeAlias()) { bool DesugarArgument = false; SmallVector Args; - for (unsigned I = 0, N = TST->getNumArgs(); I != N; ++I) { - const TemplateArgument &Arg = TST->getArg(I); + for (const TemplateArgument &Arg : TST->getSpecifiedArguments()) { if (Arg.getKind() == TemplateArgument::Type) Args.push_back(desugarForDiagnostic(Context, Arg.getAsType(), DesugarArgument)); @@ -130,7 +129,8 @@ if (DesugarArgument) { ShouldAKA = true; QT = Context.getTemplateSpecializationType( - TST->getTemplateName(), Args, QT); + TST->getTemplateName(), Args, TST->getConvertedArguments(), + /*CanonicalConvertedArguments=*/{}, QT); } break; } @@ -986,7 +986,7 @@ if (isEnd()) return; // Set to first template argument. If not a parameter pack, done. - TemplateArgument TA = TST->getArg(0); + TemplateArgument TA = TST->getSpecifiedArguments()[0]; if (TA.getKind() != TemplateArgument::Pack) return; // Start looking into the parameter pack. @@ -1007,7 +1007,7 @@ /// isEnd - Returns true if the iterator is one past the end. bool isEnd() const { assert(TST && "InternalIterator is invalid with a null TST."); - return Index >= TST->getNumArgs(); + return Index >= TST->getSpecifiedArguments().size(); } /// &operator++ - Increment the iterator to the next template argument. @@ -1027,11 +1027,11 @@ // Loop until a template argument is found, or the end is reached. while (true) { // Advance to the next template argument. Break if reached the end. - if (++Index == TST->getNumArgs()) + if (++Index == TST->getSpecifiedArguments().size()) break; // If the TemplateArgument is not a parameter pack, done. - TemplateArgument TA = TST->getArg(Index); + TemplateArgument TA = TST->getSpecifiedArguments()[Index]; if (TA.getKind() != TemplateArgument::Pack) break; @@ -1051,7 +1051,7 @@ assert(TST && "InternalIterator is invalid with a null TST."); assert(!isEnd() && "Index exceeds number of arguments."); if (CurrentTA == EndTA) - return TST->getArg(Index); + return TST->getSpecifiedArguments()[Index]; else return *CurrentTA; } @@ -1135,9 +1135,11 @@ return nullptr; Ty = Context.getTemplateSpecializationType( - TemplateName(CTSD->getSpecializedTemplate()), - CTSD->getTemplateArgs().asArray(), - Ty.getLocalUnqualifiedType().getCanonicalType()); + TemplateName(CTSD->getSpecializedTemplate()), + /*SpecifiedArgs=*/CTSD->getTemplateArgs().asArray(), + /*SugaredConvertedArgs=*/CTSD->getTemplateArgs().asArray(), + /*CanonicalConvertedArgs=*/{}, + Ty.getLocalUnqualifiedType().getCanonicalType()); return Ty->getAs(); } 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 @@ -471,9 +471,8 @@ Error ImportDefinition( ObjCProtocolDecl *From, ObjCProtocolDecl *To, ImportDefinitionKind Kind = IDK_Default); - Error ImportTemplateArguments( - const TemplateArgument *FromArgs, unsigned NumFromArgs, - SmallVectorImpl &ToArgs); + Error ImportTemplateArguments(ArrayRef FromArgs, + SmallVectorImpl &ToArgs); Expected ImportTemplateArgument(const TemplateArgument &From); @@ -791,9 +790,8 @@ return std::move(Err); // Import template arguments. - auto TemplArgs = FTSInfo->TemplateArguments->asArray(); - if (Error Err = ImportTemplateArguments(TemplArgs.data(), TemplArgs.size(), - std::get<1>(Result))) + if (Error Err = ImportTemplateArguments(FTSInfo->TemplateArguments->asArray(), + std::get<1>(Result))) return std::move(Err); return Result; @@ -894,8 +892,7 @@ case TemplateArgument::Pack: { SmallVector ToPack; ToPack.reserve(From.pack_size()); - if (Error Err = ImportTemplateArguments( - From.pack_begin(), From.pack_size(), ToPack)) + if (Error Err = ImportTemplateArguments(From.pack_elements(), ToPack)) return std::move(Err); return TemplateArgument( @@ -1362,8 +1359,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) { @@ -1432,9 +1433,7 @@ return ToTypeConstraintConcept.takeError(); SmallVector ToTemplateArgs; - ArrayRef FromTemplateArgs = T->getTypeConstraintArguments(); - if (Error Err = ImportTemplateArguments(FromTemplateArgs.data(), - FromTemplateArgs.size(), + if (Error Err = ImportTemplateArguments(T->getTypeConstraintArguments(), ToTemplateArgs)) return std::move(Err); @@ -1520,8 +1519,7 @@ ExpectedType ASTNodeImporter::VisitSubstTemplateTypeParmType( const SubstTemplateTypeParmType *T) { - Expected ReplacedOrErr = - import(T->getReplacedParameter()); + Expected ReplacedOrErr = import(T->getReplacedDecl()); if (!ReplacedOrErr) return ReplacedOrErr.takeError(); @@ -1530,14 +1528,13 @@ return ToReplacementTypeOrErr.takeError(); return Importer.getToContext().getSubstTemplateTypeParmType( - *ReplacedOrErr, ToReplacementTypeOrErr->getCanonicalType(), + *ToReplacementTypeOrErr, *ReplacedOrErr, T->getIndex(), T->getPackIndex()); } ExpectedType ASTNodeImporter::VisitSubstTemplateTypeParmPackType( const SubstTemplateTypeParmPackType *T) { - Expected ReplacedOrErr = - import(T->getReplacedParameter()); + Expected ReplacedOrErr = import(T->getReplacedDecl()); if (!ReplacedOrErr) return ReplacedOrErr.takeError(); @@ -1546,7 +1543,7 @@ return ToArgumentPack.takeError(); return Importer.getToContext().getSubstTemplateTypeParmPackType( - *ReplacedOrErr, *ToArgumentPack); + *ReplacedOrErr, T->getIndex(), *ToArgumentPack); } ExpectedType ASTNodeImporter::VisitTemplateSpecializationType( @@ -1555,9 +1552,14 @@ if (!ToTemplateOrErr) return ToTemplateOrErr.takeError(); - SmallVector ToTemplateArgs; - if (Error Err = ImportTemplateArguments( - T->getArgs(), T->getNumArgs(), ToTemplateArgs)) + SmallVector ToSpecifiedArgs; + if (Error Err = + ImportTemplateArguments(T->getSpecifiedArguments(), ToSpecifiedArgs)) + return std::move(Err); + + SmallVector ToConvertedArgs; + if (Error Err = + ImportTemplateArguments(T->getConvertedArguments(), ToConvertedArgs)) return std::move(Err); QualType ToCanonType; @@ -1569,9 +1571,9 @@ else return TyOrErr.takeError(); } - return Importer.getToContext().getTemplateSpecializationType(*ToTemplateOrErr, - ToTemplateArgs, - ToCanonType); + return Importer.getToContext().getTemplateSpecializationType( + *ToTemplateOrErr, ToSpecifiedArgs, ToConvertedArgs, + /*CanonicalConvertedArgs=*/{}, ToCanonType); } ExpectedType ASTNodeImporter::VisitElaboratedType(const ElaboratedType *T) { @@ -1615,8 +1617,7 @@ SmallVector ToPack; ToPack.reserve(T->getNumArgs()); - if (Error Err = ImportTemplateArguments( - T->getArgs(), T->getNumArgs(), ToPack)) + if (Error Err = ImportTemplateArguments(T->template_arguments(), ToPack)) return std::move(Err); return Importer.getToContext().getDependentTemplateSpecializationType( @@ -2187,10 +2188,10 @@ } Error ASTNodeImporter::ImportTemplateArguments( - const TemplateArgument *FromArgs, unsigned NumFromArgs, + ArrayRef FromArgs, SmallVectorImpl &ToArgs) { - for (unsigned I = 0; I != NumFromArgs; ++I) { - if (auto ToOrErr = import(FromArgs[I])) + for (const TemplateArgument &FromArg : FromArgs) { + if (auto ToOrErr = import(FromArg)) ToArgs.push_back(*ToOrErr); else return ToOrErr.takeError(); @@ -3280,7 +3281,7 @@ // TemplateSpecializationType. } if (const auto *TST = T->getAs()) - return llvm::count_if(TST->template_arguments(), CheckTemplateArgument); + return llvm::count_if(TST->getSpecifiedArguments(), CheckTemplateArgument); return false; } @@ -3638,6 +3639,10 @@ } } + // If it is a template, import all related things. + if (Error Err = ImportTemplateInformation(D, ToFunction)) + return std::move(Err); + if (D->doesThisDeclarationHaveABody()) { Error Err = ImportFunctionDeclBody(D, ToFunction); @@ -3659,10 +3664,6 @@ // FIXME: Other bits to merge? - // If it is a template, import all related things. - if (Error Err = ImportTemplateInformation(D, ToFunction)) - return std::move(Err); - addDeclToContexts(D, ToFunction); if (auto *FromCXXMethod = dyn_cast(D)) @@ -5723,8 +5724,8 @@ // Import template arguments. SmallVector TemplateArgs; - if (Error Err = ImportTemplateArguments( - D->getTemplateArgs().data(), D->getTemplateArgs().size(), TemplateArgs)) + if (Error Err = + ImportTemplateArguments(D->getTemplateArgs().asArray(), TemplateArgs)) return std::move(Err); // Try to find an existing specialization with these template arguments and // template parameter list. @@ -5882,6 +5883,30 @@ D2->setTemplateSpecializationKind(D->getTemplateSpecializationKind()); + if (auto P = D->getInstantiatedFrom()) { + if (auto *CTD = P.dyn_cast()) { + if (auto CTDorErr = import(CTD)) + D2->setInstantiationOf(*CTDorErr); + } else { + auto *CTPSD = cast(P); + auto CTPSDOrErr = import(CTPSD); + if (!CTPSDOrErr) + return CTPSDOrErr.takeError(); + const TemplateArgumentList &DArgs = D->getTemplateInstantiationArgs(); + SmallVector D2ArgsVec(DArgs.size()); + for (unsigned I = 0; I < DArgs.size(); ++I) { + const TemplateArgument &DArg = DArgs[I]; + if (auto ArgOrErr = import(DArg)) + D2ArgsVec[I] = *ArgOrErr; + else + return ArgOrErr.takeError(); + } + D2->setInstantiationOf( + *CTPSDOrErr, + TemplateArgumentList::CreateCopy(Importer.getToContext(), D2ArgsVec)); + } + } + if (D->isCompleteDefinition()) if (Error Err = ImportDefinition(D, D2)) return std::move(Err); @@ -6021,8 +6046,8 @@ // Import template arguments. SmallVector TemplateArgs; - if (Error Err = ImportTemplateArguments( - D->getTemplateArgs().data(), D->getTemplateArgs().size(), TemplateArgs)) + if (Error Err = + ImportTemplateArguments(D->getTemplateArgs().asArray(), TemplateArgs)) return std::move(Err); // Try to find an existing specialization with these template arguments. @@ -6045,15 +6070,6 @@ } } } else { - // Import the type. - QualType T; - if (Error Err = importInto(T, D->getType())) - return std::move(Err); - - auto TInfoOrErr = import(D->getTypeSourceInfo()); - if (!TInfoOrErr) - return TInfoOrErr.takeError(); - TemplateArgumentListInfo ToTAInfo; if (const ASTTemplateArgumentListInfo *Args = D->getTemplateArgsInfo()) { if (Error Err = ImportTemplateArgumentListInfo(*Args, ToTAInfo)) @@ -6078,7 +6094,7 @@ PartVarSpecDecl *ToPartial; if (GetImportedOrCreateDecl(ToPartial, D, Importer.getToContext(), DC, *BeginLocOrErr, *IdLocOrErr, *ToTPListOrErr, - VarTemplate, T, *TInfoOrErr, + VarTemplate, QualType(), nullptr, D->getStorageClass(), TemplateArgs, ArgInfos)) return ToPartial; @@ -6099,11 +6115,21 @@ } else { // Full specialization if (GetImportedOrCreateDecl(D2, D, Importer.getToContext(), DC, *BeginLocOrErr, *IdLocOrErr, VarTemplate, - T, *TInfoOrErr, - D->getStorageClass(), TemplateArgs)) + QualType(), nullptr, D->getStorageClass(), + TemplateArgs)) return D2; } + QualType T; + if (Error Err = importInto(T, D->getType())) + return std::move(Err); + D2->setType(T); + + auto TInfoOrErr = import(D->getTypeSourceInfo()); + if (!TInfoOrErr) + return TInfoOrErr.takeError(); + D2->setTypeSourceInfo(*TInfoOrErr); + if (D->getPointOfInstantiation().isValid()) { if (ExpectedSLoc POIOrErr = import(D->getPointOfInstantiation())) D2->setPointOfInstantiation(*POIOrErr); @@ -7677,10 +7703,8 @@ SmallVector ToPartialArguments; if (E->isPartiallySubstituted()) { - if (Error Err = ImportTemplateArguments( - E->getPartialArguments().data(), - E->getPartialArguments().size(), - ToPartialArguments)) + if (Error Err = ImportTemplateArguments(E->getPartialArguments(), + ToPartialArguments)) return std::move(Err); } @@ -7818,6 +7842,7 @@ auto ToQualifierLoc = importChecked(Err, E->getQualifierLoc()); auto ToTemplateKeywordLoc = importChecked(Err, E->getTemplateKeywordLoc()); auto ToMemberDecl = importChecked(Err, E->getMemberDecl()); + auto ToDeduced = importChecked(Err, E->getDeduced()); auto ToType = importChecked(Err, E->getType()); auto ToDecl = importChecked(Err, E->getFoundDecl().getDecl()); auto ToName = importChecked(Err, E->getMemberNameInfo().getName()); @@ -7842,7 +7867,7 @@ return MemberExpr::Create(Importer.getToContext(), ToBase, E->isArrow(), ToOperatorLoc, ToQualifierLoc, ToTemplateKeywordLoc, ToMemberDecl, ToFoundDecl, ToMemberNameInfo, - ResInfo, ToType, E->getValueKind(), + ResInfo, ToDeduced, ToType, E->getValueKind(), E->getObjectKind(), E->isNonOdrUse()); } @@ -9522,6 +9547,17 @@ return Importer.ImportAPValue(FromValue); } +llvm::Expected +ASTImporter::Import(const TemplateArgumentList *ArgList) { + ASTNodeImporter Importer(*this); + if (!ArgList) + return nullptr; + SmallVector ToArgs(ArgList->size()); + if (auto Res = Importer.ImportTemplateArguments(ArgList->asArray(), ToArgs)) + return std::move(Res); + return TemplateArgumentList::CreateCopy(ToContext, ToArgs); +} + Error ASTImporter::ImportDefinition(Decl *From) { ExpectedDecl ToOrErr = Import(From); if (!ToOrErr) 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 @@ -526,6 +526,10 @@ return true; } +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + ArrayRef Args1, + ArrayRef Args2); + /// Determine whether two template arguments are equivalent. static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, const TemplateArgument &Arg1, @@ -568,20 +572,26 @@ Arg2.getAsExpr()); case TemplateArgument::Pack: - if (Arg1.pack_size() != Arg2.pack_size()) - return false; - - for (unsigned I = 0, N = Arg1.pack_size(); I != N; ++I) - if (!IsStructurallyEquivalent(Context, Arg1.pack_begin()[I], - Arg2.pack_begin()[I])) - return false; - - return true; + return IsStructurallyEquivalent(Context, Arg1.pack_elements(), + Arg2.pack_elements()); } llvm_unreachable("Invalid template argument kind"); } +/// Determine whether two template argument lists are equivalent. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + ArrayRef Args1, + ArrayRef Args2) { + if (Args1.size() != Args2.size()) + return false; + + for (unsigned I = 0, N = Args1.size(); I != N; ++I) + if (!IsStructurallyEquivalent(Context, Args1[I], Args2[I])) + return false; + return true; +} + /// Determine structural equivalence for the common part of array /// types. static bool IsArrayStructurallyEquivalent(StructuralEquivalenceContext &Context, @@ -957,11 +967,17 @@ if (!IsStructurallyEquivalent(Context, cast(T1)->getFoundDecl(), cast(T2)->getFoundDecl())) return false; + if (!IsStructurallyEquivalent(Context, + cast(T1)->getUnderlyingType(), + cast(T2)->getUnderlyingType())) + return false; break; 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; @@ -1005,16 +1021,10 @@ if (Auto1->getTypeConstraintConcept() != Auto2->getTypeConstraintConcept()) return false; - ArrayRef Auto1Args = - Auto1->getTypeConstraintArguments(); - ArrayRef Auto2Args = - Auto2->getTypeConstraintArguments(); - if (Auto1Args.size() != Auto2Args.size()) + if (!IsStructurallyEquivalent(Context, + Auto1->getTypeConstraintArguments(), + Auto2->getTypeConstraintArguments())) return false; - for (unsigned I = 0, N = Auto1Args.size(); I != N; ++I) { - if (!IsStructurallyEquivalent(Context, Auto1Args[I], Auto2Args[I])) - return false; - } } break; } @@ -1055,13 +1065,13 @@ case Type::SubstTemplateTypeParm: { const auto *Subst1 = cast(T1); const auto *Subst2 = cast(T2); - if (!IsStructurallyEquivalent(Context, - QualType(Subst1->getReplacedParameter(), 0), - QualType(Subst2->getReplacedParameter(), 0))) - return false; if (!IsStructurallyEquivalent(Context, Subst1->getReplacementType(), Subst2->getReplacementType())) return false; + if (Subst1->getReplacedDecl() != Subst2->getReplacedDecl()) + return false; + if (Subst1->getIndex() != Subst2->getIndex()) + return false; if (Subst1->getPackIndex() != Subst2->getPackIndex()) return false; break; @@ -1070,9 +1080,9 @@ case Type::SubstTemplateTypeParmPack: { const auto *Subst1 = cast(T1); const auto *Subst2 = cast(T2); - if (!IsStructurallyEquivalent(Context, - QualType(Subst1->getReplacedParameter(), 0), - QualType(Subst2->getReplacedParameter(), 0))) + if (Subst1->getReplacedDecl() != Subst2->getReplacedDecl()) + return false; + if (Subst1->getIndex() != Subst2->getIndex()) return false; if (!IsStructurallyEquivalent(Context, Subst1->getArgumentPack(), Subst2->getArgumentPack())) @@ -1086,13 +1096,12 @@ if (!IsStructurallyEquivalent(Context, Spec1->getTemplateName(), Spec2->getTemplateName())) return false; - if (Spec1->getNumArgs() != Spec2->getNumArgs()) + if (!IsStructurallyEquivalent(Context, Spec1->getSpecifiedArguments(), + Spec2->getSpecifiedArguments())) + return false; + if (!IsStructurallyEquivalent(Context, Spec1->getConvertedArguments(), + Spec2->getConvertedArguments())) return false; - for (unsigned I = 0, N = Spec1->getNumArgs(); I != N; ++I) { - if (!IsStructurallyEquivalent(Context, Spec1->getArg(I), - Spec2->getArg(I))) - return false; - } break; } @@ -1143,13 +1152,9 @@ if (!IsStructurallyEquivalent(Spec1->getIdentifier(), Spec2->getIdentifier())) return false; - if (Spec1->getNumArgs() != Spec2->getNumArgs()) + if (!IsStructurallyEquivalent(Context, Spec1->template_arguments(), + Spec2->template_arguments())) return false; - for (unsigned I = 0, N = Spec1->getNumArgs(); I != N; ++I) { - if (!IsStructurallyEquivalent(Context, Spec1->getArg(I), - Spec2->getArg(I))) - return false; - } break; } diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp --- a/clang/lib/AST/DeclPrinter.cpp +++ b/clang/lib/AST/DeclPrinter.cpp @@ -1001,7 +1001,7 @@ if (const auto* TSI = S->getTypeAsWritten()) if (const auto *TST = dyn_cast(TSI->getType())) - Args = TST->template_arguments(); + Args = TST->getSpecifiedArguments(); printTemplateArguments( Args, S->getSpecializedTemplate()->getTemplateParameters()); } diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -250,6 +250,23 @@ return false; } +bool TemplateDecl::isTypeAlias() const { + switch (getKind()) { + case TemplateDecl::TypeAliasTemplate: + return true; + case TemplateDecl::BuiltinTemplate: { + const auto *BT = cast(this); + if (BT->getBuiltinTemplateKind() == + BuiltinTemplateKind::BTK__make_integer_seq) + return true; + return false; + } + default: + return false; + }; + llvm_unreachable("unknown template kind"); +} + //===----------------------------------------------------------------------===// // RedeclarableTemplateDecl Implementation //===----------------------------------------------------------------------===// @@ -614,9 +631,10 @@ TemplateParameterList *Params = getTemplateParameters(); SmallVector TemplateArgs; Context.getInjectedTemplateArgs(Params, TemplateArgs); - CommonPtr->InjectedClassNameType - = Context.getTemplateSpecializationType(TemplateName(this), - TemplateArgs); + CommonPtr->InjectedClassNameType = Context.getTemplateSpecializationType( + TemplateName(this), + /*SpecifiedArgs=*/TemplateArgs, /*SugaredConvertedArgs=*/TemplateArgs, + /*CanonicalConvertedArgs=*/{}); return CommonPtr->InjectedClassNameType; } @@ -1057,15 +1075,12 @@ } ClassTemplatePartialSpecializationDecl * -ClassTemplatePartialSpecializationDecl:: -Create(ASTContext &Context, TagKind TK,DeclContext *DC, - SourceLocation StartLoc, SourceLocation IdLoc, - TemplateParameterList *Params, - ClassTemplateDecl *SpecializedTemplate, - ArrayRef Args, - const TemplateArgumentListInfo &ArgInfos, - QualType CanonInjectedType, - ClassTemplatePartialSpecializationDecl *PrevDecl) { +ClassTemplatePartialSpecializationDecl::Create( + ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, TemplateParameterList *Params, + ClassTemplateDecl *SpecializedTemplate, ArrayRef Args, + const TemplateArgumentListInfo &ArgInfos, QualType InjectedType, + ClassTemplatePartialSpecializationDecl *PrevDecl) { const ASTTemplateArgumentListInfo *ASTArgInfos = ASTTemplateArgumentListInfo::Create(Context, ArgInfos); @@ -1076,7 +1091,7 @@ Result->setSpecializationKind(TSK_ExplicitSpecialization); Result->setMayHaveOutOfDateDef(false); - Context.getInjectedClassNameType(Result, CanonInjectedType); + Context.getInjectedClassNameType(Result, InjectedType); return Result; } diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -1612,11 +1612,13 @@ MemberExpr::MemberExpr(Expr *Base, bool IsArrow, SourceLocation OperatorLoc, ValueDecl *MemberDecl, - const DeclarationNameInfo &NameInfo, QualType T, + const DeclarationNameInfo &NameInfo, + const TemplateArgumentList *Deduced, QualType T, ExprValueKind VK, ExprObjectKind OK, NonOdrUseReason NOUR) : Expr(MemberExprClass, T, VK, OK), Base(Base), MemberDecl(MemberDecl), - MemberDNLoc(NameInfo.getInfo()), MemberLoc(NameInfo.getLoc()) { + Deduced(Deduced), MemberDNLoc(NameInfo.getInfo()), + MemberLoc(NameInfo.getLoc()) { assert(!NameInfo.getName() || MemberDecl->getDeclName() == NameInfo.getName()); MemberExprBits.IsArrow = IsArrow; @@ -1633,7 +1635,8 @@ NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, ValueDecl *MemberDecl, DeclAccessPair FoundDecl, DeclarationNameInfo NameInfo, const TemplateArgumentListInfo *TemplateArgs, - QualType T, ExprValueKind VK, ExprObjectKind OK, NonOdrUseReason NOUR) { + const TemplateArgumentList *Deduced, QualType T, ExprValueKind VK, + ExprObjectKind OK, NonOdrUseReason NOUR) { bool HasQualOrFound = QualifierLoc || FoundDecl.getDecl() != MemberDecl || FoundDecl.getAccess() != MemberDecl->getAccess(); bool HasTemplateKWAndArgsInfo = TemplateArgs || TemplateKWLoc.isValid(); @@ -1645,7 +1648,7 @@ void *Mem = C.Allocate(Size, alignof(MemberExpr)); MemberExpr *E = new (Mem) MemberExpr(Base, IsArrow, OperatorLoc, MemberDecl, - NameInfo, T, VK, OK, NOUR); + NameInfo, Deduced, T, VK, OK, NOUR); // FIXME: remove remaining dependence computation to computeDependence(). auto Deps = E->getDependence(); diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -1244,8 +1244,9 @@ // FIXME: GCC does not appear to mangle the template arguments when // the template in question is a dependent template name. Should we // emulate that badness? - mangleTemplateArgs(TST->getTemplateName(), TST->getArgs(), - TST->getNumArgs()); + auto Args = TST->isCanonicalUnqualified() ? TST->getConvertedArguments() + : TST->getSpecifiedArguments(); + mangleTemplateArgs(TST->getTemplateName(), Args.begin(), Args.size()); addSubstitution(QualType(TST, 0)); } } else if (const auto *DTST = @@ -2410,13 +2411,14 @@ break; } } - + auto Args = TST->isCanonicalUnqualified() ? TST->getConvertedArguments() + : TST->getSpecifiedArguments(); // Note: we don't pass in the template name here. We are mangling the // original source-level template arguments, so we shouldn't consider // conversions to the corresponding template parameter. // FIXME: Other compilers mangle partially-resolved template arguments in // unresolved-qualifier-levels. - mangleTemplateArgs(TemplateName(), TST->getArgs(), TST->getNumArgs()); + mangleTemplateArgs(TemplateName(), Args.begin(), Args.size()); break; } @@ -3873,8 +3875,10 @@ } void CXXNameMangler::mangleType(const TemplateSpecializationType *T) { + auto Args = T->isCanonicalUnqualified() ? T->getConvertedArguments() + : T->getSpecifiedArguments(); if (TemplateDecl *TD = T->getTemplateName().getAsTemplateDecl()) { - mangleTemplateName(TD, T->getArgs(), T->getNumArgs()); + mangleTemplateName(TD, Args.begin(), Args.size()); } else { if (mangleSubstitution(QualType(T, 0))) return; @@ -3884,7 +3888,7 @@ // FIXME: GCC does not appear to mangle the template arguments when // the template in question is a dependent template name. Should we // emulate that badness? - mangleTemplateArgs(T->getTemplateName(), T->getArgs(), T->getNumArgs()); + mangleTemplateArgs(T->getTemplateName(), Args.begin(), Args.size()); addSubstitution(QualType(T, 0)); } } 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) { @@ -682,10 +684,16 @@ void JSONNodeDumper::VisitSubstTemplateTypeParmType( const SubstTemplateTypeParmType *STTPT) { + JOS.attribute("index", STTPT->getIndex()); if (auto PackIndex = STTPT->getPackIndex()) JOS.attribute("pack_index", *PackIndex); } +void JSONNodeDumper::VisitSubstTemplateTypeParmPackType( + const SubstTemplateTypeParmPackType *T) { + JOS.attribute("index", T->getIndex()); +} + void JSONNodeDumper::VisitAutoType(const AutoType *AT) { JOS.attribute("undeduced", !AT->isDeduced()); switch (AT->getKeyword()) { diff --git a/clang/lib/AST/NestedNameSpecifier.cpp b/clang/lib/AST/NestedNameSpecifier.cpp --- a/clang/lib/AST/NestedNameSpecifier.cpp +++ b/clang/lib/AST/NestedNameSpecifier.cpp @@ -315,7 +315,7 @@ TemplateName::Qualified::None); // Print the template argument list. - printTemplateArgumentList(OS, SpecType->template_arguments(), + printTemplateArgumentList(OS, SpecType->getSpecifiedArguments(), InnerPolicy); } else if (const auto *DepSpecType = dyn_cast(T)) { diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp --- a/clang/lib/AST/ODRHash.cpp +++ b/clang/lib/AST/ODRHash.cpp @@ -671,7 +671,7 @@ } } - void AddDecl(Decl *D) { + void AddDecl(const Decl *D) { Hash.AddBoolean(D); if (D) { Hash.AddDecl(D); @@ -995,13 +995,13 @@ void VisitSubstTemplateTypeParmPackType(const SubstTemplateTypeParmPackType *T) { - AddType(T->getReplacedParameter()); + AddDecl(T->getReplacedDecl()); Hash.AddTemplateArgument(T->getArgumentPack()); VisitType(T); } void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T) { - AddType(T->getReplacedParameter()); + AddDecl(T->getReplacedDecl()); AddQualType(T->getReplacementType()); VisitType(T); } @@ -1015,8 +1015,8 @@ void VisitEnumType(const EnumType *T) { VisitTagType(T); } void VisitTemplateSpecializationType(const TemplateSpecializationType *T) { - ID.AddInteger(T->getNumArgs()); - for (const auto &TA : T->template_arguments()) { + ID.AddInteger(T->getSpecifiedArguments().size()); + for (const auto &TA : T->getSpecifiedArguments()) { Hash.AddTemplateArgument(TA); } Hash.AddTemplateName(T->getTemplateName()); 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 @@ -129,11 +129,9 @@ if (const auto *TST = dyn_cast(TypePtr)) { bool MightHaveChanged = false; SmallVector FQArgs; - for (TemplateSpecializationType::iterator I = TST->begin(), E = TST->end(); - I != E; ++I) { - // Cheap to copy and potentially modified by - // getFullyQualifedTemplateArgument. - TemplateArgument Arg(*I); + // Cheap to copy and potentially modified by + // getFullyQualifedTemplateArgument. + for (TemplateArgument Arg : TST->getSpecifiedArguments()) { MightHaveChanged |= getFullyQualifiedTemplateArgument( Ctx, Arg, WithGlobalNsPrefix); FQArgs.push_back(Arg); @@ -143,8 +141,8 @@ // allocate new type in the AST. if (MightHaveChanged) { QualType QT = Ctx.getTemplateSpecializationType( - TST->getTemplateName(), FQArgs, - TST->getCanonicalTypeInternal()); + TST->getTemplateName(), FQArgs, TST->getConvertedArguments(), + /*CanonicalConvertedArgs=*/{}, TST->getCanonicalTypeInternal()); // getTemplateSpecializationType returns a fully qualified // version of the specialization itself, so no need to qualify // it. @@ -175,7 +173,8 @@ if (MightHaveChanged) { TemplateName TN(TSTDecl->getSpecializedTemplate()); QualType QT = Ctx.getTemplateSpecializationType( - TN, FQArgs, + TN, FQArgs, FQArgs, + /*CanonicalConvertedArgs=*/{}, TSTRecord->getCanonicalTypeInternal()); // getTemplateSpecializationType returns a fully qualified // version of the specialization itself, so no need to qualify diff --git a/clang/lib/AST/TemplateBase.cpp b/clang/lib/AST/TemplateBase.cpp --- a/clang/lib/AST/TemplateBase.cpp +++ b/clang/lib/AST/TemplateBase.cpp @@ -321,26 +321,15 @@ case Declaration: getParamTypeForDecl().Profile(ID); - ID.AddPointer(getAsDecl()? getAsDecl()->getCanonicalDecl() : nullptr); + ID.AddPointer(getAsDecl()); break; + case TemplateExpansion: + ID.AddInteger(TemplateArg.NumExpansions); + LLVM_FALLTHROUGH; case Template: - case TemplateExpansion: { - TemplateName Template = getAsTemplateOrTemplatePattern(); - if (TemplateTemplateParmDecl *TTP - = dyn_cast_or_null( - Template.getAsTemplateDecl())) { - ID.AddBoolean(true); - ID.AddInteger(TTP->getDepth()); - ID.AddInteger(TTP->getPosition()); - ID.AddBoolean(TTP->isParameterPack()); - } else { - ID.AddBoolean(false); - ID.AddPointer(Context.getCanonicalTemplateName(Template) - .getAsVoidPointer()); - } + getAsTemplateOrTemplatePattern().Profile(ID); break; - } case Integral: getAsIntegral().Profile(ID); 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 @@ -1543,10 +1543,14 @@ void TextNodeDumper::VisitUsingType(const UsingType *T) { dumpDeclRef(T->getFoundDecl()); + if (T->hasDifferentUnderlyingType()) + OS << " resugared"; } void TextNodeDumper::VisitTypedefType(const TypedefType *T) { dumpDeclRef(T->getDecl()); + if (T->hasDifferentUnderlyingType()) + OS << " resugared"; } void TextNodeDumper::VisitUnaryTransformType(const UnaryTransformType *T) { @@ -1570,10 +1574,18 @@ void TextNodeDumper::VisitSubstTemplateTypeParmType( const SubstTemplateTypeParmType *T) { + dumpDeclRef(T->getReplacedDecl()); + VisitTemplateTypeParmDecl(T->getReplacedTemplateParam()); if (auto PackIndex = T->getPackIndex()) OS << " pack_index " << *PackIndex; } +void TextNodeDumper::VisitSubstTemplateTypeParmPackType( + const SubstTemplateTypeParmPackType *T) { + dumpDeclRef(T->getReplacedDecl()); + VisitTemplateTypeParmDecl(T->getReplacedTemplateParam()); +} + void TextNodeDumper::VisitAutoType(const AutoType *T) { if (T->isDecltypeAuto()) OS << " decltype(auto)"; 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 @@ -1166,8 +1166,9 @@ == T->getReplacementType().getAsOpaquePtr()) return QualType(T, 0); - return Ctx.getSubstTemplateTypeParmType(T->getReplacedParameter(), - replacementType, T->getPackIndex()); + return Ctx.getSubstTemplateTypeParmType(replacementType, + T->getReplacedDecl(), T->getIndex(), + T->getPackIndex()); } // FIXME: Non-trivial to implement, but important for C++ @@ -1773,6 +1774,17 @@ return nullptr; } +const TemplateSpecializationType * +Type::getAsNonAliasTemplateSpecializationType() const { + for (auto T = this; /**/; /**/) { + const TemplateSpecializationType *TST = + T->getAs(); + if (!TST || !TST->isTypeAlias()) + return TST; + T = TST->desugar().getTypePtr(); + } +} + bool Type::hasAttr(attr::Kind AK) const { const Type *Cur = this; while (const auto *AT = Cur->getAs()) { @@ -3434,25 +3446,35 @@ } 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, QualType Canon) - : Type(Using, Canon, toSemanticDependence(Underlying->getDependence())), + : Type(Using, Canon, toSemanticDependence(Canon->getDependence())), Found(const_cast(Found)) { - assert(Underlying == getUnderlyingType()); + UsingBits.hasDifferentUnderlyingType = !Underlying.isNull(); + if (hasDifferentUnderlyingType()) + *reinterpret_cast(this + 1) = Underlying; } QualType UsingType::getUnderlyingType() const { - return QualType(cast(Found->getTargetDecl())->getTypeForDecl(), 0); + return hasDifferentUnderlyingType() + ? *reinterpret_cast(this + 1) + : QualType( + cast(Found->getTargetDecl())->getTypeForDecl(), 0); } QualType MacroQualifiedType::desugar() const { return getUnderlyingType(); } @@ -3649,14 +3671,105 @@ return isCanonicalUnqualified() ? nullptr : getDecl()->getIdentifier(); } +static const TemplateParameterList * +getReplacedTemplateParameterList(const Decl *D) { + switch (D->getKind()) { + case Decl::Kind::ClassTemplate: + return cast(D)->getTemplateParameters(); + case Decl::Kind::ClassTemplateSpecialization: { + const auto *CTSD = cast(D); + auto P = CTSD->getSpecializedTemplateOrPartial(); + if (const auto *CTPSD = + P.dyn_cast()) + return CTPSD->getTemplateParameters(); + return cast(P)->getTemplateParameters(); + } + case Decl::Kind::ClassTemplatePartialSpecialization: + return cast(D) + ->getTemplateParameters(); + case Decl::Kind::TypeAliasTemplate: + return cast(D)->getTemplateParameters(); + case Decl::Kind::BuiltinTemplate: + return cast(D)->getTemplateParameters(); + case Decl::Kind::CXXConversion: + case Decl::Kind::CXXConstructor: + case Decl::Kind::CXXDestructor: + case Decl::Kind::CXXMethod: + case Decl::Kind::Function: + return cast(D) + ->getTemplateSpecializationInfo() + ->getTemplate() + ->getTemplateParameters(); + case Decl::Kind::FunctionTemplate: + return cast(D)->getTemplateParameters(); + case Decl::Kind::VarTemplate: + return cast(D)->getTemplateParameters(); + case Decl::Kind::VarTemplateSpecialization: { + const auto *VTSD = cast(D); + auto P = VTSD->getSpecializedTemplateOrPartial(); + if (const auto *VTPSD = + P.dyn_cast()) + return VTPSD->getTemplateParameters(); + return cast(P)->getTemplateParameters(); + } + case Decl::Kind::VarTemplatePartialSpecialization: + return cast(D) + ->getTemplateParameters(); + case Decl::Kind::TemplateTemplateParm: + return cast(D)->getTemplateParameters(); + case Decl::Kind::Concept: + return cast(D)->getTemplateParameters(); + default: + D->dumpColor(); + llvm_unreachable("Unhandled Replaced Kind"); + } +} + +static const TemplateTypeParmDecl *getReplacedTemplateParam(const Decl *D, + unsigned Index) { + if (const auto *TTP = dyn_cast(D)) + return TTP; + return cast( + getReplacedTemplateParameterList(D)->getParam(Index)); +} + +SubstTemplateTypeParmType::SubstTemplateTypeParmType( + QualType Replacement, Decl *ReplacedDecl, unsigned Index, + Optional PackIndex) + : Type(SubstTemplateTypeParm, Replacement.getCanonicalType(), + Replacement->getDependence()), + Replacement(Replacement), ReplacedDecl(ReplacedDecl) { + SubstTemplateTypeParmTypeBits.Index = Index; + SubstTemplateTypeParmTypeBits.PackIndex = PackIndex ? *PackIndex + 1 : 0; + assert(ReplacedDecl != nullptr); + assert(getReplacedTemplateParam() != nullptr); +} + +const TemplateTypeParmDecl * +SubstTemplateTypeParmType::getReplacedTemplateParam() const { + return ::getReplacedTemplateParam(getReplacedDecl(), getIndex()); +} + SubstTemplateTypeParmPackType::SubstTemplateTypeParmPackType( - const TemplateTypeParmType *Param, QualType Canon, + QualType Canon, Decl *ReplacedDecl, unsigned Index, const TemplateArgument &ArgPack) : Type(SubstTemplateTypeParmPack, Canon, TypeDependence::DependentInstantiation | TypeDependence::UnexpandedPack), - Replaced(Param), Arguments(ArgPack.pack_begin()) { + Arguments(ArgPack.pack_begin()), ReplacedDecl(ReplacedDecl) { + SubstTemplateTypeParmPackTypeBits.Index = Index; SubstTemplateTypeParmPackTypeBits.NumArgs = ArgPack.pack_size(); + assert(ReplacedDecl != nullptr); + assert(getReplacedTemplateParam() != nullptr); +} + +const TemplateTypeParmDecl * +SubstTemplateTypeParmPackType::getReplacedTemplateParam() const { + return ::getReplacedTemplateParam(getReplacedDecl(), getIndex()); +} + +IdentifierInfo *SubstTemplateTypeParmPackType::getIdentifier() const { + return getReplacedTemplateParam()->getIdentifier(); } TemplateArgument SubstTemplateTypeParmPackType::getArgumentPack() const { @@ -3664,13 +3777,15 @@ } void SubstTemplateTypeParmPackType::Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getReplacedParameter(), getArgumentPack()); + Profile(ID, getReplacedDecl(), getIndex(), getArgumentPack()); } void SubstTemplateTypeParmPackType::Profile(llvm::FoldingSetNodeID &ID, - const TemplateTypeParmType *Replaced, + const Decl *ReplacedDecl, + unsigned Index, const TemplateArgument &ArgPack) { - ID.AddPointer(Replaced); + ID.AddPointer(ReplacedDecl); + ID.AddInteger(Index); ID.AddInteger(ArgPack.pack_size()); for (const auto &P : ArgPack.pack_elements()) ID.AddPointer(P.getAsType().getAsOpaquePtr()); @@ -3699,16 +3814,56 @@ } TemplateSpecializationType::TemplateSpecializationType( - TemplateName T, ArrayRef Args, QualType Canon, + TemplateName T, ArrayRef ConvertedArgs) + : Type(TemplateSpecialization, QualType(this, 0), + TypeDependence::DependentInstantiation | + (toTypeDependence(T.getDependence()) & + TypeDependence::UnexpandedPack)), + Template(T) { + TemplateSpecializationTypeBits.NumSpecifiedArgs = 0; + TemplateSpecializationTypeBits.NumConvertedArgs = ConvertedArgs.size(); + TemplateSpecializationTypeBits.TypeAlias = false; + + assert(!T.getAsDependentTemplateName() && + "Use DependentTemplateSpecializationType for dependent template-name"); + assert((T.getKind() == TemplateName::Template || + T.getKind() == TemplateName::SubstTemplateTemplateParm || + T.getKind() == TemplateName::SubstTemplateTemplateParmPack || + T.getKind() == TemplateName::UsingTemplate) && + "Unexpected template name for TemplateSpecializationType"); + + auto *ConvArgs = + const_cast(getConvertedArguments().data()); + for (const TemplateArgument &Arg : ConvertedArgs) { + // Update instantiation-dependent, variably-modified, and error bits. + // If the canonical type exists and is non-dependent, the template + // specialization type can be non-dependent even if one of the type + // arguments is. Given: + // template using U = int; + // U is always non-dependent, irrespective of the type T. + // However, U contains an unexpanded parameter pack, even though + // its expansion (and thus its desugared type) doesn't. + addDependence(toTypeDependence(Arg.getDependence()) & + ~TypeDependence::Dependent); + if (Arg.getKind() == TemplateArgument::Type) + addDependence(Arg.getAsType()->getDependence() & + TypeDependence::VariablyModified); + new (ConvArgs++) TemplateArgument(Arg); + } +} + +TemplateSpecializationType::TemplateSpecializationType( + TemplateName T, ArrayRef SpecifiedArgs, + ArrayRef ConvertedArgs, QualType Canon, QualType AliasedType) : Type(TemplateSpecialization, Canon.isNull() ? QualType(this, 0) : Canon, - (Canon.isNull() - ? TypeDependence::DependentInstantiation - : toSemanticDependence(Canon->getDependence())) | + (Canon.isNull() ? TypeDependence::DependentInstantiation + : toSemanticDependence(Canon->getDependence())) | (toTypeDependence(T.getDependence()) & TypeDependence::UnexpandedPack)), Template(T) { - TemplateSpecializationTypeBits.NumArgs = Args.size(); + TemplateSpecializationTypeBits.NumSpecifiedArgs = SpecifiedArgs.size(); + TemplateSpecializationTypeBits.NumConvertedArgs = ConvertedArgs.size(); TemplateSpecializationTypeBits.TypeAlias = !AliasedType.isNull(); assert(!T.getAsDependentTemplateName() && @@ -3719,8 +3874,9 @@ T.getKind() == TemplateName::UsingTemplate) && "Unexpected template name for TemplateSpecializationType"); - auto *TemplateArgs = reinterpret_cast(this + 1); - for (const TemplateArgument &Arg : Args) { + auto *SpecArgs = + const_cast(getSpecifiedArguments().data()); + for (const TemplateArgument &Arg : SpecifiedArgs) { // Update instantiation-dependent, variably-modified, and error bits. // If the canonical type exists and is non-dependent, the template // specialization type can be non-dependent even if one of the type @@ -3734,23 +3890,39 @@ if (Arg.getKind() == TemplateArgument::Type) addDependence(Arg.getAsType()->getDependence() & TypeDependence::VariablyModified); - new (TemplateArgs++) TemplateArgument(Arg); + new (SpecArgs++) TemplateArgument(Arg); } + // For a non-canonical TST, the converted args don't figure into + // the dependence. + auto *ConvArgs = + const_cast(getConvertedArguments().data()); + for (const TemplateArgument &Arg : ConvertedArgs) + new (ConvArgs++) TemplateArgument(Arg); + // Store the aliased type if this is a type alias template specialization. - if (isTypeAlias()) { - auto *Begin = reinterpret_cast(this + 1); - *reinterpret_cast(Begin + getNumArgs()) = AliasedType; - } + if (isTypeAlias()) + *reinterpret_cast(const_cast( + getConvertedArguments().end())) = AliasedType; } -void -TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID, - TemplateName T, - ArrayRef Args, - const ASTContext &Context) { +ArrayRef +TemplateSpecializationType::getConvertedArguments() const { + return {getSpecifiedArguments().end(), + TemplateSpecializationTypeBits.NumConvertedArgs}; +} + +QualType TemplateSpecializationType::getAliasedType() const { + assert(isTypeAlias() && "not a type alias template specialization"); + return *reinterpret_cast(getConvertedArguments().end()); +} + +void TemplateSpecializationType::Profile( + llvm::FoldingSetNodeID &ID, TemplateName T, + ArrayRef ConvertedArgs, const ASTContext &Context) { T.Profile(ID); - for (const TemplateArgument &Arg : Args) + ID.AddInteger(ConvertedArgs.size()); + for (const TemplateArgument &Arg : ConvertedArgs) Arg.Profile(ID, Context); } diff --git a/clang/lib/AST/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp --- a/clang/lib/AST/TypeLoc.cpp +++ b/clang/lib/AST/TypeLoc.cpp @@ -568,17 +568,16 @@ setTemplateNameLoc(Loc); setLAngleLoc(Loc); setRAngleLoc(Loc); - TemplateSpecializationTypeLoc::initializeArgLocs(Context, getNumArgs(), - getTypePtr()->getArgs(), - getArgInfos(), Loc); + TemplateSpecializationTypeLoc::initializeArgLocs( + Context, + ArrayRef(getTypePtr()->getArgs(), getNumArgs()), + getArgInfos(), Loc); } -void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context, - unsigned NumArgs, - const TemplateArgument *Args, - TemplateArgumentLocInfo *ArgInfos, - SourceLocation Loc) { - for (unsigned i = 0, e = NumArgs; i != e; ++i) { +void TemplateSpecializationTypeLoc::initializeArgLocs( + ASTContext &Context, ArrayRef Args, + TemplateArgumentLocInfo *ArgInfos, SourceLocation Loc) { + for (unsigned i = 0, e = Args.size(); i != e; ++i) { switch (Args[i].getKind()) { case TemplateArgument::Null: llvm_unreachable("Impossible TemplateArgument"); @@ -635,9 +634,10 @@ setRAngleLoc(Loc); setLAngleLoc(Loc); setRParenLoc(Loc); - TemplateSpecializationTypeLoc::initializeArgLocs(Context, getNumArgs(), - getTypePtr()->getArgs(), - getArgInfos(), Loc); + TemplateSpecializationTypeLoc::initializeArgLocs( + Context, + ArrayRef(getTypePtr()->getArgs(), getNumArgs()), + getArgInfos(), Loc); setNameLoc(Loc); } diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -1387,7 +1387,7 @@ if (!Policy.PrintCanonicalTypes && TAW) { const TemplateSpecializationType *TST = cast(TAW->getType()); - Args = TST->template_arguments(); + Args = TST->getSpecifiedArguments(); } else { const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); Args = TemplateArgs.asArray(); @@ -1470,14 +1470,27 @@ const SubstTemplateTypeParmPackType *T, raw_ostream &OS) { IncludeStrongLifetimeRAII Strong(Policy); - printTemplateTypeParmBefore(T->getReplacedParameter(), OS); + if (const TemplateTypeParmDecl *D = T->getReplacedTemplateParam()) { + if (D && D->isImplicit()) { + if (auto *TC = D->getTypeConstraint()) { + TC->print(OS, Policy); + OS << ' '; + } + OS << "auto"; + } else if (IdentifierInfo *Id = D->getIdentifier()) + OS << (Policy.CleanUglifiedParameters ? Id->deuglifiedName() + : Id->getName()); + else + OS << "type-parameter-" << D->getDepth() << '-' << D->getIndex(); + + spaceBeforePlaceHolder(OS); + } } void TypePrinter::printSubstTemplateTypeParmPackAfter( const SubstTemplateTypeParmPackType *T, raw_ostream &OS) { IncludeStrongLifetimeRAII Strong(Policy); - printTemplateTypeParmAfter(T->getReplacedParameter(), OS); } void TypePrinter::printTemplateId(const TemplateSpecializationType *T, @@ -1497,7 +1510,10 @@ DefaultTemplateArgsPolicyRAII TemplateArgs(Policy); const TemplateParameterList *TPL = TD ? TD->getTemplateParameters() : nullptr; - printTemplateArgumentList(OS, T->template_arguments(), Policy, TPL); + ArrayRef Args = T->isCanonicalUnqualified() + ? T->getConvertedArguments() + : T->getSpecifiedArguments(); + printTemplateArgumentList(OS, Args, Policy, TPL); spaceBeforePlaceHolder(OS); } @@ -1980,7 +1996,8 @@ ArrayRef TemplateArgs; if (auto *TTST = T->getAs()) { Template = TTST->getTemplateName(); - TemplateArgs = TTST->template_arguments(); + assert(!TTST->isCanonicalUnqualified()); + TemplateArgs = TTST->getSpecifiedArguments(); } else if (auto *CTSD = dyn_cast_or_null( T->getAsCXXRecordDecl())) { Template = TemplateName(CTSD->getSpecializedTemplate()); @@ -1992,11 +2009,12 @@ if (!isSubstitutedTemplateArgument(Ctx, Template, PTST->getTemplateName(), Args, Depth)) return false; - if (TemplateArgs.size() != PTST->getNumArgs()) + ArrayRef PArgs = PTST->getConvertedArguments(); + if (TemplateArgs.size() != PArgs.size()) return false; for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I) - if (!isSubstitutedTemplateArgument(Ctx, TemplateArgs[I], PTST->getArg(I), - Args, Depth)) + if (!isSubstitutedTemplateArgument(Ctx, TemplateArgs[I], PArgs[I], Args, + Depth)) return false; return true; } diff --git a/clang/lib/Analysis/BodyFarm.cpp b/clang/lib/Analysis/BodyFarm.cpp --- a/clang/lib/Analysis/BodyFarm.cpp +++ b/clang/lib/Analysis/BodyFarm.cpp @@ -230,8 +230,8 @@ C, base, IsArrow, SourceLocation(), NestedNameSpecifierLoc(), SourceLocation(), MemberDecl, FoundDecl, DeclarationNameInfo(MemberDecl->getDeclName(), SourceLocation()), - /* TemplateArgumentListInfo=*/ nullptr, MemberDecl->getType(), ValueKind, - OK_Ordinary, NOUR_None); + /* TemplateArgumentListInfo=*/nullptr, /*Deduced=*/nullptr, + MemberDecl->getType(), ValueKind, OK_Ordinary, NOUR_None); } ValueDecl *ASTMaker::findMemberField(const RecordDecl *RD, StringRef Name) { 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 @@ -1266,10 +1266,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; @@ -1277,7 +1278,8 @@ llvm::raw_svector_ostream OS(NS); Ty->getTemplateName().print(OS, getPrintingPolicy(), TemplateName::Qualified::None); - printTemplateArgumentList(OS, Ty->template_arguments(), getPrintingPolicy()); + printTemplateArgumentList(OS, Ty->getSpecifiedArguments(), + getPrintingPolicy()); SourceLocation Loc = AliasDecl->getLocation(); return DBuilder.createTypedef(Src, OS.str(), getOrCreateFile(Loc), diff --git a/clang/lib/Index/USRGeneration.cpp b/clang/lib/Index/USRGeneration.cpp --- a/clang/lib/Index/USRGeneration.cpp +++ b/clang/lib/Index/USRGeneration.cpp @@ -855,9 +855,9 @@ = T->getAs()) { Out << '>'; VisitTemplateName(Spec->getTemplateName()); - Out << Spec->getNumArgs(); - for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I) - VisitTemplateArgument(Spec->getArg(I)); + Out << Spec->getConvertedArguments().size(); + for (const TemplateArgument &Arg : Spec->getConvertedArguments()) + VisitTemplateArgument(Arg); return; } if (const DependentNameType *DNT = T->getAs()) { 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 @@ -99,8 +99,7 @@ if (ClassTemplateDecl *ClassTemplate = dyn_cast_or_null( SpecType->getTemplateName().getAsTemplateDecl())) { - QualType ContextType - = Context.getCanonicalType(QualType(SpecType, 0)); + auto ContextType = QualType(SpecType, 0); // If the type of the nested name specifier is the same as the // injected class name of the named class template, we're entering @@ -734,8 +733,8 @@ return false; } - QualType T = - Context.getTypeDeclType(cast(SD->getUnderlyingDecl())); + QualType T = resugar( + SS, Context.getTypeDeclType(cast(SD->getUnderlyingDecl()))); if (T->isEnumeralType()) Diag(IdInfo.IdentifierLoc, diag::warn_cxx98_compat_enum_nested_name_spec); @@ -875,17 +874,19 @@ QualType T = BuildDecltypeType(DS.getRepAsExpr()); if (T.isNull()) return true; + T = resugar(SS, 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; @@ -931,10 +932,9 @@ // Handle a dependent template specialization for which we cannot resolve // the template name. assert(DTN->getQualifier() == SS.getScopeRep()); - QualType T = Context.getDependentTemplateSpecializationType(ETK_None, - DTN->getQualifier(), - DTN->getIdentifier(), - TemplateArgs); + QualType T = Context.getDependentTemplateSpecializationType( + ETK_None, DTN->getQualifier(), DTN->getIdentifier(), + TemplateArgs.arguments()); // Create source-location information for this type. TypeLocBuilder Builder; @@ -975,18 +975,10 @@ // 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, 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 +990,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/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp --- a/clang/lib/Sema/SemaCast.cpp +++ b/clang/lib/Sema/SemaCast.cpp @@ -1808,7 +1808,9 @@ return TC_Failed; } - SrcExpr = Self.FixOverloadedFunctionReference(SrcExpr, FoundOverload, Fn); + // FIXME: resugar + SrcExpr = Self.FixOverloadedFunctionReference(SrcExpr, FoundOverload, Fn, + nullptr); if (!SrcExpr.isUsable()) { msg = 0; return TC_Failed; @@ -2885,7 +2887,9 @@ DeclAccessPair DAP; if (FunctionDecl *FD = Self.ResolveAddressOfOverloadedFunction( SrcExpr.get(), DestType, /*Complain=*/true, DAP)) - SrcExpr = Self.FixOverloadedFunctionReference(SrcExpr.get(), DAP, FD); + // FIXME: resugar + SrcExpr = + Self.FixOverloadedFunctionReference(SrcExpr.get(), DAP, FD, nullptr); else return; assert(SrcExpr.isUsable()); diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -560,9 +560,11 @@ if (!FD || FD->isUnnamedBitfield() || FD->isAnonymousStructOrUnion()) continue; + QualType FieldType = FD->getType(); + llvm::SmallString<20> Format = llvm::StringRef("%s%s %s "); llvm::SmallVector Args = {FieldIndentArg, - getTypeString(FD->getType()), + getTypeString(FieldType), getStringLiteral(FD->getName())}; if (FD->isBitField()) { @@ -578,15 +580,16 @@ ExprResult Field = IFD ? S.BuildAnonymousStructUnionMemberReference( CXXScopeSpec(), Loc, IFD, - DeclAccessPair::make(IFD, AS_public), RecordArg, Loc) + DeclAccessPair::make(IFD, AS_public), RecordArg, nullptr, + Loc) : S.BuildFieldReferenceExpr( - RecordArg, RecordArgIsPtr, Loc, CXXScopeSpec(), FD, - DeclAccessPair::make(FD, AS_public), + RecordArg, RecordArgIsPtr, Loc, NestedNameSpecifierLoc(), + FD, FieldType, DeclAccessPair::make(FD, AS_public), DeclarationNameInfo(FD->getDeclName(), Loc)); if (Field.isInvalid()) return true; - auto *InnerRD = FD->getType()->getAsRecordDecl(); + auto *InnerRD = FieldType->getAsRecordDecl(); auto *InnerCXXRD = dyn_cast_or_null(InnerRD); if (InnerRD && (!InnerCXXRD || InnerCXXRD->isAggregate())) { // Recursively print the values of members of aggregate record type. @@ -595,7 +598,7 @@ return true; } else { Format += " "; - if (appendFormatSpecifier(FD->getType(), Format)) { + if (appendFormatSpecifier(FieldType, Format)) { // We know how to print this field. Args.push_back(Field.get()); } else { diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -4657,9 +4657,10 @@ // Note we only handle the sugared types, they closely match what users wrote. // We explicitly choose to not handle ClassTemplateSpecializationDecl. if (auto *Specialization = T->getAs()) { - if (Specialization->getNumArgs() != 1) + if (Specialization->getSpecifiedArguments().size() != 1) return nullptr; - const TemplateArgument &Argument = Specialization->getArg(0); + const TemplateArgument &Argument = + Specialization->getSpecifiedArguments()[0]; if (Argument.getKind() != TemplateArgument::Type) return nullptr; return Argument.getAsType()->getAs(); diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -292,7 +292,8 @@ return true; MultiLevelTemplateArgumentList MLTAL; - MLTAL.addOuterTemplateArguments(TemplateArgs); + MLTAL.addOuterTemplateArguments(const_cast(Template), + TemplateArgs); for (const Expr *ConstraintExpr : ConstraintExprs) { if (calculateConstraintSatisfaction(S, Template, TemplateArgs, @@ -434,7 +435,7 @@ if (Inst.isInvalid()) return true; MultiLevelTemplateArgumentList MLTAL( - *Decl->getTemplateSpecializationArgs()); + Decl, Decl->getTemplateSpecializationArgs()->asArray()); if (addInstantiatedParametersToScope( Decl, Decl->getPrimaryTemplate()->getTemplatedDecl(), Scope, MLTAL)) return true; @@ -736,7 +737,7 @@ AtomicConstraint &Atomic = *N.getAtomicConstraint(); TemplateArgumentListInfo SubstArgs; MultiLevelTemplateArgumentList MLTAL; - MLTAL.addOuterTemplateArguments(TemplateArgs); + MLTAL.addOuterTemplateArguments(Concept, TemplateArgs); if (!Atomic.ParameterMapping) { llvm::SmallBitVector OccurringIndices(TemplateParams->size()); S.MarkUsedTemplateParameters(Atomic.ConstraintExpr, /*OnlyDeduced=*/false, 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 @@ -91,8 +91,8 @@ AddArg(T); // Build the template-id. - QualType CoroTrait = - S.CheckTemplateIdType(TemplateName(CoroTraits), KwLoc, Args); + QualType CoroTrait = S.CheckTemplateIdType( + CXXScopeSpec(), TemplateName(CoroTraits), KwLoc, Args); if (CoroTrait.isNull()) return QualType(); if (S.RequireCompleteType(KwLoc, CoroTrait, @@ -169,8 +169,8 @@ S.Context.getTrivialTypeSourceInfo(PromiseType, Loc))); // Build the template-id. - QualType CoroHandleType = - S.CheckTemplateIdType(TemplateName(CoroHandle), Loc, Args); + QualType CoroHandleType = S.CheckTemplateIdType( + CXXScopeSpec(), 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 @@ -530,6 +530,8 @@ DiagnoseUseOfDecl(IIDecl, NameLoc); T = Context.getTypeDeclType(TD); + if (SS && SS->isNotEmpty()) + T = resugar(*SS, T); MarkAnyDeclReferenced(TD->getLocation(), TD, /*OdrUse=*/false); } else if (ObjCInterfaceDecl *IDecl = dyn_cast(IIDecl)) { (void)DiagnoseUseOfDecl(IDecl, NameLoc); @@ -12277,6 +12279,7 @@ return true; } + // FIXME: Set TypeSourceInfo? VDecl->setType(DeducedType); assert(VDecl->isLinkageValid()); diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -3596,9 +3596,13 @@ return; } } else if (auto *ULE = dyn_cast(E)) { - if (ULE->hasExplicitTemplateArgs()) + if (ULE->hasExplicitTemplateArgs()) { S.Diag(Loc, diag::warn_cleanup_ext); - FD = S.ResolveSingleFunctionTemplateSpecialization(ULE, true); + TemplateArgumentListInfo ExplicitTemplateArgs; + ULE->copyTemplateArgumentsInto(ExplicitTemplateArgs); + FD = S.ResolveSingleFunctionTemplateSpecialization( + ULE, ExplicitTemplateArgs, /*Complain=*/true); + } NI = ULE->getNameInfo(); if (!FD) { S.Diag(Loc, diag::err_attribute_cleanup_arg_not_function) << 2 @@ -3620,6 +3624,7 @@ // We're currently more strict than GCC about what function types we accept. // If this ever proves to be a problem it should be easy to fix. + // FIXME: resugar QualType Ty = S.Context.getPointerType(cast(D)->getType()); QualType ParamTy = FD->getParamDecl(0)->getType(); if (S.CheckAssignmentConstraints(FD->getParamDecl(0)->getLocation(), 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(CXXScopeSpec(), TemplateName(TraitTD), Loc, Args); if (TraitTy.isNull()) return true; if (!S.isCompleteType(Loc, TraitTy)) { @@ -1401,6 +1402,9 @@ if (FD->isUnnamedBitfield()) continue; + // FIXME: Avoid having to recreate the naming context for every field. + QualType FieldType = S.resugar(DecompType.getTypePtr(), FD->getType()); + // All the non-static data members are required to be nameable, so they // must all have names. if (!FD->getDeclName()) { @@ -1412,7 +1416,7 @@ if (FD->isAnonymousStructOrUnion()) { S.Diag(Src->getLocation(), diag::err_decomp_decl_anon_union_member) - << DecompType << FD->getType()->isUnionType(); + << DecompType << FieldType->isUnionType(); S.Diag(FD->getLocation(), diag::note_declared_at); return true; } @@ -1444,7 +1448,7 @@ if (E.isInvalid()) return true; E = S.BuildFieldReferenceExpr(E.get(), /*IsArrow*/ false, Loc, - CXXScopeSpec(), FD, + NestedNameSpecifierLoc(), FD, FieldType, DeclAccessPair::make(FD, FD->getAccess()), DeclarationNameInfo(FD->getDeclName(), Loc)); if (E.isInvalid()) @@ -1458,7 +1462,7 @@ Qualifiers Q = DecompType.getQualifiers(); if (FD->isMutable()) Q.removeConst(); - B->setBinding(S.BuildQualifiedType(FD->getType(), Loc, Q), E.get()); + B->setBinding(S.BuildQualifiedType(FieldType, Loc, Q), E.get()); } if (I != Bindings.size()) @@ -8246,10 +8250,13 @@ DeclAccessPair Found = DeclAccessPair::make(Field, Field->getAccess()); DeclarationNameInfo NameInfo(Field->getDeclName(), Loc); + QualType FieldType = Field->getType(); return {S.BuildFieldReferenceExpr(Obj.first.get(), /*IsArrow=*/false, Loc, - CXXScopeSpec(), Field, Found, NameInfo), + NestedNameSpecifierLoc(), Field, + FieldType, Found, NameInfo), S.BuildFieldReferenceExpr(Obj.second.get(), /*IsArrow=*/false, Loc, - CXXScopeSpec(), Field, Found, NameInfo)}; + NestedNameSpecifierLoc(), Field, + FieldType, Found, NameInfo)}; } // FIXME: When expanding a subobject, register a note in the code synthesis @@ -11479,7 +11486,7 @@ Ty->getAs()) { Template = dyn_cast_or_null( TST->getTemplateName().getAsTemplateDecl()); - Arguments = TST->getArgs(); + Arguments = TST->getSpecifiedArguments().begin(); } if (!Template) return false; @@ -11561,7 +11568,8 @@ return Context.getElaboratedType( ElaboratedTypeKeyword::ETK_None, NestedNameSpecifier::Create(Context, nullptr, getStdNamespace()), - CheckTemplateIdType(TemplateName(StdInitializerList), Loc, Args)); + CheckTemplateIdType(CXXScopeSpec(), TemplateName(StdInitializerList), Loc, + Args)); } bool Sema::isInitListConstructor(const FunctionDecl *Ctor) { diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -3308,6 +3308,13 @@ QualType type = VD->getType(); if (type.isNull()) return ExprError(); + // A DeclRefExpr captures everything needed to make sense + // of the substitution sugar, so it's not correct to say + // that it would be escaping into it, however there is + // seemingly no use for it, and it would be more annoying + // to deal with it later. + type = TemplateArgs ? resugar(SS, VD, TemplateArgs->arguments(), type) + : resugar(SS, type); ExprValueKind valueKind = VK_PRValue; // In 'T ...V;', the type of the declaration 'V' is 'T...', but the type of @@ -9977,7 +9984,8 @@ DeclAccessPair DAP; if (FunctionDecl *FD = ResolveAddressOfOverloadedFunction( RHS.get(), LHSType, /*Complain=*/false, DAP)) - RHS = FixOverloadedFunctionReference(RHS.get(), DAP, FD); + // FIXME: resugar + RHS = FixOverloadedFunctionReference(RHS.get(), DAP, FD, nullptr); else return Incompatible; } @@ -14264,14 +14272,18 @@ } OverloadExpr *Ovl = cast(E); - if (isa(Ovl)) - if (!ResolveSingleFunctionTemplateSpecialization(Ovl)) { - Diag(OpLoc, diag::err_invalid_form_pointer_member_function) - << OrigOp.get()->getSourceRange(); - return QualType(); - } - - return Context.OverloadTy; + if (!isa(Ovl)) + return Context.OverloadTy; + if (Ovl->hasExplicitTemplateArgs()) { + TemplateArgumentListInfo ExplicitTemplateArgs; + Ovl->copyTemplateArgumentsInto(ExplicitTemplateArgs); + if (ResolveSingleFunctionTemplateSpecialization(Ovl, + ExplicitTemplateArgs)) + return Context.OverloadTy; + } + Diag(OpLoc, diag::err_invalid_form_pointer_member_function) + << OrigOp.get()->getSourceRange(); + return QualType(); } if (PTy->getKind() == BuiltinType::UnknownAny) @@ -14377,8 +14389,24 @@ if (isa(MD)) Diag(OpLoc, diag::err_typecheck_addrof_dtor) << op->getSourceRange(); - QualType MPTy = Context.getMemberPointerType( - op->getType(), Context.getTypeDeclType(MD->getParent()).getTypePtr()); + const CXXRecordDecl *Cls = MD->getParent(); + const Type *ClsType = nullptr; + if (const NestedNameSpecifier *NNS = DRE->getQualifier()) { + const Type *Type = NNS->getAsType(); + const CXXRecordDecl *ClsAsWritten = + Type ? Type->getAsCXXRecordDecl() : NNS->getAsRecordDecl(); + assert(ClsAsWritten != nullptr); + if (declaresSameEntity(Cls, ClsAsWritten)) + ClsType = + Type ? Type : Context.getTypeDeclType(ClsAsWritten).getTypePtr(); + else + // FIXME: Can we do better here? + assert(ClsAsWritten->isDerivedFrom(Cls)); + } + if (!ClsType) + ClsType = Context.getTypeDeclType(Cls).getTypePtr(); + + QualType MPTy = Context.getMemberPointerType(op->getType(), ClsType); // Under the MS ABI, lock down the inheritance model now. if (Context.getTargetInfo().getCXXABI().isMicrosoft()) (void)isCompleteType(OpLoc, MPTy); @@ -19144,8 +19172,8 @@ S.Context, Base.get(), ME->isArrow(), ME->getOperatorLoc(), ME->getQualifierLoc(), ME->getTemplateKeywordLoc(), ME->getMemberDecl(), ME->getFoundDecl(), ME->getMemberNameInfo(), - CopiedTemplateArgs(ME), ME->getType(), ME->getValueKind(), - ME->getObjectKind(), ME->isNonOdrUse()); + CopiedTemplateArgs(ME), ME->getDeduced(), ME->getType(), + ME->getValueKind(), ME->getObjectKind(), ME->isNonOdrUse()); } if (ME->getMemberDecl()->isCXXInstanceMember()) @@ -19162,7 +19190,8 @@ S.Context, ME->getBase(), ME->isArrow(), ME->getOperatorLoc(), ME->getQualifierLoc(), ME->getTemplateKeywordLoc(), ME->getMemberDecl(), ME->getFoundDecl(), ME->getMemberNameInfo(), CopiedTemplateArgs(ME), - ME->getType(), ME->getValueKind(), ME->getObjectKind(), NOUR); + ME->getDeduced(), ME->getType(), ME->getValueKind(), + ME->getObjectKind(), NOUR); } case Expr::BinaryOperatorClass: { @@ -19464,10 +19493,18 @@ // Re-set the member to trigger a recomputation of the dependence bits // for the expression. - if (auto *DRE = dyn_cast_or_null(E)) + CXXScopeSpec SS; + if (auto *DRE = dyn_cast_or_null(E)) { DRE->setDecl(DRE->getDecl()); - else if (auto *ME = dyn_cast_or_null(E)) + SS.Adopt(DRE->getQualifierLoc()); + DRE->setType(SemaRef.resugar( + SS, DRE->getDecl(), DRE->template_arguments(), DRE->getType())); + } else if (auto *ME = dyn_cast_or_null(E)) { ME->setMemberDecl(ME->getMemberDecl()); + SS.Adopt(ME->getQualifierLoc()); + ME->setType(SemaRef.resugar(SS, ME->getMemberDecl(), + ME->template_arguments(), ME->getType())); + } } else if (FirstInstantiation || isa(Var)) { // FIXME: For a specialization of a variable template, we don't @@ -20678,6 +20715,7 @@ SS.Adopt(DRE->getQualifierLoc()); TemplateArgumentListInfo TemplateArgs; DRE->copyTemplateArgumentsInto(TemplateArgs); + // FIXME: resugar return BuildDeclRefExpr( FD, FD->getType(), VK_LValue, DRE->getNameInfo(), DRE->hasQualifier() ? &SS : nullptr, DRE->getFoundDecl(), 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 @@ -4249,7 +4249,8 @@ if (DiagnoseUseOfDecl(Fn, From->getBeginLoc())) return ExprError(); - From = FixOverloadedFunctionReference(From, Found, Fn); + // FIXME: resugar + From = FixOverloadedFunctionReference(From, Found, Fn, nullptr); // We might get back another placeholder expression if we resolved to a // builtin. @@ -8907,13 +8908,13 @@ Context.getReferenceQualifiedType(E).getCanonicalType(); llvm::SmallVector Args; Args.push_back(TemplateArgument(MatchedType)); + + auto *Param = cast(TPL->getParam(0)); + TemplateArgumentList TAL(TemplateArgumentList::OnStack, Args); - MultiLevelTemplateArgumentList MLTAL(TAL); - for (unsigned I = 0; I < TPL->getDepth(); ++I) - MLTAL.addOuterRetainedLevel(); - Expr *IDC = - cast(TPL->getParam(0))->getTypeConstraint() - ->getImmediatelyDeclaredConstraint(); + MultiLevelTemplateArgumentList MLTAL(Param, TAL.asArray()); + MLTAL.addOuterRetainedLevels(TPL->getDepth()); + Expr *IDC = Param->getTypeConstraint()->getImmediatelyDeclaredConstraint(); ExprResult Constraint = SubstExpr(IDC, MLTAL); if (Constraint.isInvalid()) { Status = concepts::ExprRequirement::SS_ExprSubstitutionFailure; diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -798,18 +798,14 @@ false, ExtraArgs); } -ExprResult -Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS, - SourceLocation loc, - IndirectFieldDecl *indirectField, - DeclAccessPair foundDecl, - Expr *baseObjectExpr, - SourceLocation opLoc) { +ExprResult Sema::BuildAnonymousStructUnionMemberReference( + const CXXScopeSpec &SS, SourceLocation loc, + IndirectFieldDecl *indirectField, DeclAccessPair foundDecl, + Expr *baseObjectExpr, const Type *BaseType, SourceLocation opLoc) { // First, build the expression that refers to the base object. // Case 1: the base of the indirect field is not a field. VarDecl *baseVariable = indirectField->getVarDecl(); - CXXScopeSpec EmptySS; if (baseVariable) { assert(baseVariable->getType()->isRecordType()); @@ -822,6 +818,7 @@ DeclarationNameInfo baseNameInfo(DeclarationName(), loc); + CXXScopeSpec EmptySS; ExprResult result = BuildDeclarationNameExpr(EmptySS, baseNameInfo, baseVariable); if (result.isInvalid()) return ExprError(); @@ -839,6 +836,8 @@ IndirectFieldDecl::chain_iterator FI = indirectField->chain_begin(), FEnd = indirectField->chain_end(); + NestedNameSpecifierLoc NNS = SS.getWithLocInContext(Context); + // Case 2: the base of the indirect field is a field and the user // wrote a member expression. if (!baseVariable) { @@ -849,11 +848,15 @@ // Make a nameInfo that properly uses the anonymous name. DeclarationNameInfo memberNameInfo(field->getDeclName(), loc); + // FIXME: Avoid redundant setting of the naming scope with the loop below. + QualType FieldType = + BaseType ? resugar(BaseType, NNS, field->getType()) : field->getType(); + // Build the first member access in the chain with full information. - result = - BuildFieldReferenceExpr(result, baseObjectIsPointer, SourceLocation(), - SS, field, foundDecl, memberNameInfo) - .get(); + result = BuildFieldReferenceExpr(result, baseObjectIsPointer, + SourceLocation(), NNS, field, FieldType, + foundDecl, memberNameInfo) + .get(); if (!result) return ExprError(); } @@ -869,10 +872,14 @@ DeclAccessPair fakeFoundDecl = DeclAccessPair::make(field, field->getAccess()); + QualType FieldType = BaseType && FI == FEnd + ? resugar(BaseType, NNS, field->getType()) + : field->getType(); + result = BuildFieldReferenceExpr(result, /*isarrow*/ false, SourceLocation(), - (FI == FEnd ? SS : EmptySS), field, - fakeFoundDecl, memberNameInfo) + (FI == FEnd ? NNS : NestedNameSpecifierLoc()), + field, FieldType, fakeFoundDecl, memberNameInfo) .get(); } @@ -897,12 +904,13 @@ SourceLocation TemplateKWLoc, ValueDecl *Member, DeclAccessPair FoundDecl, bool HadMultipleCandidates, const DeclarationNameInfo &MemberNameInfo, QualType Ty, ExprValueKind VK, ExprObjectKind OK, - const TemplateArgumentListInfo *TemplateArgs) { + const TemplateArgumentListInfo *TemplateArgs, + const TemplateArgumentList *Deduced) { NestedNameSpecifierLoc NNS = SS ? SS->getWithLocInContext(Context) : NestedNameSpecifierLoc(); return BuildMemberExpr(Base, IsArrow, OpLoc, NNS, TemplateKWLoc, Member, FoundDecl, HadMultipleCandidates, MemberNameInfo, Ty, - VK, OK, TemplateArgs); + VK, OK, TemplateArgs, Deduced); } MemberExpr *Sema::BuildMemberExpr( @@ -910,13 +918,14 @@ SourceLocation TemplateKWLoc, ValueDecl *Member, DeclAccessPair FoundDecl, bool HadMultipleCandidates, const DeclarationNameInfo &MemberNameInfo, QualType Ty, ExprValueKind VK, ExprObjectKind OK, - const TemplateArgumentListInfo *TemplateArgs) { + const TemplateArgumentListInfo *TemplateArgs, + const TemplateArgumentList *Deduced) { assert((!IsArrow || Base->isPRValue()) && "-> base must be a pointer prvalue"); - MemberExpr *E = - MemberExpr::Create(Context, Base, IsArrow, OpLoc, NNS, TemplateKWLoc, - Member, FoundDecl, MemberNameInfo, TemplateArgs, Ty, - VK, OK, getNonOdrUseReasonInCurrentContext(Member)); + MemberExpr *E = MemberExpr::Create( + Context, Base, IsArrow, OpLoc, NNS, TemplateKWLoc, Member, FoundDecl, + MemberNameInfo, TemplateArgs, Deduced, Ty, VK, OK, + getNonOdrUseReasonInCurrentContext(Member)); E->setHadMultipleCandidates(HadMultipleCandidates); MarkMemberReferenced(E); @@ -1094,29 +1103,41 @@ if (DiagnoseUseOfDecl(MemberDecl, MemberLoc)) return ExprError(); - if (FieldDecl *FD = dyn_cast(MemberDecl)) - return BuildFieldReferenceExpr(BaseExpr, IsArrow, OpLoc, SS, FD, FoundDecl, - MemberNameInfo); + if (FieldDecl *FD = dyn_cast(MemberDecl)) { + assert(!TemplateArgs); + NestedNameSpecifierLoc NNS = SS.getWithLocInContext(Context); + QualType FieldType = resugar(BaseType.getTypePtr(), NNS, FD->getType()); + // null + // in case of implicit access. + return BuildFieldReferenceExpr(BaseExpr, IsArrow, OpLoc, NNS, FD, FieldType, + FoundDecl, MemberNameInfo); + } if (MSPropertyDecl *PD = dyn_cast(MemberDecl)) + // FIXME: resugar these. return BuildMSPropertyRefExpr(*this, BaseExpr, IsArrow, SS, PD, MemberNameInfo); if (IndirectFieldDecl *FD = dyn_cast(MemberDecl)) // We may have found a field within an anonymous union or struct // (C++ [class.union]). - return BuildAnonymousStructUnionMemberReference(SS, MemberLoc, FD, - FoundDecl, BaseExpr, - OpLoc); + return BuildAnonymousStructUnionMemberReference( + SS, MemberLoc, FD, FoundDecl, BaseExpr, BaseType.getTypePtr(), OpLoc); if (VarDecl *Var = dyn_cast(MemberDecl)) { - return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, &SS, TemplateKWLoc, Var, + assert(!TemplateArgs); + NestedNameSpecifierLoc NNS = SS.getWithLocInContext(Context); + QualType VarType = resugar(BaseType.getTypePtr(), NNS, Var->getType()); + return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, NNS, TemplateKWLoc, Var, FoundDecl, /*HadMultipleCandidates=*/false, - MemberNameInfo, Var->getType().getNonReferenceType(), + MemberNameInfo, VarType.getNonReferenceType(), VK_LValue, OK_Ordinary); } if (CXXMethodDecl *MemberFn = dyn_cast(MemberDecl)) { + assert(!TemplateArgs); + NestedNameSpecifierLoc NNS = SS.getWithLocInContext(Context); + ExprValueKind valueKind; QualType type; if (MemberFn->isInstance()) { @@ -1124,20 +1145,23 @@ type = Context.BoundMemberTy; } else { valueKind = VK_LValue; - type = MemberFn->getType(); + type = resugar(BaseType.getTypePtr(), NNS, MemberFn->getType()); } - return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, &SS, TemplateKWLoc, + return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, NNS, TemplateKWLoc, MemberFn, FoundDecl, /*HadMultipleCandidates=*/false, MemberNameInfo, type, valueKind, OK_Ordinary); } assert(!isa(MemberDecl) && "member function not C++ method?"); if (EnumConstantDecl *Enum = dyn_cast(MemberDecl)) { - return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, &SS, TemplateKWLoc, Enum, + assert(!TemplateArgs); + NestedNameSpecifierLoc NNS = SS.getWithLocInContext(Context); + // FIXME: EnumType resugaring not implemented. + QualType EnumType = resugar(BaseType.getTypePtr(), NNS, Enum->getType()); + return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, NNS, TemplateKWLoc, Enum, FoundDecl, /*HadMultipleCandidates=*/false, - MemberNameInfo, Enum->getType(), VK_PRValue, - OK_Ordinary); + MemberNameInfo, EnumType, VK_PRValue, OK_Ordinary); } if (VarTemplateDecl *VarTempl = dyn_cast(MemberDecl)) { @@ -1161,10 +1185,13 @@ if (!Var->getTemplateSpecializationKind()) Var->setTemplateSpecializationKind(TSK_ImplicitInstantiation, MemberLoc); + NestedNameSpecifierLoc NNS = SS.getWithLocInContext(Context); + QualType VarType = resugar(BaseType.getTypePtr(), NNS, Var, + TemplateArgs->arguments(), Var->getType()); return BuildMemberExpr( - BaseExpr, IsArrow, OpLoc, &SS, TemplateKWLoc, Var, FoundDecl, + BaseExpr, IsArrow, OpLoc, NNS, TemplateKWLoc, Var, FoundDecl, /*HadMultipleCandidates=*/false, MemberNameInfo, - Var->getType().getNonReferenceType(), VK_LValue, OK_Ordinary); + VarType.getNonReferenceType(), VK_LValue, OK_Ordinary); } // We found something that we didn't expect. Complain. @@ -1796,11 +1823,10 @@ } } -ExprResult -Sema::BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow, - SourceLocation OpLoc, const CXXScopeSpec &SS, - FieldDecl *Field, DeclAccessPair FoundDecl, - const DeclarationNameInfo &MemberNameInfo) { +ExprResult Sema::BuildFieldReferenceExpr( + Expr *BaseExpr, bool IsArrow, SourceLocation OpLoc, + const NestedNameSpecifierLoc &NNS, FieldDecl *Field, QualType FieldType, + DeclAccessPair FoundDecl, const DeclarationNameInfo &MemberNameInfo) { // x.a is an l-value if 'a' has a reference type. Otherwise: // x.a is an l-value/x-value/pr-value if the base is (and note // that *x is always an l-value), except that if the base isn't @@ -1817,9 +1843,8 @@ OK = OK_BitField; // Figure out the type of the member; see C99 6.5.2.3p3, C++ [expr.ref] - QualType MemberType = Field->getType(); - if (const ReferenceType *Ref = MemberType->getAs()) { - MemberType = Ref->getPointeeType(); + if (const ReferenceType *Ref = FieldType->getAs()) { + FieldType = Ref->getPointeeType(); VK = VK_LValue; } else { QualType BaseType = BaseExpr->getType(); @@ -1835,29 +1860,29 @@ if (Field->isMutable()) BaseQuals.removeConst(); Qualifiers MemberQuals = - Context.getCanonicalType(MemberType).getQualifiers(); + Context.getCanonicalType(FieldType).getQualifiers(); assert(!MemberQuals.hasAddressSpace()); Qualifiers Combined = BaseQuals + MemberQuals; if (Combined != MemberQuals) - MemberType = Context.getQualifiedType(MemberType, Combined); + FieldType = Context.getQualifiedType(FieldType, Combined); // Pick up NoDeref from the base in case we end up using AddrOf on the // result. E.g. the expression // &someNoDerefPtr->pointerMember // should be a noderef pointer again. if (BaseType->hasAttr(attr::NoDeref)) - MemberType = - Context.getAttributedType(attr::NoDeref, MemberType, MemberType); + FieldType = + Context.getAttributedType(attr::NoDeref, FieldType, FieldType); } auto *CurMethod = dyn_cast(CurContext); if (!(CurMethod && CurMethod->isDefaulted())) UnusedPrivateFields.remove(Field); - ExprResult Base = PerformObjectMemberConversion(BaseExpr, SS.getScopeRep(), - FoundDecl, Field); + ExprResult Base = PerformObjectMemberConversion( + BaseExpr, NNS.getNestedNameSpecifier(), FoundDecl, Field); if (Base.isInvalid()) return ExprError(); @@ -1872,10 +1897,10 @@ } } - return BuildMemberExpr(Base.get(), IsArrow, OpLoc, &SS, + return BuildMemberExpr(Base.get(), IsArrow, OpLoc, NNS, /*TemplateKWLoc=*/SourceLocation(), Field, FoundDecl, /*HadMultipleCandidates=*/false, MemberNameInfo, - MemberType, VK, OK); + FieldType, VK, OK); } /// Builds an implicit member access expression. The current context 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 @@ -8251,9 +8251,9 @@ S.CheckAddressOfMemberAccess(CurInit.get(), Step->Function.FoundDecl); if (S.DiagnoseUseOfDecl(Step->Function.FoundDecl, Kind.getLocation())) return ExprError(); - CurInit = S.FixOverloadedFunctionReference(CurInit, - Step->Function.FoundDecl, - Step->Function.Function); + // FIXME: resugar + CurInit = S.FixOverloadedFunctionReference( + CurInit, Step->Function.FoundDecl, Step->Function.Function, nullptr); // We might get back another placeholder expression if we resolved to a // builtin. if (!CurInit.isInvalid()) @@ -10275,12 +10275,13 @@ MarkFunctionReferenced(Kind.getLocation(), Best->Function); break; } + QualType RT = Best->Function->getReturnType(); + // FIXME: resugar here // C++ [dcl.type.class.deduct]p1: // The placeholder is replaced by the return type of the function selected // by overload resolution for class template deduction. - QualType DeducedType = - SubstAutoType(TSInfo->getType(), Best->Function->getReturnType()); + QualType DeducedType = SubstAutoType(TSInfo->getType(), RT); Diag(TSInfo->getTypeLoc().getBeginLoc(), diag::warn_cxx14_compat_class_template_argument_deduction) << TSInfo->getTypeLoc().getSourceRange() << 1 << DeducedType; diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -3691,11 +3691,11 @@ // is a well-formed template argument for the template parameter. if (StringLit) { SFINAETrap Trap(*this); - SmallVector Checked; + SmallVector SugaredChecked, CanonicalChecked; TemplateArgumentLoc Arg(TemplateArgument(StringLit), StringLit); - if (CheckTemplateArgument(Params->getParam(0), Arg, FD, - R.getNameLoc(), R.getNameLoc(), 0, - Checked) || + if (CheckTemplateArgument( + Params->getParam(0), Arg, FD, R.getNameLoc(), R.getNameLoc(), + 0, SugaredChecked, CanonicalChecked, CTAK_Specified) || Trap.hasErrorOccurred()) IsTemplate = false; } 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 @@ -637,7 +637,7 @@ auto *Saved = new (Context) DFIDeducedMismatchArgs; Saved->FirstArg = Info.FirstArg; Saved->SecondArg = Info.SecondArg; - Saved->TemplateArgs = Info.take(); + Saved->TemplateArgs = Info.takeSugared(); Saved->CallArgIndex = Info.CallArgIndex; Result.Data = Saved; break; @@ -666,7 +666,7 @@ } case Sema::TDK_SubstitutionFailure: - Result.Data = Info.take(); + Result.Data = Info.takeSugared(); if (Info.hasSFINAEDiagnostic()) { PartialDiagnosticAt *Diag = new (Result.Diagnostic) PartialDiagnosticAt( SourceLocation(), PartialDiagnostic::NullDiagnostic()); @@ -677,7 +677,7 @@ case Sema::TDK_ConstraintsNotSatisfied: { CNSInfo *Saved = new (Context) CNSInfo; - Saved->TemplateArgs = Info.take(); + Saved->TemplateArgs = Info.takeSugared(); Saved->Satisfaction = Info.AssociatedConstraintsSatisfaction; Result.Data = Saved; break; @@ -5692,9 +5692,6 @@ Sema::CCEKind CCE, bool RequireInt, NamedDecl *Dest) { - assert(S.getLangOpts().CPlusPlus11 && - "converted constant expression outside C++11"); - if (checkPlaceholderForOverload(S, From)) return ExprError(); @@ -6333,7 +6330,7 @@ OverloadCandidateSet &CandidateSet, bool SuppressUserConversions, bool PartialOverloading, bool AllowExplicit, bool AllowExplicitConversions, ADLCallKind IsADLCandidate, ConversionSequenceList EarlyConversions, - OverloadCandidateParamOrder PO) { + OverloadCandidateParamOrder PO, const TemplateArgumentList *Deduced) { const FunctionProtoType *Proto = dyn_cast(Function->getType()->getAs()); assert(Proto && "Functions without a prototype cannot be overloaded"); @@ -6352,7 +6349,7 @@ AddMethodCandidate(Method, FoundDecl, Method->getParent(), QualType(), Expr::Classification::makeSimpleLValue(), Args, CandidateSet, SuppressUserConversions, - PartialOverloading, EarlyConversions, PO); + PartialOverloading, EarlyConversions, PO, Deduced); return; } // We treat a constructor like a non-member function, since its object @@ -6397,6 +6394,7 @@ Candidate.IsADLCandidate = IsADLCandidate; Candidate.IgnoreObjectArgument = false; Candidate.ExplicitCallArguments = Args.size(); + Candidate.Deduced = Deduced; // Explicit functions are not actually candidates at all if we're not // allowing them in this context, but keep them around so we can point @@ -6931,16 +6929,13 @@ /// both @c a1 and @c a2. If @p SuppressUserConversions, then don't /// allow user-defined conversions via constructors or conversion /// operators. -void -Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, - CXXRecordDecl *ActingContext, QualType ObjectType, - Expr::Classification ObjectClassification, - ArrayRef Args, - OverloadCandidateSet &CandidateSet, - bool SuppressUserConversions, - bool PartialOverloading, - ConversionSequenceList EarlyConversions, - OverloadCandidateParamOrder PO) { +void Sema::AddMethodCandidate( + CXXMethodDecl *Method, DeclAccessPair FoundDecl, + CXXRecordDecl *ActingContext, QualType ObjectType, + Expr::Classification ObjectClassification, ArrayRef Args, + OverloadCandidateSet &CandidateSet, bool SuppressUserConversions, + bool PartialOverloading, ConversionSequenceList EarlyConversions, + OverloadCandidateParamOrder PO, const TemplateArgumentList *Deduced) { const FunctionProtoType *Proto = dyn_cast(Method->getType()->getAs()); assert(Proto && "Methods without a prototype cannot be overloaded"); @@ -6971,6 +6966,7 @@ Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; Candidate.ExplicitCallArguments = Args.size(); + Candidate.Deduced = Deduced; unsigned NumParams = Proto->getNumParams(); @@ -7147,7 +7143,7 @@ AddMethodCandidate(cast(Specialization), FoundDecl, ActingContext, ObjectType, ObjectClassification, Args, CandidateSet, SuppressUserConversions, PartialOverloading, - Conversions, PO); + Conversions, PO, Info.takeSugared()); } /// Determine whether a given function template has a simple explicit specifier @@ -7227,10 +7223,11 @@ // Add the function template specialization produced by template argument // deduction as a candidate. assert(Specialization && "Missing function template specialization?"); - AddOverloadCandidate( - Specialization, FoundDecl, Args, CandidateSet, SuppressUserConversions, - PartialOverloading, AllowExplicit, - /*AllowExplicitConversions*/ false, IsADLCandidate, Conversions, PO); + AddOverloadCandidate(Specialization, FoundDecl, Args, CandidateSet, + SuppressUserConversions, PartialOverloading, + AllowExplicit, + /*AllowExplicitConversions*/ false, IsADLCandidate, + Conversions, PO, Info.takeSugared()); } /// Check that implicit conversion sequences can be formed for each argument @@ -12076,15 +12073,20 @@ FailedCandidates(OvlExpr->getNameLoc(), /*ForTakingAddress=*/true) { ExtractUnqualifiedFunctionTypeFromTargetType(); + if (OvlExpr->hasExplicitTemplateArgs()) + OvlExpr->copyTemplateArgumentsInto(OvlExplicitTemplateArgs); + if (TargetFunctionType->isFunctionType()) { if (UnresolvedMemberExpr *UME = dyn_cast(OvlExpr)) if (!UME->isImplicitAccess() && - !S.ResolveSingleFunctionTemplateSpecialization(UME)) + (!OvlExpr->hasExplicitTemplateArgs() || + !S.ResolveSingleFunctionTemplateSpecialization( + UME, OvlExplicitTemplateArgs))) StaticMemberFunctionFromBoundPointer = true; } else if (OvlExpr->hasExplicitTemplateArgs()) { DeclAccessPair dap; if (FunctionDecl *Fn = S.ResolveSingleFunctionTemplateSpecialization( - OvlExpr, false, &dap)) { + OvlExpr, OvlExplicitTemplateArgs, /*Complain=*/false, &dap)) { if (CXXMethodDecl *Method = dyn_cast(Fn)) if (!Method->isStatic()) { // If the target type is a non-function type and the function found @@ -12103,9 +12105,6 @@ return; } - if (OvlExpr->hasExplicitTemplateArgs()) - OvlExpr->copyTemplateArgumentsInto(OvlExplicitTemplateArgs); - if (FindAllFunctionsThatMatchTargetTypeExactly()) { // C++ [over.over]p4: // If more than one function is selected, [...] @@ -12591,7 +12590,8 @@ // for both. DiagnoseUseOfDecl(Found, E->getExprLoc()); CheckAddressOfMemberAccess(E, DAP); - Expr *Fixed = FixOverloadedFunctionReference(E, DAP, Found); + // FIXME: resugar + Expr *Fixed = FixOverloadedFunctionReference(E, DAP, Found, nullptr); if (DoFunctionPointerConverion && Fixed->getType()->isFunctionType()) SrcExpr = DefaultFunctionArrayConversion(Fixed, /*Diagnose=*/false); else @@ -12609,10 +12609,9 @@ /// /// If no template-ids are found, no diagnostics are emitted and NULL is /// returned. -FunctionDecl * -Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl, - bool Complain, - DeclAccessPair *FoundResult) { +FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization( + OverloadExpr *ovl, TemplateArgumentListInfo &ExplicitTemplateArgs, + bool Complain, DeclAccessPair *FoundResult) { // C++ [over.over]p1: // [...] [Note: any redundant set of parentheses surrounding the // overloaded function name is ignored (5.1). ] @@ -12620,12 +12619,9 @@ // [...] The overloaded function name can be preceded by the & // operator. - // If we didn't actually find any template-ids, we're done. - if (!ovl->hasExplicitTemplateArgs()) - return nullptr; + // Specializations must have template args. + assert(ovl->hasExplicitTemplateArgs()); - TemplateArgumentListInfo ExplicitTemplateArgs; - ovl->copyTemplateArgumentsInto(ExplicitTemplateArgs); TemplateSpecCandidateSet FailedCandidates(ovl->getNameLoc()); // Look through all of the overloaded functions, searching for one @@ -12701,50 +12697,54 @@ assert(SrcExpr.get()->getType() == Context.OverloadTy); OverloadExpr::FindResult ovl = OverloadExpr::find(SrcExpr.get()); - - DeclAccessPair found; ExprResult SingleFunctionExpression; - if (FunctionDecl *fn = ResolveSingleFunctionTemplateSpecialization( - ovl.Expression, /*complain*/ false, &found)) { - if (DiagnoseUseOfDecl(fn, SrcExpr.get()->getBeginLoc())) { - SrcExpr = ExprError(); - return true; - } + if (ovl.Expression->hasExplicitTemplateArgs()) { + TemplateArgumentListInfo ExplicitTemplateArgs; + ovl.Expression->copyTemplateArgumentsInto(ExplicitTemplateArgs); + + DeclAccessPair found; + if (FunctionDecl *fn = ResolveSingleFunctionTemplateSpecialization( + ovl.Expression, ExplicitTemplateArgs, /*Complain=*/false, &found)) { + if (DiagnoseUseOfDecl(fn, SrcExpr.get()->getBeginLoc())) { + SrcExpr = ExprError(); + return true; + } - // It is only correct to resolve to an instance method if we're - // resolving a form that's permitted to be a pointer to member. - // Otherwise we'll end up making a bound member expression, which - // is illegal in all the contexts we resolve like this. - if (!ovl.HasFormOfMemberPointer && - isa(fn) && - cast(fn)->isInstance()) { - if (!complain) return false; - - Diag(ovl.Expression->getExprLoc(), - diag::err_bound_member_function) - << 0 << ovl.Expression->getSourceRange(); - - // TODO: I believe we only end up here if there's a mix of - // static and non-static candidates (otherwise the expression - // would have 'bound member' type, not 'overload' type). - // Ideally we would note which candidate was chosen and why - // the static candidates were rejected. - SrcExpr = ExprError(); - return true; - } + // It is only correct to resolve to an instance method if we're + // resolving a form that's permitted to be a pointer to member. + // Otherwise we'll end up making a bound member expression, which + // is illegal in all the contexts we resolve like this. + if (!ovl.HasFormOfMemberPointer && isa(fn) && + cast(fn)->isInstance()) { + if (!complain) + return false; - // Fix the expression to refer to 'fn'. - SingleFunctionExpression = - FixOverloadedFunctionReference(SrcExpr.get(), found, fn); + Diag(ovl.Expression->getExprLoc(), diag::err_bound_member_function) + << 0 << ovl.Expression->getSourceRange(); - // If desired, do function-to-pointer decay. - if (doFunctionPointerConverion) { - SingleFunctionExpression = - DefaultFunctionArrayLvalueConversion(SingleFunctionExpression.get()); - if (SingleFunctionExpression.isInvalid()) { + // TODO: I believe we only end up here if there's a mix of + // static and non-static candidates (otherwise the expression + // would have 'bound member' type, not 'overload' type). + // Ideally we would note which candidate was chosen and why + // the static candidates were rejected. SrcExpr = ExprError(); return true; } + + // Fix the expression to refer to 'fn'. + // FIXME: resugar + SingleFunctionExpression = + FixOverloadedFunctionReference(SrcExpr.get(), found, fn, nullptr); + + // If desired, do function-to-pointer decay. + if (doFunctionPointerConverion) { + SingleFunctionExpression = DefaultFunctionArrayLvalueConversion( + SingleFunctionExpression.get()); + if (SingleFunctionExpression.isInvalid()) { + SrcExpr = ExprError(); + return true; + } + } } } @@ -13257,7 +13257,8 @@ SemaRef.CheckUnresolvedLookupAccess(ULE, (*Best)->FoundDecl); if (SemaRef.DiagnoseUseOfDecl(FDecl, ULE->getNameLoc())) return ExprError(); - Fn = SemaRef.FixOverloadedFunctionReference(Fn, (*Best)->FoundDecl, FDecl); + Fn = SemaRef.FixOverloadedFunctionReference(Fn, (*Best)->FoundDecl, FDecl, + (*Best)->Deduced); return SemaRef.BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, RParenLoc, ExecConfig, /*IsExecConfig=*/false, (*Best)->IsADLCandidate); @@ -13315,7 +13316,8 @@ // We emitted an error for the unavailable/deleted function call but keep // the call in the AST. FunctionDecl *FDecl = (*Best)->Function; - Fn = SemaRef.FixOverloadedFunctionReference(Fn, (*Best)->FoundDecl, FDecl); + Fn = SemaRef.FixOverloadedFunctionReference(Fn, (*Best)->FoundDecl, FDecl, + (*Best)->Deduced); return SemaRef.BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, RParenLoc, ExecConfig, /*IsExecConfig=*/false, (*Best)->IsADLCandidate); @@ -14583,7 +14585,8 @@ if (!Succeeded) return BuildRecoveryExpr(chooseRecoveryType(CandidateSet, &Best)); - MemExprE = FixOverloadedFunctionReference(MemExprE, FoundDecl, Method); + MemExprE = FixOverloadedFunctionReference(MemExprE, FoundDecl, Method, + Best->Deduced); // If overload resolution picked a static member, build a // non-member call based on that function. @@ -14594,20 +14597,34 @@ MemExpr = cast(MemExprE->IgnoreParens()); } + assert(Method && "Member call to something that isn't a method?"); - QualType ResultType = Method->getReturnType(); - ExprValueKind VK = Expr::getValueKindForType(ResultType); - ResultType = ResultType.getNonLValueExprType(Context); + QualType MethodType; + { + QualType BaseType = MemExpr->getBase()->getType(); + if (MemExpr->isArrow()) + BaseType = BaseType->castAs()->getPointeeType(); + NestedNameSpecifierLoc NNS = MemExpr->getQualifierLoc(); + // FIXME: Should we resugar the explicit template arguments as well? + const TemplateArgumentList *Deduced = MemExpr->getDeduced(); + MethodType = Deduced + ? resugar(BaseType.getTypePtr(), NNS, Method, + Deduced->asArray(), Method->getType()) + : resugar(BaseType.getTypePtr(), NNS, Method->getType()); + } + + const auto *Proto = MethodType->castAs(); + QualType ReturnType = Proto->getReturnType(); + + ExprValueKind VK = Expr::getValueKindForType(ReturnType); + QualType ResultType = ReturnType.getNonLValueExprType(Context); - assert(Method && "Member call to something that isn't a method?"); - const auto *Proto = Method->getType()->castAs(); CXXMemberCallExpr *TheCall = CXXMemberCallExpr::Create( Context, MemExprE, Args, ResultType, VK, RParenLoc, CurFPFeatureOverrides(), Proto->getNumParams()); // Check for a valid return type. - if (CheckCallReturnType(Method->getReturnType(), MemExpr->getMemberLoc(), - TheCall, Method)) + if (CheckCallReturnType(ReturnType, MemExpr->getMemberLoc(), TheCall, Method)) return BuildRecoveryExpr(ResultType); // Convert the object argument (for a non-static member function call). @@ -15198,11 +15215,13 @@ /// perhaps a '&' around it). We have resolved the overloaded function /// to the function declaration Fn, so patch up the expression E to /// refer (possibly indirectly) to Fn. Returns the new expr. -Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, - FunctionDecl *Fn) { +Expr * +Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, + FunctionDecl *Fn, + const TemplateArgumentList *Deduced) { if (ParenExpr *PE = dyn_cast(E)) { - Expr *SubExpr = FixOverloadedFunctionReference(PE->getSubExpr(), - Found, Fn); + Expr *SubExpr = + FixOverloadedFunctionReference(PE->getSubExpr(), Found, Fn, Deduced); if (SubExpr == PE->getSubExpr()) return PE; @@ -15210,8 +15229,8 @@ } if (ImplicitCastExpr *ICE = dyn_cast(E)) { - Expr *SubExpr = FixOverloadedFunctionReference(ICE->getSubExpr(), - Found, Fn); + Expr *SubExpr = + FixOverloadedFunctionReference(ICE->getSubExpr(), Found, Fn, Deduced); assert(Context.hasSameType(ICE->getSubExpr()->getType(), SubExpr->getType()) && "Implicit cast type cannot be determined from overload"); @@ -15226,8 +15245,8 @@ if (auto *GSE = dyn_cast(E)) { if (!GSE->isResultDependent()) { - Expr *SubExpr = - FixOverloadedFunctionReference(GSE->getResultExpr(), Found, Fn); + Expr *SubExpr = FixOverloadedFunctionReference(GSE->getResultExpr(), + Found, Fn, Deduced); if (SubExpr == GSE->getResultExpr()) return GSE; @@ -15261,7 +15280,7 @@ // UnresolvedLookupExpr holding an overloaded member function // or template. Expr *SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(), - Found, Fn); + Found, Fn, Deduced); if (SubExpr == UnOp->getSubExpr()) return UnOp; @@ -15273,10 +15292,15 @@ // We have taken the address of a pointer to member // function. Perform the computation here so that we get the // appropriate pointer to member type. + // FIXME: get sugared class type QualType ClassType = Context.getTypeDeclType(cast(Method->getDeclContext())); - QualType MemPtrType - = Context.getMemberPointerType(Fn->getType(), ClassType.getTypePtr()); + QualType Type = Type = + Deduced + ? resugar(CXXScopeSpec(), Fn, Deduced->asArray(), Fn->getType()) + : resugar(CXXScopeSpec(), Fn->getType()); + QualType MemPtrType = + Context.getMemberPointerType(Type, ClassType.getTypePtr()); // Under the MS ABI, lock down the inheritance model now. if (Context.getTargetInfo().getCXXABI().isMicrosoft()) (void)isCompleteType(UnOp->getOperatorLoc(), MemPtrType); @@ -15286,8 +15310,8 @@ UnOp->getOperatorLoc(), false, CurFPFeatureOverrides()); } } - Expr *SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(), - Found, Fn); + Expr *SubExpr = + FixOverloadedFunctionReference(UnOp->getSubExpr(), Found, Fn, Deduced); if (SubExpr == UnOp->getSubExpr()) return UnOp; @@ -15303,21 +15327,28 @@ ULE->copyTemplateArgumentsInto(TemplateArgsBuffer); TemplateArgs = &TemplateArgsBuffer; } + NestedNameSpecifierLoc NNS = ULE->getQualifierLoc(); - QualType Type = Fn->getType(); ExprValueKind ValueKind = getLangOpts().CPlusPlus ? VK_LValue : VK_PRValue; // FIXME: Duplicated from BuildDeclarationNameExpr. - if (unsigned BID = Fn->getBuiltinID()) { - if (!Context.BuiltinInfo.isDirectlyAddressable(BID)) { + QualType Type; + { + unsigned BID = Fn->getBuiltinID(); + if (BID && !Context.BuiltinInfo.isDirectlyAddressable(BID)) { Type = Context.BuiltinFnTy; ValueKind = VK_PRValue; + } else { + CXXScopeSpec SS; + SS.Adopt(NNS); + Type = Deduced ? resugar(SS, Fn, Deduced->asArray(), Fn->getType()) + : resugar(SS, Fn->getType()); } } DeclRefExpr *DRE = BuildDeclRefExpr( - Fn, Type, ValueKind, ULE->getNameInfo(), ULE->getQualifierLoc(), - Found.getDecl(), ULE->getTemplateKeywordLoc(), TemplateArgs); + Fn, Type, ValueKind, ULE->getNameInfo(), NNS, Found.getDecl(), + ULE->getTemplateKeywordLoc(), TemplateArgs); DRE->setHadMultipleCandidates(ULE->getNumDecls() > 1); return DRE; } @@ -15329,6 +15360,10 @@ MemExpr->copyTemplateArgumentsInto(TemplateArgsBuffer); TemplateArgs = &TemplateArgsBuffer; } + QualType BaseType = MemExpr->getBaseType(); + const Type *BasePointeeType = BaseType->getPointeeType().getTypePtrOrNull(); + if (!BasePointeeType) + BasePointeeType = BaseType.getTypePtr(); Expr *Base; @@ -15336,46 +15371,52 @@ // implicit member access, rewrite to a simple decl ref. if (MemExpr->isImplicitAccess()) { if (cast(Fn)->isStatic()) { - DeclRefExpr *DRE = BuildDeclRefExpr( - Fn, Fn->getType(), VK_LValue, MemExpr->getNameInfo(), - MemExpr->getQualifierLoc(), Found.getDecl(), - MemExpr->getTemplateKeywordLoc(), TemplateArgs); + QualType Type = Type = Deduced + ? resugar(BasePointeeType, Fn, + Deduced->asArray(), Fn->getType()) + : resugar(BasePointeeType, Fn->getType()); + DeclRefExpr *DRE = + BuildDeclRefExpr(Fn, Type, VK_LValue, MemExpr->getNameInfo(), + MemExpr->getQualifierLoc(), Found.getDecl(), + MemExpr->getTemplateKeywordLoc(), TemplateArgs); DRE->setHadMultipleCandidates(MemExpr->getNumDecls() > 1); return DRE; } else { SourceLocation Loc = MemExpr->getMemberLoc(); if (MemExpr->getQualifier()) Loc = MemExpr->getQualifierLoc().getBeginLoc(); - Base = - BuildCXXThisExpr(Loc, MemExpr->getBaseType(), /*IsImplicit=*/true); + Base = BuildCXXThisExpr(Loc, BaseType, /*IsImplicit=*/true); } } else Base = MemExpr->getBase(); ExprValueKind valueKind; - QualType type; + QualType Type; if (cast(Fn)->isStatic()) { valueKind = VK_LValue; - type = Fn->getType(); + Type = Deduced ? resugar(BasePointeeType, Fn, Deduced->asArray(), + Fn->getType()) + : resugar(BasePointeeType, Fn->getType()); } else { valueKind = VK_PRValue; - type = Context.BoundMemberTy; + Type = Context.BoundMemberTy; } return BuildMemberExpr( Base, MemExpr->isArrow(), MemExpr->getOperatorLoc(), MemExpr->getQualifierLoc(), MemExpr->getTemplateKeywordLoc(), Fn, Found, - /*HadMultipleCandidates=*/true, MemExpr->getMemberNameInfo(), - type, valueKind, OK_Ordinary, TemplateArgs); + /*HadMultipleCandidates=*/true, MemExpr->getMemberNameInfo(), Type, + valueKind, OK_Ordinary, TemplateArgs, Deduced); } llvm_unreachable("Invalid reference to overloaded function"); } -ExprResult Sema::FixOverloadedFunctionReference(ExprResult E, - DeclAccessPair Found, - FunctionDecl *Fn) { - return FixOverloadedFunctionReference(E.get(), Found, Fn); +ExprResult +Sema::FixOverloadedFunctionReference(ExprResult E, DeclAccessPair Found, + FunctionDecl *Fn, + const TemplateArgumentList *Deduced) { + return FixOverloadedFunctionReference(E.get(), Found, Fn, Deduced); } bool clang::shouldEnforceArgLimit(bool PartialOverloading, 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" @@ -91,6 +92,1272 @@ return Depth; } +TemplateDecl *getTemplateDecl(NamedDecl *D) { + switch (D->getKind()) { + case Decl::Kind::Var: + case Decl::Kind::ParmVar: + case Decl::Kind::Field: + case Decl::Kind::IndirectField: + case Decl::Kind::EnumConstant: + case Decl::Kind::Binding: + case Decl::Kind::ImplicitParam: + case Decl::Kind::MSGuid: + case Decl::Kind::MSProperty: + case Decl::Kind::NonTypeTemplateParm: + case Decl::Kind::TemplateParamObject: + return nullptr; + case Decl::Kind::FunctionTemplate: + case Decl::Kind::ClassTemplate: + case Decl::Kind::TypeAliasTemplate: + case Decl::Kind::BuiltinTemplate: + return cast(D); + case Decl::Kind::VarTemplateSpecialization: + return cast(D)->getSpecializedTemplate(); + case Decl::Kind::CXXDeductionGuide: + return cast(D)->getDeducedTemplate(); + case Decl::Kind::CXXConversion: + case Decl::Kind::CXXConstructor: + case Decl::Kind::CXXDestructor: + case Decl::Kind::CXXMethod: + case Decl::Kind::Function: { + const auto *FD = cast(D); + switch (FD->getTemplatedKind()) { + case FunctionDecl::TK_NonTemplate: + case FunctionDecl::TK_DependentNonTemplate: + return nullptr; + case FunctionDecl::TK_FunctionTemplate: + return FD->getDescribedFunctionTemplate(); + case FunctionDecl::TK_MemberSpecialization: + return nullptr; + case FunctionDecl::TK_FunctionTemplateSpecialization: + return FD->getPrimaryTemplate(); + case FunctionDecl::TK_DependentFunctionTemplateSpecialization: + return nullptr; + } + llvm_unreachable("Unhandled function template kind"); + } + case Decl::Kind::CXXRecord: + return cast(D)->getDescribedClassTemplate(); + case Decl::Kind::TemplateTemplateParm: + return cast(D); + default: + // Maybe fall back to Decl::getDescribedTemplate. + D->dumpColor(); + llvm_unreachable("Unhandled decl kind"); + } +} + +namespace { +class Resugarer : public TreeTransform { + using inherited = TreeTransform; + + struct Inner { + const Decl *ReplacedDecl; + ArrayRef Args; + }; + Inner CurInner; + + using TemplateToArgs = + llvm::DenseMap>; + TemplateToArgs CurTemplateToArgs; + + SmallVector, 4> ArgsBuf; + + const TemplateArgument *getArgument(const Decl *ReplacedDecl, unsigned Index, + Optional PackIndex) const { + ArrayRef Args; + if (!CurInner.Args.empty() && CurInner.ReplacedDecl == ReplacedDecl) { + Args = CurInner.Args; + } else { + auto It = CurTemplateToArgs.find(ReplacedDecl); + if (It == CurTemplateToArgs.end()) + return nullptr; + Args = It->second; + } + // FIXME: This should never happen, but some arguments might be missing + // from argument deduction of function templates + if (Index >= Args.size()) + return nullptr; + const TemplateArgument &Arg = Args[Index]; + if (!PackIndex) + return &Arg; + ArrayRef PackArgs = Arg.getPackAsArray(); + // FIXME: As above, arguments might be missing. + if (*PackIndex >= PackArgs.size()) + return nullptr; + return &PackArgs[*PackIndex]; + } + + struct BaseSemanticContextRAII { + BaseSemanticContextRAII(Resugarer &R) + : R(&R), OldInner(std::move(R.CurInner)) {} + ~BaseSemanticContextRAII() { R->CurInner = std::move(OldInner); } + + protected: + Resugarer *R; + + private: + Inner OldInner; + }; + +public: + struct NonTemplateSemanticContextRAII { + NonTemplateSemanticContextRAII(Resugarer &R) + : R(&R), OldInner(std::move(R.CurInner)) {} + ~NonTemplateSemanticContextRAII() { R->CurInner = std::move(OldInner); } + + protected: + Resugarer *R; + + private: + Inner OldInner; + }; + + struct SemanticContextRAII : private NonTemplateSemanticContextRAII { + SemanticContextRAII(Resugarer &R, NamedDecl *ND, + ArrayRef Args) + : NonTemplateSemanticContextRAII(R), OldArgsBufSize(R.ArgsBuf.size()) { + assert(ND != nullptr); + assert(Args.size() != 0); + TemplateDecl *TD = getTemplateDecl(ND); + assert(TD != nullptr); + R.CurInner = {TD->getCanonicalDecl(), Args}; + } + + SemanticContextRAII(Resugarer &R, NamedDecl *ND, + ArrayRef Args) + : NonTemplateSemanticContextRAII(R), OldArgsBufSize(R.ArgsBuf.size()) { + assert(ND != nullptr); + if (Args.size() == 0) + return; + TemplateDecl *TD = getTemplateDecl(ND); + assert(TD != nullptr); + R.CurInner.ReplacedDecl = TD->getCanonicalDecl(); + + Sema::SFINAETrap Trap(R.SemaRef); + + Qualifiers ThisTypeQuals; + CXXRecordDecl *ThisContext = nullptr; + if (auto *Method = dyn_cast(ND)) { + ThisContext = Method->getParent(); + ThisTypeQuals = Method->getMethodQualifiers(); + } + Sema::CXXThisScopeRAII ThisScope(R.SemaRef, ThisContext, ThisTypeQuals, + R.SemaRef.getLangOpts().CPlusPlus17); + + TemplateArgumentListInfo TAL; + for (const auto &ArgLoc : Args) + TAL.addArgument(ArgLoc); + SmallVector ConvertedArgs, CanonicalConverted; + if (R.SemaRef.CheckTemplateArgumentList( + TD, SourceLocation(), TAL, false, ConvertedArgs, + CanonicalConverted, + /*UpdateArgsWithConversions=*/false)) { + // FIXME: This can fail sometimes because we only keep + // the as-written template arguments around for + // functions, and we don't have the information + // to try to deduce them again. + assert(TD->getKind() == Decl::Kind::FunctionTemplate); + return; + } + switch (ND->getKind()) { + case Decl::Kind::TypeAliasTemplate: + case Decl::Kind::BuiltinTemplate: + case Decl::Kind::CXXMethod: + case Decl::Kind::Function: + break; + case Decl::Kind::VarTemplateSpecialization: { + auto *VD = cast(ND); + auto *VTPSD = VD->getSpecializedTemplateOrPartial() + .dyn_cast(); + if (!VTPSD) + break; + TemplateParameterList *TPL = VTPSD->getTemplateParameters(); + TemplateDeductionInfo Info(SourceLocation{}, TPL->getDepth()); + // FIXME: We can't deal very well with non-canonical template + // arguments so this will fail sometimes. + Sema::TemplateDeductionResult Res = R.SemaRef.DeduceTemplateArguments( + VTPSD, + TemplateArgumentList(TemplateArgumentList::OnStackType{}, + ConvertedArgs), + Info); + if (Res != Sema::TDK_Success) + break; + R.CurInner.Args = Info.takeSugared()->asArray(); + return; + } + default: + ND->dump(); + llvm_unreachable("Unhandled Template Kind"); + } + R.CurInner.Args = R.ArgsBuf.emplace_back(std::move(ConvertedArgs)); + } + + ~SemanticContextRAII() { R->ArgsBuf.resize(OldArgsBufSize); } + + size_t OldArgsBufSize; + }; + + struct NamingContextBase { + NamingContextBase(Resugarer &R) + : R(&R), OldTemplateToArgs(std::move(R.CurTemplateToArgs)), + OldArgsBufSize(R.ArgsBuf.size()) {} + ~NamingContextBase() { + R->CurTemplateToArgs = std::move(OldTemplateToArgs); + R->ArgsBuf.resize(OldArgsBufSize); + } + + protected: + void insertTemplateToMap(bool Reverse, const Decl *Template, + ArrayRef Args) { + Template = Template->getCanonicalDecl(); + assert(!Args.empty()); + if (Reverse) { + R->CurTemplateToArgs.try_emplace(Template, Args); + } else { + R->CurTemplateToArgs[Template] = Args; + } + } + + void addTypeToMap(bool Reverse, const Type *T) { + struct { + NamedDecl *ND; + const TemplateSpecializationType *TS; + } Entity; + { + QualType TCanon = T->getCanonicalTypeInternal(); + switch (TCanon->getTypeClass()) { + case Type::Record: { + const auto *TS = T->getAs(); + while (TS && TS->isTypeAlias()) + TS = TS->getAliasedType()->getAs(); + Entity = {T->getAsRecordDecl(), TS}; + break; + } + case Type::InjectedClassName: { + const auto *ICN = cast(TCanon); + Entity = {ICN->getDecl(), ICN->getInjectedTST()}; + break; + } + case Type::TemplateSpecialization: + case Type::DependentTemplateSpecialization: + case Type::TemplateTypeParm: + case Type::DependentName: + case Type::Enum: + case Type::Builtin: + return; + default: + TCanon.dump(); + llvm_unreachable(""); + } + } + switch (auto NDK = Entity.ND->getKind()) { + case Decl::CXXRecord: + case Decl::Record: + return; + case Decl::ClassTemplateSpecialization: + case Decl::ClassTemplatePartialSpecialization: { + if (!Entity.TS) + return; + assert(!Entity.TS->isTypeAlias()); + auto *CTSD = cast(Entity.ND); + if (auto *CTPSD = + CTSD->getSpecializedTemplateOrPartial() + .dyn_cast()) { + TemplateParameterList *TPL = CTPSD->getTemplateParameters(); + TemplateDeductionInfo Info(SourceLocation{}, TPL->getDepth()); + // FIXME: We can't deal very well with non-canonical template + // arguments so this will fail sometimes. + Sema::TemplateDeductionResult Res = + R->SemaRef.DeduceTemplateArguments( + CTPSD, + TemplateArgumentList(TemplateArgumentList::OnStackType{}, + Entity.TS->getConvertedArguments()), + Info); + assert(Res == Sema::TDK_Success); + return insertTemplateToMap(Reverse, CTSD, + Info.takeSugared()->asArray()); + } + return insertTemplateToMap(Reverse, CTSD, + Entity.TS->getConvertedArguments()); + } + default: + break; + } + Entity.ND->dumpColor(); + llvm_unreachable("Unhandled Decl Kind"); + } + + Resugarer *R; + TemplateToArgs OldTemplateToArgs; + + private: + size_t OldArgsBufSize; + }; + + struct NamingContextRAII : NamingContextBase { + NamingContextRAII(Resugarer &R, const NestedNameSpecifier *NNS, + const Type *BaseType = nullptr) + : NamingContextBase(R) { + if (BaseType) { + assert(!BaseType->getAs()); + addTypeToMap(/*Reverse=*/false, BaseType); + } + for (/**/; NNS; NNS = NNS->getPrefix()) { + switch (NNS->getKind()) { + case NestedNameSpecifier::Global: + case NestedNameSpecifier::Namespace: + case NestedNameSpecifier::NamespaceAlias: + return; + case NestedNameSpecifier::Identifier: + case NestedNameSpecifier::Super: + continue; + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: + addTypeToMap(/*Reverse=*/false, NNS->getAsType()); + continue; + } + llvm_unreachable("Unknown NestedNameSpecifier Kind"); + } + for (auto &&I : OldTemplateToArgs) { + auto &P = R.CurTemplateToArgs[I.first]; + if (P.empty()) + P = I.second; + } + } + }; + + struct NamingContextTransformRAII : NamingContextBase { + NamingContextTransformRAII(Resugarer &R, NestedNameSpecifierLoc &NNS) + : NamingContextBase(R) { + SmallVector Qs; + bool InheritOldMap = true; + for (/**/; NNS; NNS = NNS.getPrefix()) { + NestedNameSpecifier::SpecifierKind K = + NNS.getNestedNameSpecifier()->getKind(); + InheritOldMap &= K != NestedNameSpecifier::Global && + K != NestedNameSpecifier::Namespace && + K != NestedNameSpecifier::NamespaceAlias; + Qs.push_back(NNS); + } + if (InheritOldMap) + R.CurTemplateToArgs.copyFrom(OldTemplateToArgs); + + CXXScopeSpec SS; + for (const NestedNameSpecifierLoc &Q : llvm::reverse(Qs)) { + const auto *Qnns = Q.getNestedNameSpecifier(); + switch (Qnns->getKind()) { + case NestedNameSpecifier::Global: + SS.MakeGlobal(R.SemaRef.Context, Q.getBeginLoc()); + continue; + case NestedNameSpecifier::Namespace: + SS.Extend(R.SemaRef.Context, Qnns->getAsNamespace(), + Q.getLocalBeginLoc(), Q.getLocalEndLoc()); + continue; + case NestedNameSpecifier::NamespaceAlias: + SS.Extend(R.SemaRef.Context, Qnns->getAsNamespaceAlias(), + Q.getLocalBeginLoc(), Q.getLocalEndLoc()); + continue; + case NestedNameSpecifier::Identifier: + SS.Extend(R.SemaRef.Context, Qnns->getAsIdentifier(), + Q.getLocalBeginLoc(), Q.getLocalEndLoc()); + continue; + case NestedNameSpecifier::Super: + SS.MakeSuper(R.SemaRef.Context, Qnns->getAsRecordDecl(), + Q.getBeginLoc(), Q.getEndLoc()); + continue; + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: { + TypeLocBuilder TLB; + TypeLoc TL = Q.getTypeLoc(); + TLB.reserve(TL.getFullDataSize()); + QualType T = R.TransformType(TLB, TL); + addTypeToMap(/*Reverse=*/true, T.getTypePtr()); + SS.Extend(R.SemaRef.Context, /*FIXME:*/ SourceLocation(), + TLB.getTypeSourceInfo(R.SemaRef.Context, T)->getTypeLoc(), + Q.getLocalEndLoc()); + continue; + } + } + llvm_unreachable("Unknown NestedNameSpecifier Kind"); + } + if (SS.getScopeRep() == NNS.getNestedNameSpecifier()) + return; + if (llvm::equal( + ArrayRef(SS.location_data(), SS.location_size()), + ArrayRef((char *)NNS.getOpaqueData(), NNS.getDataLength()))) + NNS = NestedNameSpecifierLoc(SS.getScopeRep(), NNS.getOpaqueData()); + else + NNS = SS.getWithLocInContext(R.SemaRef.Context); + } + }; + + Resugarer(Sema &SemaRef) : inherited(SemaRef) {} + + bool AlwaysRebuild() { return false; } + bool ReplacingOriginal() { return false; } + + QualType TransformQualifiedType(TypeLocBuilder &TLB, QualifiedTypeLoc TL) { + QualType NewUnqual = TransformType(TLB, TL.getUnqualifiedLoc()); + QualType Result = TL.getType(); + if (NewUnqual != TL.getUnqualifiedLoc().getType()) + Result = SemaRef.Context.getQualifiedType( + NewUnqual, TL.getType().getLocalQualifiers()); + TLB.TypeWasModifiedSafely(Result); + return Result; + } + + QualType TransformAdjustedType(TypeLocBuilder &TLB, AdjustedTypeLoc TL) { + const AdjustedType *T = TL.getTypePtr(); + QualType NewOrig = TransformType(TLB, TL.getOriginalLoc()); + + QualType Result = TL.getType(); + if (NewOrig != T->getOriginalType()) + Result = SemaRef.Context.getAdjustedType(NewOrig, T->getAdjustedType()); + TLB.push(Result); + return Result; + } + + QualType TransformElaboratedType(TypeLocBuilder &TLB, ElaboratedTypeLoc TL) { + NestedNameSpecifierLoc QualifierLoc = TL.getQualifierLoc(); + NamingContextTransformRAII NamingScope(*this, QualifierLoc); + QualType NamedT = TransformType(TLB, TL.getNamedTypeLoc()); + + const ElaboratedType *T = TL.getTypePtr(); + QualType Result = TL.getType(); + if (QualifierLoc != TL.getQualifierLoc() || NamedT != T->getNamedType()) + Result = SemaRef.Context.getElaboratedType( + T->getKeyword(), QualifierLoc.getNestedNameSpecifier(), NamedT); + + auto 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) { + QualType QT = TL.getType(); + const SubstTemplateTypeParmType *T = TL.getTypePtr(); + Decl *ReplacedDecl = T->getReplacedDecl(); + + Optional PackIndex = T->getPackIndex(); + if (const TemplateArgument *Arg = + getArgument(ReplacedDecl, T->getIndex(), PackIndex)) { + QualType Replacement = Arg->getAsType().getNonPackExpansionType(); + if (!SemaRef.Context.hasSameType(Replacement, T->getReplacementType())) { + Replacement.dump(); + T->getReplacementType().dump(); + assert(false); + } + if (Replacement != T->getReplacementType()) + QT = SemaRef.Context.getSubstTemplateTypeParmType( + Replacement, ReplacedDecl, T->getIndex(), PackIndex); + } + auto NewTL = TLB.push(QT); + NewTL.setNameLoc(TL.getNameLoc()); + return QT; + } + + using inherited::TransformTemplateSpecializationType; + + QualType TransformTemplateSpecializationType(TypeLocBuilder &TLB, + TemplateSpecializationTypeLoc TL, + TemplateName N) { + const TemplateSpecializationType *T = TL.getTypePtr(); + + SmallVector SpecArgs(TL.getNumArgs()); + for (unsigned I = 0, E = TL.getNumArgs(); I < E; ++I) + SpecArgs[I] = TL.getArgLoc(I); + TransformTemplateArguments(SpecArgs); + + auto ConvertedArgs = SmallVector( + llvm::iterator_range( + T->getConvertedArguments())); + TransformTemplateArguments(ConvertedArgs); + + QualType Underlying = T->desugar(); + if (T->isTypeAlias()) { + SemanticContextRAII SemanticScope(*this, N.getAsTemplateDecl(), + ConvertedArgs); + Underlying = TransformType(Underlying); + } + + // FIXME: Rebuild only if changed. + QualType Result = SemaRef.Context.getTemplateSpecializationType( + N, SpecArgs, ConvertedArgs, /*CanonicalConvertedArgs=*/{}, Underlying); + + auto 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 = SpecArgs.size(); I < E; ++I) + NewTL.setArgLocInfo(I, SpecArgs[I].getLocInfo()); + return Result; + } + + QualType TransformDependentTemplateSpecializationType( + TypeLocBuilder &TLB, DependentTemplateSpecializationTypeLoc TL) { + const DependentTemplateSpecializationType *T = TL.getTypePtr(); + + SmallVector Args(TL.getNumArgs()); + for (unsigned I = 0, E = TL.getNumArgs(); I < E; ++I) + Args[I] = TL.getArgLoc(I); + + NestedNameSpecifierLoc NNS = TL.getQualifierLoc(); + NamingContextTransformRAII NamingScope(*this, NNS); + TransformTemplateArguments(Args); + // FIXME: Don't rebuild if nothing changed. + QualType Result = SemaRef.Context.getDependentTemplateSpecializationType( + T->getKeyword(), NNS.getNestedNameSpecifier(), T->getIdentifier(), + Args); + + auto NewTL = TLB.push(Result); + NewTL.setElaboratedKeywordLoc(TL.getElaboratedKeywordLoc()); + NewTL.setQualifierLoc(NNS); + NewTL.setTemplateKeywordLoc(TL.getTemplateKeywordLoc()); + NewTL.setTemplateNameLoc(TL.getTemplateNameLoc()); + NewTL.setLAngleLoc(TL.getLAngleLoc()); + NewTL.setRAngleLoc(TL.getRAngleLoc()); + for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) + NewTL.setArgLocInfo(I, Args[I].getLocInfo()); + return Result; + } + + TypeSourceInfo *TransformTSIInObjectScope(TypeLoc TL, QualType, NamedDecl *, + CXXScopeSpec &) = delete; + + QualType TransformDependentTemplateSpecializationType( + TypeLocBuilder &, DependentTemplateSpecializationTypeLoc, TemplateName, + CXXScopeSpec &) = delete; + + 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; // FIXME: resugar these + 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 = TL.getQualifierLoc(); + NamingContextTransformRAII NamingContext(*this, QualifierLoc); + assert(QualifierLoc); + assert(QualifierLoc.getNestedNameSpecifier()->isDependent()); + QualType Result = SemaRef.Context.getDependentNameType( + T->getKeyword(), QualifierLoc.getNestedNameSpecifier(), + T->getIdentifier()); + auto 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 OldUnderlying = T->desugar(); + NonTemplateSemanticContextRAII SemanticScope(*this); + QualType NewUnderlying = TransformType(OldUnderlying); + QualType Result = TL.getType(); + if (NewUnderlying != OldUnderlying) + Result = SemaRef.Context.getTypedefType(D, NewUnderlying); + auto NewTL = TLB.push(Result); + NewTL.setNameLoc(TL.getNameLoc()); + return Result; + } + + QualType TransformUsingType(TypeLocBuilder &TLB, UsingTypeLoc TL) { + const UsingType *T = TL.getTypePtr(); + const UsingShadowDecl *D = T->getFoundDecl(); + QualType OldUnderlying = T->desugar(); + NonTemplateSemanticContextRAII SemanticScope(*this); + QualType NewUnderlying = TransformType(OldUnderlying); + QualType Result = TL.getType(); + if (NewUnderlying != OldUnderlying) + Result = SemaRef.Context.getUsingType(D, NewUnderlying); + TLB.pushTypeSpec(Result).setNameLoc(TL.getNameLoc()); + return Result; + } + + ExprResult TransformExpr(Expr *E) { return E; } + + bool TransformTemplateArgument(const TemplateArgumentLoc &Input, + TemplateArgumentLoc &Output, bool) = delete; + + bool TransformTemplateArgument(TemplateArgument &Arg) { + switch (Arg.getKind()) { + case TemplateArgument::Null: + llvm_unreachable("Unexpected Null TemplateArgument"); + case TemplateArgument::Pack: { + ArrayRef PackArray = Arg.getPackAsArray(); + if (PackArray.empty()) + return false; + auto NewPack = PackArray.copy(SemaRef.Context); + Arg = TemplateArgument(NewPack); + return TransformTemplateArguments(NewPack); + } + case TemplateArgument::Integral: + case TemplateArgument::NullPtr: + case TemplateArgument::Declaration: { + QualType T = Arg.getNonTypeTemplateArgumentType(); + QualType NewT = TransformType(T); + if (NewT == T) + return false; + switch (Arg.getKind()) { + case TemplateArgument::Integral: + Arg = TemplateArgument(SemaRef.Context, Arg.getAsIntegral(), NewT); + return true; + case TemplateArgument::NullPtr: + Arg = TemplateArgument(NewT, /*IsNullPtr=*/true); + return true; + case TemplateArgument::Declaration: + Arg = TemplateArgument(Arg.getAsDecl(), NewT); + return true; + default: + break; + } + llvm_unreachable(""); + } + case TemplateArgument::Type: { + QualType T = TransformType(Arg.getAsType()); + if (T == Arg.getAsType()) + return false; + Arg = TemplateArgument(T); + return true; + } + case TemplateArgument::Template: + case TemplateArgument::TemplateExpansion: { + // FIXME: Transform these. + return false; + } + case TemplateArgument::Expression: + // FIXME: convert the type of these. + return false; + } + llvm_unreachable("Unexpected TemplateArgument kind"); + } + + bool TransformTemplateArgument(TemplateArgumentLoc &AL) { + const TemplateArgument &Arg = AL.getArgument(); + switch (Arg.getKind()) { + case TemplateArgument::Null: + llvm_unreachable("Unexpected Null TemplateArgument"); + case TemplateArgument::Pack: { + ArrayRef PackArray = Arg.getPackAsArray(); + SmallVector Pack(PackArray.size()); + for (unsigned I = 0; I < PackArray.size(); ++I) + Pack[I] = SemaRef.getTrivialTemplateArgumentLoc( + PackArray[I], QualType(), SourceLocation()); + bool Changed = TransformTemplateArguments(Pack); + SmallVector ROuts(Pack.size()); + for (unsigned I = 0; I < Pack.size(); ++I) + ROuts[I] = Pack[I].getArgument(); + AL = TemplateArgumentLoc( + TemplateArgument::CreatePackCopy(SemaRef.Context, ROuts), + AL.getLocInfo()); + return Changed; + } + case TemplateArgument::Integral: + case TemplateArgument::NullPtr: + case TemplateArgument::Declaration: { + QualType T = Arg.getNonTypeTemplateArgumentType(); + QualType NewT = TransformType(T); + if (NewT == T) + return false; + switch (Arg.getKind()) { + case TemplateArgument::Integral: + AL = TemplateArgumentLoc( + TemplateArgument(SemaRef.Context, Arg.getAsIntegral(), NewT), + AL.getLocInfo()); + return true; + case TemplateArgument::NullPtr: + AL = TemplateArgumentLoc(TemplateArgument(NewT, /*IsNullPtr=*/true), + AL.getLocInfo()); + return true; + default: + AL = TemplateArgumentLoc(TemplateArgument(Arg.getAsDecl(), NewT), + AL.getLocInfo()); + return true; + } + llvm_unreachable(""); + } + case TemplateArgument::Type: { + if (Arg.isPackExpansion()) { + QualType T = TransformType(Arg.getAsType()); + if (T == Arg.getAsType()) + return false; + AL = TemplateArgumentLoc(TemplateArgument(T), AL.getLocInfo()); + return true; + } + TypeSourceInfo *DI = AL.getTypeSourceInfo(); + if (!DI) + DI = InventTypeSourceInfo(Arg.getAsType()); + TypeSourceInfo *NewDI = TransformType(DI); + if (DI == NewDI) + return false; + AL = TemplateArgumentLoc(TemplateArgument(NewDI->getType()), NewDI); + return true; + } + case TemplateArgument::Template: { + NestedNameSpecifierLoc QualifierLoc = AL.getTemplateQualifierLoc(); + NamingContextTransformRAII NamingContext(*this, QualifierLoc); + + CXXScopeSpec SS; + SS.Adopt(QualifierLoc); + TemplateName Template = TransformTemplateName(SS, Arg.getAsTemplate(), + AL.getTemplateNameLoc()); + if (Template.getAsVoidPointer() == Arg.getAsTemplate().getAsVoidPointer()) + return false; + + AL = TemplateArgumentLoc(SemaRef.Context, TemplateArgument(Template), + QualifierLoc, AL.getTemplateNameLoc()); + return true; + } + case TemplateArgument::TemplateExpansion: { + AL = TemplateArgumentLoc( + TemplateArgument(Arg.getAsTemplateOrTemplatePattern(), + Arg.getNumTemplateExpansions()), + AL.getLocInfo()); + return false; + } + case TemplateArgument::Expression: + // FIXME: convert the type of these. + return false; + } + llvm_unreachable("Unexpected TemplateArgument kind"); + } + + template + bool TransformTemplateArguments(InputIterator First, InputIterator Last, + TemplateArgumentListInfo &Outputs, + bool Uneval = true) = delete; + + bool TransformTemplateArguments(MutableArrayRef Args) { + bool Changed = false; + for (auto &Arg : Args) + Changed |= TransformTemplateArgument(Arg); + return Changed; + } + bool TransformTemplateArguments(MutableArrayRef Args) { + bool Changed = false; + for (auto &Arg : Args) + Changed |= TransformTemplateArgument(Arg); + return Changed; + } + + 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); + } + + auto 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(); + + SmallVector ExceptionStorage( + EPI.ExceptionSpec.Exceptions.size()); + Changed |= TransformTypes(EPI.ExceptionSpec.Exceptions, ExceptionStorage); + EPI.ExceptionSpec.Exceptions = ExceptionStorage; + + QualType Result = + Changed ? SemaRef.Context.getFunctionType(ResultType, ParamTypes, EPI) + : TL.getType(); + + auto 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()); + } + + auto newTL = TLB.push(Result); + newTL.setAttr(NewAttr); + return Result; + } + + QualType TransformAutoType(TypeLocBuilder &TLB, AutoTypeLoc TL) { + NestedNameSpecifierLoc NNS; + const AutoType *T = TL.getTypePtr(); + + SmallVector Args(TL.getNumArgs()); + for (unsigned I = 0, E = TL.getNumArgs(); I < E; ++I) + Args[I] = TL.getArgLoc(I); + bool ChangedArgs = TransformTemplateArguments(Args); + + QualType Deduced = !T->getDeducedType().isNull() + ? TransformType(T->getDeducedType()) + : QualType(); + + QualType Result = TL.getType(); + if (Deduced != T->getDeducedType() || ChangedArgs) { + NNS = TL.getNestedNameSpecifierLoc(); + NamingContextTransformRAII NamingContext(*this, NNS); + // FIXME: Maybe don't rebuild if all template arguments are the same. + llvm::SmallVector TypeConstraintArgs(Args.size()); + for (unsigned I = 0; I < Args.size(); ++I) + TypeConstraintArgs[I] = Args[I].getArgument(); + Result = SemaRef.Context.getAutoType( + Deduced, T->getKeyword(), Deduced.isNull(), + T->containsUnexpandedParameterPack(), T->getTypeConstraintConcept(), + TypeConstraintArgs); + } + + auto NewTL = TLB.push(Result); + NewTL.setNameLoc(TL.getNameLoc()); + NewTL.setNestedNameSpecifierLoc(NNS); + NewTL.setTemplateKWLoc(TL.getTemplateKWLoc()); + NewTL.setConceptNameLoc(TL.getConceptNameLoc()); + NewTL.setFoundDecl(TL.getFoundDecl()); + NewTL.setLAngleLoc(TL.getLAngleLoc()); + NewTL.setRAngleLoc(TL.getRAngleLoc()); + NewTL.setRParenLoc(TL.getRParenLoc()); + for (unsigned I = 0; I < NewTL.getNumArgs(); ++I) + NewTL.setArgLocInfo(I, Args[I].getLocInfo()); + return Result; + } + + QualType TransformConstantArrayType(TypeLocBuilder &TLB, + ConstantArrayTypeLoc TL) { + const ConstantArrayType *T = TL.getTypePtr(); + QualType ElementType = TransformType(TLB, TL.getElementLoc()); + assert(!ElementType.isNull()); + + // Prefer the expression from the TypeLoc; the other may have been uniqued. + Expr *OldSize = TL.getSizeExpr(); + if (!OldSize) + OldSize = const_cast(T->getSizeExpr()); + Expr *NewSize = nullptr; + if (OldSize) { + NewSize = TransformExpr(OldSize).template getAs(); + } + + QualType Result = TL.getType(); + if (ElementType != T->getElementType() || + (T->getSizeExpr() && NewSize != OldSize)) { + Result = SemaRef.Context.getConstantArrayType( + ElementType, T->getSize(), NewSize, T->getSizeModifier(), + T->getIndexTypeCVRQualifiers()); + } + + auto NewTL = TLB.push(Result); + NewTL.setLBracketLoc(TL.getLBracketLoc()); + NewTL.setRBracketLoc(TL.getRBracketLoc()); + NewTL.setSizeExpr(NewSize); + return Result; + } + + QualType TransformIncompleteArrayType(TypeLocBuilder &TLB, + IncompleteArrayTypeLoc TL) { + const IncompleteArrayType *T = TL.getTypePtr(); + QualType ElementType = TransformType(TLB, TL.getElementLoc()); + assert(!ElementType.isNull()); + + QualType Result = TL.getType(); + if (ElementType != T->getElementType()) { + Result = SemaRef.Context.getIncompleteArrayType( + ElementType, T->getSizeModifier(), T->getIndexTypeCVRQualifiers()); + } + + auto NewTL = TLB.push(Result); + NewTL.setLBracketLoc(TL.getLBracketLoc()); + NewTL.setRBracketLoc(TL.getRBracketLoc()); + NewTL.setSizeExpr(nullptr); + return Result; + } + + QualType TransformVariableArrayType(TypeLocBuilder &TLB, + VariableArrayTypeLoc TL) { + const VariableArrayType *T = TL.getTypePtr(); + QualType ElementType = TransformType(TLB, TL.getElementLoc()); + assert(!ElementType.isNull()); + + Expr *NewSize = TransformExpr(T->getSizeExpr()).template getAs(); + + QualType Result = TL.getType(); + if (ElementType != T->getElementType() || NewSize != T->getSizeExpr()) { + Result = SemaRef.Context.getVariableArrayType( + ElementType, NewSize, T->getSizeModifier(), + T->getIndexTypeCVRQualifiers(), TL.getBracketsRange()); + } + + auto NewTL = TLB.push(Result); + NewTL.setLBracketLoc(TL.getLBracketLoc()); + NewTL.setRBracketLoc(TL.getRBracketLoc()); + NewTL.setSizeExpr(NewSize); + return Result; + } + + QualType TransformDependentSizedArrayType(TypeLocBuilder &TLB, + DependentSizedArrayTypeLoc TL) { + const DependentSizedArrayType *T = TL.getTypePtr(); + QualType ElementType = TransformType(TLB, TL.getElementLoc()); + assert(!ElementType.isNull()); + + // Prefer the expression from the TypeLoc; the other may have been uniqued. + Expr *OldSize = TL.getSizeExpr(); + if (!OldSize) + OldSize = const_cast(T->getSizeExpr()); + Expr *NewSize = nullptr; + if (OldSize) { + NewSize = TransformExpr(OldSize).template getAs(); + } + + QualType Result = TL.getType(); + if (ElementType != T->getElementType() || NewSize != OldSize) { + Result = SemaRef.Context.getDependentSizedArrayType( + ElementType, NewSize, T->getSizeModifier(), + T->getIndexTypeCVRQualifiers(), TL.getBracketsRange()); + } + + auto NewTL = TLB.push(Result); + NewTL.setLBracketLoc(TL.getLBracketLoc()); + NewTL.setRBracketLoc(TL.getRBracketLoc()); + NewTL.setSizeExpr(NewSize); + return Result; + } + + QualType TransformBTFTagAttributedType(TypeLocBuilder &TLB, + BTFTagAttributedTypeLoc TL) { + // The BTFTagAttributedType is available for C only. + const BTFTagAttributedType *T = TL.getTypePtr(); + + QualType NewWrappedType = TransformType(TLB, TL.getWrappedLoc()); + assert(!NewWrappedType.isNull()); + + const Attr *NewAttr = TransformAttr(T->getAttr()); + + QualType Result = TL.getType(); + if (NewWrappedType != T->getWrappedType() || NewAttr != T->getAttr()) { + Result = + SemaRef.Context.getBTFTagAttributedType(T->getAttr(), NewWrappedType); + } + TLB.push(Result); + return Result; + } + + QualType TransformDependentAddressSpaceType(TypeLocBuilder &TLB, + DependentAddressSpaceTypeLoc TL) { + const DependentAddressSpaceType *T = TL.getTypePtr(); + + QualType pointeeType = TransformType(TLB, TL.getPointeeTypeLoc()); + assert(!pointeeType.isNull()); + + Expr *AddrSpace = + TransformExpr(T->getAddrSpaceExpr()).template getAs(); + + QualType Result = TL.getType(); + if (pointeeType != T->getPointeeType() || + AddrSpace != T->getAddrSpaceExpr()) { + Result = SemaRef.Context.getDependentAddressSpaceType( + pointeeType, AddrSpace, T->getAttributeLoc()); + } + + auto NewTL = TLB.push(Result); + NewTL.setAttrOperandParensRange(TL.getAttrOperandParensRange()); + NewTL.setAttrExprOperand(AddrSpace); + NewTL.setAttrNameLoc(TL.getAttrNameLoc()); + return Result; + } + + QualType TransformDeducedTemplateSpecializationType( + TypeLocBuilder &TLB, DeducedTemplateSpecializationTypeLoc TL) { + const DeducedTemplateSpecializationType *T = TL.getTypePtr(); + + CXXScopeSpec SS; + TemplateName Template = TransformTemplateName(SS, T->getTemplateName(), + TL.getTemplateNameLoc()); + assert(!Template.isNull()); + + QualType NewDeduced; + if (!T->getDeducedType().isNull()) { + NewDeduced = TransformType(T->getDeducedType()); + assert(!NewDeduced.isNull()); + } + + QualType Result = TL.getType(); + if (Template.getAsVoidPointer() != + T->getTemplateName().getAsVoidPointer() || + NewDeduced != T->getDeducedType()) + Result = SemaRef.Context.getDeducedTemplateSpecializationType( + Template, NewDeduced, T->isDependentType()); + + auto NewTL = TLB.push(Result); + NewTL.setTemplateNameLoc(TL.getTemplateNameLoc()); + return Result; + } + + QualType TransformTypeOfExprType(TypeLocBuilder &TLB, TypeOfExprTypeLoc TL) { + ExprResult E = TransformExpr(TL.getUnderlyingExpr()); + // FIXME: resugar + QualType Result = TL.getType(); + if (E.get() != TL.getUnderlyingExpr()) { + Result = SemaRef.BuildTypeofExprType(E.get()); + } + TypeOfExprTypeLoc NewTL = TLB.push(Result); + NewTL.setTypeofLoc(TL.getTypeofLoc()); + NewTL.setLParenLoc(TL.getLParenLoc()); + NewTL.setRParenLoc(TL.getRParenLoc()); + return Result; + } + + QualType TransformTypeOfType(TypeLocBuilder &TLB, TypeOfTypeLoc TL) { + TypeSourceInfo *Old = TL.getUnderlyingTInfo(); + TypeSourceInfo *New = TransformType(Old); + + QualType Result = TL.getType(); + if (New != Old) + Result = SemaRef.Context.getTypeOfType(New->getType()); + + TypeOfTypeLoc NewTL = TLB.push(Result); + NewTL.setTypeofLoc(TL.getTypeofLoc()); + NewTL.setLParenLoc(TL.getLParenLoc()); + NewTL.setRParenLoc(TL.getRParenLoc()); + NewTL.setUnderlyingTInfo(New); + return Result; + } + + QualType TransformDecltypeType(TypeLocBuilder &TLB, DecltypeTypeLoc TL) { + const DecltypeType *T = TL.getTypePtr(); + QualType NewT = TransformType(T->getUnderlyingType()); + QualType Result = TL.getType(); + if (NewT != T->getUnderlyingType()) + Result = SemaRef.Context.getDecltypeType(T->getUnderlyingExpr(), NewT); + + DecltypeTypeLoc NewTL = TLB.push(Result); + NewTL.setDecltypeLoc(TL.getDecltypeLoc()); + NewTL.setRParenLoc(TL.getRParenLoc()); + return Result; + } + + QualType TransformUnaryTransformType(TypeLocBuilder &TLB, + UnaryTransformTypeLoc TL) { + QualType Result = TL.getType(); + if (Result->isDependentType()) { + TypeSourceInfo *NewBase = TransformType(TL.getUnderlyingTInfo()); + if (NewBase->getType() != TL.getUnderlyingTInfo()->getType()) + Result = SemaRef.BuildUnaryTransformType( + NewBase->getType(), TL.getTypePtr()->getUTTKind(), TL.getKWLoc()); + } + UnaryTransformTypeLoc NewTL = TLB.push(Result); + NewTL.setKWLoc(TL.getKWLoc()); + NewTL.setParensRange(TL.getParensRange()); + NewTL.setUnderlyingTInfo(TL.getUnderlyingTInfo()); + return Result; + } + // FIXME: missing resugar of enums. +}; +} // namespace + +QualType Sema::resugar(const CXXScopeSpec &SS, QualType T) { + if (!getLangOpts().Resugar) + return T; + Resugarer R(*this); + Resugarer::NamingContextRAII NamingScope(R, SS.getScopeRep()); + return R.TransformType(T); +} + +QualType Sema::resugar(const CXXScopeSpec &SS, NamedDecl *ND, + ArrayRef Args, QualType T) { + assert(ND != nullptr); + if (!getLangOpts().Resugar) + return T; + Resugarer R(*this); + Resugarer::NamingContextRAII NamingScope(R, SS.getScopeRep()); + Resugarer::SemanticContextRAII SemanticScope(R, ND, Args); + return R.TransformType(T); +} +QualType Sema::resugar(const CXXScopeSpec &SS, NamedDecl *ND, + ArrayRef Args, QualType T) { + assert(ND != nullptr); + if (!getLangOpts().Resugar) + return T; + Resugarer R(*this); + Resugarer::NamingContextRAII NamingScope(R, SS.getScopeRep()); + Resugarer::SemanticContextRAII SemanticScope(R, ND, Args); + return R.TransformType(T); +} + +static const NestedNameSpecifier *decomposeBaseType(const Type *&Base) { + if (const auto *ElTy = Base->getAs()) { + Base = ElTy->getNamedType().getTypePtr(); + return ElTy->getQualifier(); + } + return nullptr; +} + +QualType Sema::resugar(const Type *Base, QualType T) { + if (!getLangOpts().Resugar) + return T; + Resugarer R(*this); + const NestedNameSpecifier *BaseNNS = decomposeBaseType(Base); + Resugarer::NamingContextRAII BaseScope(R, BaseNNS, Base); + return R.TransformType(T); +} + +QualType Sema::resugar(const Type *Base, NamedDecl *ND, + ArrayRef Args, QualType T) { + if (!getLangOpts().Resugar) + return T; + Resugarer R(*this); + const NestedNameSpecifier *BaseNNS = decomposeBaseType(Base); + Resugarer::NamingContextRAII BaseScope(R, BaseNNS, Base); + Resugarer::SemanticContextRAII SemanticScope(R, ND, Args); + return R.TransformType(T); +} +QualType Sema::resugar(const Type *Base, NamedDecl *ND, + ArrayRef Args, QualType T) { + if (!getLangOpts().Resugar) + return T; + Resugarer R(*this); + const NestedNameSpecifier *BaseNNS = decomposeBaseType(Base); + Resugarer::NamingContextRAII BaseScope(R, BaseNNS, Base); + Resugarer::SemanticContextRAII SemanticScope(R, ND, Args); + return R.TransformType(T); +} + +QualType Sema::resugar(const Type *Base, NestedNameSpecifierLoc &FieldNNS, + QualType T) { + if (!getLangOpts().Resugar) + return T; + Resugarer R(*this); + const NestedNameSpecifier *BaseNNS = decomposeBaseType(Base); + Resugarer::NamingContextRAII BaseScope(R, BaseNNS, Base); + Resugarer::NamingContextTransformRAII FieldScope(R, FieldNNS); + return R.TransformType(T); +} + +QualType Sema::resugar(const Type *Base, NestedNameSpecifierLoc &FieldNNS, + NamedDecl *ND, ArrayRef Args, + QualType T) { + if (!getLangOpts().Resugar) + return T; + Resugarer R(*this); + const NestedNameSpecifier *BaseNNS = decomposeBaseType(Base); + Resugarer::NamingContextRAII BaseScope(R, BaseNNS, Base); + Resugarer::NamingContextTransformRAII FieldScope(R, FieldNNS); + Resugarer::SemanticContextRAII SemanticScope(R, ND, Args); + return R.TransformType(T); +} +QualType Sema::resugar(const Type *Base, NestedNameSpecifierLoc &FieldNNS, + NamedDecl *ND, ArrayRef Args, + QualType T) { + if (!getLangOpts().Resugar) + return T; + Resugarer R(*this); + const NestedNameSpecifier *BaseNNS = decomposeBaseType(Base); + Resugarer::NamingContextRAII BaseScope(R, BaseNNS, Base); + Resugarer::NamingContextTransformRAII FieldScope(R, FieldNNS); + Resugarer::SemanticContextRAII SemanticScope(R, ND, Args); + return R.TransformType(T); +} + +static QualType getResugaredTemplateSpecializationType( + Sema &S, const CXXScopeSpec &SS, TemplateName Template, + MutableArrayRef SpecArgs, + MutableArrayRef SugaredConvertedArgs, + ArrayRef CanonicalConvertedArgs, + QualType Underlying = QualType()) { + if (!S.getLangOpts().Resugar) + return S.Context.getTemplateSpecializationType( + Template, SpecArgs, SugaredConvertedArgs, CanonicalConvertedArgs, + Underlying); + + auto *TD = Template.getAsTemplateDecl(); + bool IsTypeAlias = !Underlying.isNull() && TD && TD->isTypeAlias(); + + Resugarer R(S); + Resugarer::NamingContextRAII NamingScope(R, SS.getScopeRep()); + R.TransformTemplateArguments(SpecArgs); + R.TransformTemplateArguments(SugaredConvertedArgs); + if (IsTypeAlias) { + Resugarer::SemanticContextRAII SemanticScope(R, TD, SugaredConvertedArgs); + Underlying = R.TransformType(Underlying); + } + return S.Context.getTemplateSpecializationType( + Template, SpecArgs, SugaredConvertedArgs, CanonicalConvertedArgs, + 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. @@ -1591,9 +2858,10 @@ if (DiagnoseUnexpandedParameterPack(Default, UPPC_DefaultArgument)) return Param; - TemplateArgument Converted; - ExprResult DefaultRes = - CheckTemplateArgument(Param, Param->getType(), Default, Converted); + TemplateArgument SugaredConverted, CanonicalConverted; + ExprResult DefaultRes = CheckTemplateArgument( + Param, Param->getType(), Default, SugaredConverted, CanonicalConverted, + CTAK_Specified); if (DefaultRes.isInvalid()) { Param->setInvalidDecl(); return Param; @@ -3494,11 +4762,10 @@ } } -static QualType -checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD, - const SmallVectorImpl &Converted, - SourceLocation TemplateLoc, - TemplateArgumentListInfo &TemplateArgs) { +static QualType checkBuiltinTemplateIdType( + Sema &SemaRef, const CXXScopeSpec &SS, TemplateName Name, + BuiltinTemplateDecl *BTD, MutableArrayRef Converted, + SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs) { ASTContext &Context = SemaRef.getASTContext(); switch (BTD->getBuiltinTemplateKind()) { case BTK__make_integer_seq: { @@ -3527,7 +4794,13 @@ TemplateArgumentListInfo SyntheticTemplateArgs; // The type argument gets reused as the first template argument in the // synthetic template argument list. - SyntheticTemplateArgs.addArgument(TemplateArgs[1]); + QualType OrigType = TemplateArgs[1].getArgument().getAsType(); + QualType SyntheticType = + SemaRef.Context.getSubstTemplateTypeParmType(OrigType, BTD, 1, None); + 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) { @@ -3537,8 +4810,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); + QualType Result = SemaRef.CheckTemplateIdType( + SS, Converted[0].getAsTemplate(), TemplateLoc, SyntheticTemplateArgs); + return SemaRef.Context.getTemplateSpecializationType( + Name, TemplateArgs.arguments(), Converted, + /*CanonicalConverted=*/{}, Result); } case BTK__type_pack_element: @@ -3560,8 +4836,11 @@ } // 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, SS, Name, TemplateArgs.arguments(), Converted, + /*CanonicalConverted=*/{}, Nth->getAsType()); } llvm_unreachable("unexpected BuiltinTemplateDecl!"); } @@ -3705,7 +4984,8 @@ return { FailedCond, Description }; } -QualType Sema::CheckTemplateIdType(TemplateName Name, +// FIXME: We should get the context we are in from the TemplateDeclInstantiator. +QualType Sema::CheckTemplateIdType(const CXXScopeSpec &SS, TemplateName Name, SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs) { DependentTemplateName *DTN @@ -3715,53 +4995,57 @@ // assume the template is a type template. Either our assumption is // correct, or the code is ill-formed and will be diagnosed when the // dependent name is substituted. - return Context.getDependentTemplateSpecializationType(ETK_None, - DTN->getQualifier(), - DTN->getIdentifier(), - TemplateArgs); + return Context.getDependentTemplateSpecializationType( + ETK_None, DTN->getQualifier(), DTN->getIdentifier(), + TemplateArgs.arguments()); if (Name.getAsAssumedTemplateName() && resolveAssumedTemplateNameAsType(/*Scope*/nullptr, Name, TemplateLoc)) return QualType(); - TemplateDecl *Template = Name.getAsTemplateDecl(); - if (!Template || isa(Template) || - isa(Template) || isa(Template)) { - // 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); - - Diag(TemplateLoc, diag::err_template_id_not_a_type) - << Name; - NoteAllFoundTemplates(Name); - return QualType(); + TemplateDecl *Template; + if (const SubstTemplateTemplateParmPackStorage *S = + Name.getAsSubstTemplateTemplateParmPack()) { + Template = S->getParameterPack(); + } else { + Template = Name.getAsTemplateDecl(); + if (!Template || isa(Template) || + isa(Template) || isa(Template)) { + Diag(TemplateLoc, diag::err_template_id_not_a_type) << Name; + NoteAllFoundTemplates(Name); + return QualType(); + } } // Check that the template argument list is well-formed for this // template. - SmallVector Converted; - if (CheckTemplateArgumentList(Template, TemplateLoc, TemplateArgs, - false, Converted, + SmallVector SugaredConverted, CanonicalConverted; + if (CheckTemplateArgumentList(Template, TemplateLoc, TemplateArgs, false, + SugaredConverted, CanonicalConverted, /*UpdateArgsWithConversions=*/true)) return QualType(); QualType CanonType; - if (TypeAliasTemplateDecl *AliasTemplate = - dyn_cast(Template)) { + if (isa(Template)) { + // We might have a substituted template template parameter pack. If so, + // build a template specialization type for it. + } else if (TypeAliasTemplateDecl *AliasTemplate = + dyn_cast(Template)) { // Find the canonical type for this type alias template specialization. TypeAliasDecl *Pattern = AliasTemplate->getTemplatedDecl(); if (Pattern->isInvalidDecl()) return QualType(); + // FIXME: Just use SugaredConverted instead. TemplateArgumentList StackTemplateArgs(TemplateArgumentList::OnStack, - Converted); + CanonicalConverted); // Only substitute for the innermost template argument list. MultiLevelTemplateArgumentList TemplateArgLists; - TemplateArgLists.addOuterTemplateArguments(&StackTemplateArgs); + TemplateArgLists.addOuterTemplateArguments(Template, + StackTemplateArgs.asArray()); TemplateArgLists.addOuterRetainedLevels( AliasTemplate->getTemplateParameters()->getDepth()); @@ -3810,7 +5094,7 @@ } } else if (Name.isDependent() || TemplateSpecializationType::anyDependentTemplateArguments( - TemplateArgs, Converted)) { + TemplateArgs, CanonicalConverted)) { // This class template specialization is a dependent // type. Therefore, its canonical type is another class template // specialization type that contains all of the converted @@ -3818,7 +5102,8 @@ // A have identical types when A is declared as: // // template struct A; - CanonType = Context.getCanonicalTemplateSpecializationType(Name, Converted); + CanonType = Context.getCanonicalTemplateSpecializationType( + Name, CanonicalConverted); // This might work out to be a current instantiation, in which // case the canonical type needs to be the InjectedClassNameType. @@ -3857,13 +5142,13 @@ break; } } - } else if (ClassTemplateDecl *ClassTemplate - = dyn_cast(Template)) { + } else if (ClassTemplateDecl *ClassTemplate = + dyn_cast(Template)) { // Find the class template specialization declaration that // corresponds to these arguments. void *InsertPos = nullptr; - ClassTemplateSpecializationDecl *Decl - = ClassTemplate->findSpecialization(Converted, InsertPos); + ClassTemplateSpecializationDecl *Decl = + ClassTemplate->findSpecialization(CanonicalConverted, InsertPos); if (!Decl) { // This is the first time we have referenced this class template // specialization. Create the canonical declaration and add it to @@ -3872,7 +5157,8 @@ Context, ClassTemplate->getTemplatedDecl()->getTagKind(), ClassTemplate->getDeclContext(), ClassTemplate->getTemplatedDecl()->getBeginLoc(), - ClassTemplate->getLocation(), ClassTemplate, Converted, nullptr); + ClassTemplate->getLocation(), ClassTemplate, CanonicalConverted, + nullptr); ClassTemplate->AddSpecialization(Decl, InsertPos); if (ClassTemplate->isOutOfLine()) Decl->setLexicalDeclContext(ClassTemplate->getLexicalDeclContext()); @@ -3883,7 +5169,8 @@ InstantiatingTemplate Inst(*this, TemplateLoc, Decl); if (!Inst.isInvalid()) { MultiLevelTemplateArgumentList TemplateArgLists; - TemplateArgLists.addOuterTemplateArguments(Converted); + TemplateArgLists.addOuterTemplateArguments(Template, + CanonicalConverted); InstantiateAttrsForDecl(TemplateArgLists, ClassTemplate->getTemplatedDecl(), Decl); } @@ -3896,14 +5183,16 @@ 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, SS, Name, BTD, SugaredConverted, + 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, SS, Name, TemplateArgs.arguments(), SugaredConverted, + CanonicalConverted, CanonType); } void Sema::ActOnUndeclaredTypeTemplateName(Scope *S, TemplateTy &ParsedName, @@ -4014,11 +5303,10 @@ translateTemplateArguments(TemplateArgsIn, TemplateArgs); if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) { - QualType T - = Context.getDependentTemplateSpecializationType(ETK_None, - DTN->getQualifier(), - DTN->getIdentifier(), - TemplateArgs); + assert(SS.getScopeRep() == DTN->getQualifier()); + QualType T = Context.getDependentTemplateSpecializationType( + ETK_None, DTN->getQualifier(), DTN->getIdentifier(), + TemplateArgs.arguments()); // Build type-source information. TypeLocBuilder TLB; DependentTemplateSpecializationTypeLoc SpecTL @@ -4034,7 +5322,8 @@ return CreateParsedType(T, TLB.getTypeSourceInfo(Context, T)); } - QualType SpecTy = CheckTemplateIdType(Template, TemplateIILoc, TemplateArgs); + QualType SpecTy = + CheckTemplateIdType(SS, Template, TemplateIILoc, TemplateArgs); if (SpecTy.isNull()) return true; @@ -4084,10 +5373,10 @@ = TypeWithKeyword::getKeywordForTagTypeKind(TagKind); if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) { - QualType T = Context.getDependentTemplateSpecializationType(Keyword, - DTN->getQualifier(), - DTN->getIdentifier(), - TemplateArgs); + assert(SS.getScopeRep() == DTN->getQualifier()); + QualType T = Context.getDependentTemplateSpecializationType( + Keyword, DTN->getQualifier(), DTN->getIdentifier(), + TemplateArgs.arguments()); // Build type-source information. TypeLocBuilder TLB; @@ -4115,30 +5404,14 @@ Diag(TAT->getLocation(), diag::note_declared_at); } - QualType Result = CheckTemplateIdType(Template, TemplateLoc, TemplateArgs); - if (Result.isNull()) + QualType T = CheckTemplateIdType(SS, 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); @@ -4148,11 +5421,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, @@ -4382,9 +5673,9 @@ // Check that the template argument list is well-formed for this // template. - SmallVector Converted; + SmallVector SugaredConverted, CanonicalConverted; if (CheckTemplateArgumentList(VarTemplate, TemplateNameLoc, TemplateArgs, - false, Converted, + false, SugaredConverted, CanonicalConverted, /*UpdateArgsWithConversions=*/true)) return true; @@ -4392,21 +5683,22 @@ // corresponds to these arguments. if (IsPartialSpecialization) { if (CheckTemplatePartialSpecializationArgs(TemplateNameLoc, VarTemplate, - TemplateArgs.size(), Converted)) + TemplateArgs.size(), + CanonicalConverted)) return true; // FIXME: Move these checks to CheckTemplatePartialSpecializationArgs so we // also do them during instantiation. if (!Name.isDependent() && - !TemplateSpecializationType::anyDependentTemplateArguments(TemplateArgs, - Converted)) { + !TemplateSpecializationType::anyDependentTemplateArguments( + TemplateArgs, CanonicalConverted)) { Diag(TemplateNameLoc, diag::err_partial_spec_fully_specialized) << VarTemplate->getDeclName(); IsPartialSpecialization = false; } if (isSameAsPrimaryTemplate(VarTemplate->getTemplateParameters(), - Converted) && + CanonicalConverted) && (!Context.getLangOpts().CPlusPlus20 || !TemplateParams->hasAssociatedConstraints())) { // C++ [temp.class.spec]p9b3: @@ -4427,10 +5719,10 @@ VarTemplateSpecializationDecl *PrevDecl = nullptr; if (IsPartialSpecialization) - PrevDecl = VarTemplate->findPartialSpecialization(Converted, TemplateParams, - InsertPos); + PrevDecl = VarTemplate->findPartialSpecialization( + CanonicalConverted, TemplateParams, InsertPos); else - PrevDecl = VarTemplate->findSpecialization(Converted, InsertPos); + PrevDecl = VarTemplate->findSpecialization(CanonicalConverted, InsertPos); VarTemplateSpecializationDecl *Specialization = nullptr; @@ -4457,7 +5749,7 @@ VarTemplatePartialSpecializationDecl::Create( Context, VarTemplate->getDeclContext(), TemplateKWLoc, TemplateNameLoc, TemplateParams, VarTemplate, DI->getType(), DI, SC, - Converted, TemplateArgs); + CanonicalConverted, TemplateArgs); if (!PrevPartial) VarTemplate->AddPartialSpecialization(Partial, InsertPos); @@ -4474,7 +5766,7 @@ // this explicit specialization or friend declaration. Specialization = VarTemplateSpecializationDecl::Create( Context, VarTemplate->getDeclContext(), TemplateKWLoc, TemplateNameLoc, - VarTemplate, DI->getType(), DI, SC, Converted); + VarTemplate, DI->getType(), DI, SC, CanonicalConverted); Specialization->setTemplateArgsInfo(TemplateArgs); if (!PrevDecl) @@ -4552,24 +5844,25 @@ assert(Template && "A variable template id without template?"); // Check that the template argument list is well-formed for this template. - SmallVector Converted; + SmallVector SugaredConverted, CanonicalConverted; if (CheckTemplateArgumentList( Template, TemplateNameLoc, const_cast(TemplateArgs), false, - Converted, /*UpdateArgsWithConversions=*/true)) + SugaredConverted, CanonicalConverted, + /*UpdateArgsWithConversions=*/true)) return true; // Produce a placeholder value if the specialization is dependent. if (Template->getDeclContext()->isDependentContext() || - TemplateSpecializationType::anyDependentTemplateArguments(TemplateArgs, - Converted)) + TemplateSpecializationType::anyDependentTemplateArguments( + TemplateArgs, CanonicalConverted)) return DeclResult(); // Find the variable template specialization declaration that // corresponds to these arguments. void *InsertPos = nullptr; - if (VarTemplateSpecializationDecl *Spec = Template->findSpecialization( - Converted, InsertPos)) { + if (VarTemplateSpecializationDecl *Spec = + Template->findSpecialization(CanonicalConverted, InsertPos)) { checkSpecializationReachability(TemplateNameLoc, Spec); // If we already have a variable template specialization, return it. return Spec; @@ -4581,7 +5874,7 @@ // that it represents. That is, VarDecl *InstantiationPattern = Template->getTemplatedDecl(); TemplateArgumentList TemplateArgList(TemplateArgumentList::OnStack, - Converted); + CanonicalConverted); TemplateArgumentList *InstantiationArgs = &TemplateArgList; bool AmbiguousPartialSpec = false; typedef PartialSpecMatchResult MatchResult; @@ -4613,7 +5906,7 @@ } else { Matched.push_back(PartialSpecMatchResult()); Matched.back().Partial = Partial; - Matched.back().Args = Info.take(); + Matched.back().Args = Info.takeCanonical(); } } @@ -4669,7 +5962,7 @@ // FIXME: LateAttrs et al.? VarTemplateSpecializationDecl *Decl = BuildVarTemplateInstantiation( Template, InstantiationPattern, *InstantiationArgs, TemplateArgs, - Converted, TemplateNameLoc /*, LateAttrs, StartingScope*/); + CanonicalConverted, TemplateNameLoc /*, LateAttrs, StartingScope*/); if (!Decl) return true; @@ -4740,30 +6033,33 @@ const TemplateArgumentListInfo *TemplateArgs) { assert(NamedConcept && "A concept template id without a template?"); - llvm::SmallVector Converted; - if (CheckTemplateArgumentList(NamedConcept, ConceptNameInfo.getLoc(), - const_cast(*TemplateArgs), - /*PartialTemplateArgs=*/false, Converted, - /*UpdateArgsWithConversions=*/false)) + llvm::SmallVector SugaredConverted, CanonicalConverted; + if (CheckTemplateArgumentList( + NamedConcept, ConceptNameInfo.getLoc(), + const_cast(*TemplateArgs), + /*PartialTemplateArgs=*/false, SugaredConverted, CanonicalConverted, + /*UpdateArgsWithConversions=*/false)) return ExprError(); ConstraintSatisfaction Satisfaction; bool AreArgsDependent = - TemplateSpecializationType::anyDependentTemplateArguments(*TemplateArgs, - Converted); + TemplateSpecializationType::anyDependentTemplateArguments( + *TemplateArgs, CanonicalConverted); + // FIXME: use SugaredConverted. if (!AreArgsDependent && CheckConstraintSatisfaction( - NamedConcept, {NamedConcept->getConstraintExpr()}, Converted, + NamedConcept, {NamedConcept->getConstraintExpr()}, CanonicalConverted, SourceRange(SS.isSet() ? SS.getBeginLoc() : ConceptNameInfo.getLoc(), TemplateArgs->getRAngleLoc()), Satisfaction)) return ExprError(); - return ConceptSpecializationExpr::Create(Context, + return ConceptSpecializationExpr::Create( + Context, SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc{}, TemplateKWLoc, ConceptNameInfo, FoundDecl, NamedConcept, - ASTTemplateArgumentListInfo::Create(Context, *TemplateArgs), Converted, - AreArgsDependent ? nullptr : &Satisfaction); + ASTTemplateArgumentListInfo::Create(Context, *TemplateArgs), + CanonicalConverted, AreArgsDependent ? nullptr : &Satisfaction); } ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS, @@ -5004,9 +6300,10 @@ return TNK_Non_template; } -bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, - TemplateArgumentLoc &AL, - SmallVectorImpl &Converted) { +bool Sema::CheckTemplateTypeArgument( + TemplateTypeParmDecl *Param, TemplateArgumentLoc &AL, + SmallVectorImpl &SugaredConverted, + SmallVectorImpl &CanonicalConverted) { const TemplateArgument &Arg = AL.getArgument(); QualType ArgType; TypeSourceInfo *TSI = nullptr; @@ -5099,9 +6396,6 @@ if (CheckTemplateArgument(TSI)) return true; - // Add the converted template type argument. - ArgType = Context.getCanonicalType(ArgType); - // Objective-C ARC: // If an explicitly-specified template argument type is a lifetime type // with no lifetime qualifier, the __strong lifetime qualifier is inferred. @@ -5113,7 +6407,9 @@ ArgType = Context.getQualifiedType(ArgType, Qs); } - Converted.push_back(TemplateArgument(ArgType)); + SugaredConverted.push_back(TemplateArgument(ArgType)); + CanonicalConverted.push_back( + TemplateArgument(Context.getCanonicalType(ArgType))); return false; } @@ -5159,8 +6455,8 @@ TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted); // Only substitute for the innermost template argument list. - MultiLevelTemplateArgumentList TemplateArgLists; - TemplateArgLists.addOuterTemplateArguments(&TemplateArgs); + MultiLevelTemplateArgumentList TemplateArgLists(Template, + TemplateArgs.asArray()); for (unsigned i = 0, e = Param->getDepth(); i != e; ++i) TemplateArgLists.addOuterTemplateArguments(None); @@ -5215,8 +6511,8 @@ TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted); // Only substitute for the innermost template argument list. - MultiLevelTemplateArgumentList TemplateArgLists; - TemplateArgLists.addOuterTemplateArguments(&TemplateArgs); + MultiLevelTemplateArgumentList TemplateArgLists(Template, + TemplateArgs.asArray()); for (unsigned i = 0, e = Param->getDepth(); i != e; ++i) TemplateArgLists.addOuterTemplateArguments(None); @@ -5268,8 +6564,8 @@ TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted); // Only substitute for the innermost template argument list. - MultiLevelTemplateArgumentList TemplateArgLists; - TemplateArgLists.addOuterTemplateArguments(&TemplateArgs); + MultiLevelTemplateArgumentList TemplateArgLists(Template, + TemplateArgs.asArray()); for (unsigned i = 0, e = Param->getDepth(); i != e; ++i) TemplateArgLists.addOuterTemplateArguments(None); @@ -5419,17 +6715,17 @@ /// explicitly written, deduced, etc. /// /// \returns true on error, false otherwise. -bool Sema::CheckTemplateArgument(NamedDecl *Param, - TemplateArgumentLoc &Arg, - NamedDecl *Template, - SourceLocation TemplateLoc, - SourceLocation RAngleLoc, - unsigned ArgumentPackIndex, - SmallVectorImpl &Converted, - CheckTemplateArgumentKind CTAK) { +bool Sema::CheckTemplateArgument( + NamedDecl *Param, TemplateArgumentLoc &Arg, NamedDecl *Template, + SourceLocation TemplateLoc, SourceLocation RAngleLoc, + unsigned ArgumentPackIndex, + SmallVectorImpl &SugaredConverted, + SmallVectorImpl &CanonicalConverted, + CheckTemplateArgumentKind CTAK) { // Check template type parameters. if (TemplateTypeParmDecl *TTP = dyn_cast(Param)) - return CheckTemplateTypeArgument(TTP, Arg, Converted); + return CheckTemplateTypeArgument(TTP, Arg, SugaredConverted, + CanonicalConverted); // Check non-type template parameters. if (NonTypeTemplateParmDecl *NTTP =dyn_cast(Param)) { @@ -5444,28 +6740,30 @@ !isa(Template) && !Template->getDeclContext()->isDependentContext()) { // Do substitution on the type of the non-type template parameter. - InstantiatingTemplate Inst(*this, TemplateLoc, Template, - NTTP, Converted, + InstantiatingTemplate Inst(*this, TemplateLoc, Template, NTTP, + SugaredConverted, SourceRange(TemplateLoc, RAngleLoc)); if (Inst.isInvalid()) return true; + // FIXME: Substitute with sugared arguments. + // getSubstTemplateTypeParmPackType needs to handle non-canonical pack. TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, - Converted); + CanonicalConverted); // If the parameter is a pack expansion, expand this slice of the pack. if (auto *PET = NTTPType->getAs()) { Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(*this, ArgumentPackIndex); - NTTPType = SubstType(PET->getPattern(), - MultiLevelTemplateArgumentList(TemplateArgs), - NTTP->getLocation(), - NTTP->getDeclName()); + NTTPType = SubstType( + PET->getPattern(), + MultiLevelTemplateArgumentList(Template, TemplateArgs.asArray()), + NTTP->getLocation(), NTTP->getDeclName()); } else { - NTTPType = SubstType(NTTPType, - MultiLevelTemplateArgumentList(TemplateArgs), - NTTP->getLocation(), - NTTP->getDeclName()); + NTTPType = SubstType( + NTTPType, + MultiLevelTemplateArgumentList(Template, TemplateArgs.asArray()), + NTTP->getLocation(), NTTP->getDeclName()); } // If that worked, check the non-type template parameter type @@ -5482,11 +6780,18 @@ llvm_unreachable("Should never see a NULL template argument here"); case TemplateArgument::Expression: { - TemplateArgument Result; + Expr *E = Arg.getArgument().getAsExpr(); + // FIXME: Workaround for double conversion + if (isa(E)) { + SugaredConverted.push_back(Arg.getArgument()); + CanonicalConverted.push_back( + Context.getCanonicalTemplateArgument(Arg.getArgument())); + break; + } + TemplateArgument SugaredResult, CanonicalResult; unsigned CurSFINAEErrors = NumSFINAEErrors; - ExprResult Res = - CheckTemplateArgument(NTTP, NTTPType, Arg.getArgument().getAsExpr(), - Result, CTAK); + ExprResult Res = CheckTemplateArgument(NTTP, NTTPType, E, SugaredResult, + CanonicalResult, CTAK); if (Res.isInvalid()) return true; // If the current template argument causes an error, give up now. @@ -5500,7 +6805,8 @@ Arg = TemplateArgumentLoc(TA, Res.get()); } - Converted.push_back(Result); + SugaredConverted.push_back(SugaredResult); + CanonicalConverted.push_back(CanonicalResult); break; } @@ -5509,7 +6815,9 @@ case TemplateArgument::NullPtr: // We've already checked this template argument, so just copy // it to the list of converted arguments. - Converted.push_back(Arg.getArgument()); + SugaredConverted.push_back(Arg.getArgument()); + CanonicalConverted.push_back( + Context.getCanonicalTemplateArgument(Arg.getArgument())); break; case TemplateArgument::Template: @@ -5545,12 +6853,14 @@ return true; } - TemplateArgument Result; - E = CheckTemplateArgument(NTTP, NTTPType, E.get(), Result); + TemplateArgument SugaredResult, CanonicalResult; + E = CheckTemplateArgument(NTTP, NTTPType, E.get(), SugaredResult, + CanonicalResult, CTAK_Specified); if (E.isInvalid()) return true; - Converted.push_back(Result); + SugaredConverted.push_back(SugaredResult); + CanonicalConverted.push_back(CanonicalResult); break; } @@ -5607,15 +6917,17 @@ { // Set up a template instantiation context. LocalInstantiationScope Scope(*this); - InstantiatingTemplate Inst(*this, TemplateLoc, Template, - TempParm, Converted, + InstantiatingTemplate Inst(*this, TemplateLoc, Template, TempParm, + SugaredConverted, SourceRange(TemplateLoc, RAngleLoc)); if (Inst.isInvalid()) return true; - TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted); - Params = SubstTemplateParams(Params, CurContext, - MultiLevelTemplateArgumentList(TemplateArgs)); + TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, + SugaredConverted); + Params = SubstTemplateParams( + Params, CurContext, + MultiLevelTemplateArgumentList(Template, TemplateArgs.asArray())); if (!Params) return true; } @@ -5640,7 +6952,9 @@ if (CheckTemplateTemplateArgument(TempParm, Params, Arg)) return true; - Converted.push_back(Arg.getArgument()); + SugaredConverted.push_back(Arg.getArgument()); + CanonicalConverted.push_back( + Context.getCanonicalTemplateArgument(Arg.getArgument())); break; case TemplateArgument::Expression: @@ -5707,7 +7021,8 @@ bool Sema::CheckTemplateArgumentList( TemplateDecl *Template, SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs, bool PartialTemplateArgs, - SmallVectorImpl &Converted, + SmallVectorImpl &SugaredConverted, + SmallVectorImpl &CanonicalConverted, bool UpdateArgsWithConversions, bool *ConstraintsNotSatisfied) { if (ConstraintsNotSatisfied) @@ -5733,7 +7048,8 @@ // corresponding parameter declared by the template in its // template-parameter-list. bool isTemplateTemplateParameter = isa(Template); - SmallVector ArgumentPack; + SmallVector SugaredArgumentPack; + SmallVector CanonicalArgumentPack; unsigned ArgIdx = 0, NumArgs = NewArgs.size(); LocalInstantiationScope InstScope(*this, true); for (TemplateParameterList::iterator Param = Params->begin(), @@ -5742,12 +7058,16 @@ // If we have an expanded parameter pack, make sure we don't have too // many arguments. if (Optional Expansions = getExpandedPackSize(*Param)) { - if (*Expansions == ArgumentPack.size()) { + if (*Expansions == SugaredArgumentPack.size()) { // We're done with this parameter pack. Pack up its arguments and add // them to the list. - Converted.push_back( - TemplateArgument::CreatePackCopy(Context, ArgumentPack)); - ArgumentPack.clear(); + SugaredConverted.push_back( + TemplateArgument::CreatePackCopy(Context, SugaredArgumentPack)); + SugaredArgumentPack.clear(); + + CanonicalConverted.push_back( + TemplateArgument::CreatePackCopy(Context, CanonicalArgumentPack)); + CanonicalArgumentPack.clear(); // This argument is assigned to the next parameter. ++Param; @@ -5766,9 +7086,10 @@ if (ArgIdx < NumArgs) { // Check the template argument we were given. - if (CheckTemplateArgument(*Param, NewArgs[ArgIdx], Template, - TemplateLoc, RAngleLoc, - ArgumentPack.size(), Converted)) + if (CheckTemplateArgument(*Param, NewArgs[ArgIdx], Template, TemplateLoc, + RAngleLoc, SugaredArgumentPack.size(), + SugaredConverted, CanonicalConverted, + CTAK_Specified)) return true; bool PackExpansionIntoNonPack = @@ -5797,7 +7118,8 @@ // deduced argument and place it on the argument pack. Note that we // stay on the same template parameter so that we can deduce more // arguments. - ArgumentPack.push_back(Converted.pop_back_val()); + SugaredArgumentPack.push_back(SugaredConverted.pop_back_val()); + CanonicalArgumentPack.push_back(CanonicalConverted.pop_back_val()); } else { // Move to the next template parameter. ++Param; @@ -5807,16 +7129,25 @@ // the remaining arguments, because we don't know what parameters they'll // match up with. if (PackExpansionIntoNonPack) { - if (!ArgumentPack.empty()) { + if (!SugaredArgumentPack.empty()) { // If we were part way through filling in an expanded parameter pack, // fall back to just producing individual arguments. - Converted.insert(Converted.end(), - ArgumentPack.begin(), ArgumentPack.end()); - ArgumentPack.clear(); + SugaredConverted.insert(SugaredConverted.end(), + SugaredArgumentPack.begin(), + SugaredArgumentPack.end()); + SugaredArgumentPack.clear(); + + CanonicalConverted.insert(CanonicalConverted.end(), + CanonicalArgumentPack.begin(), + CanonicalArgumentPack.end()); + CanonicalArgumentPack.clear(); } while (ArgIdx < NumArgs) { - Converted.push_back(NewArgs[ArgIdx].getArgument()); + const TemplateArgument &Arg = NewArgs[ArgIdx].getArgument(); + SugaredConverted.push_back(Arg); + CanonicalConverted.push_back( + Context.getCanonicalTemplateArgument(Arg)); ++ArgIdx; } @@ -5828,9 +7159,12 @@ // If we're checking a partial template argument list, we're done. if (PartialTemplateArgs) { - if ((*Param)->isTemplateParameterPack() && !ArgumentPack.empty()) - Converted.push_back( - TemplateArgument::CreatePackCopy(Context, ArgumentPack)); + if ((*Param)->isTemplateParameterPack() && !SugaredArgumentPack.empty()) { + SugaredConverted.push_back( + TemplateArgument::CreatePackCopy(Context, SugaredArgumentPack)); + CanonicalConverted.push_back( + TemplateArgument::CreatePackCopy(Context, CanonicalArgumentPack)); + } return false; } @@ -5846,9 +7180,13 @@ if (Param + 1 != ParamEnd) return true; - Converted.push_back( - TemplateArgument::CreatePackCopy(Context, ArgumentPack)); - ArgumentPack.clear(); + SugaredConverted.push_back( + TemplateArgument::CreatePackCopy(Context, SugaredArgumentPack)); + SugaredArgumentPack.clear(); + + CanonicalConverted.push_back( + TemplateArgument::CreatePackCopy(Context, CanonicalArgumentPack)); + CanonicalArgumentPack.clear(); ++Param; continue; @@ -5867,12 +7205,8 @@ return diagnoseMissingArgument(*this, TemplateLoc, Template, TTP, NewArgs); - TypeSourceInfo *ArgType = SubstDefaultTemplateArgument(*this, - Template, - TemplateLoc, - RAngleLoc, - TTP, - Converted); + TypeSourceInfo *ArgType = SubstDefaultTemplateArgument( + *this, Template, TemplateLoc, RAngleLoc, TTP, SugaredConverted); if (!ArgType) return true; @@ -5884,11 +7218,8 @@ return diagnoseMissingArgument(*this, TemplateLoc, Template, NTTP, NewArgs); - ExprResult E = SubstDefaultTemplateArgument(*this, Template, - TemplateLoc, - RAngleLoc, - NTTP, - Converted); + ExprResult E = SubstDefaultTemplateArgument( + *this, Template, TemplateLoc, RAngleLoc, NTTP, SugaredConverted); if (E.isInvalid()) return true; @@ -5903,12 +7234,9 @@ NewArgs); NestedNameSpecifierLoc QualifierLoc; - TemplateName Name = SubstDefaultTemplateArgument(*this, Template, - TemplateLoc, - RAngleLoc, - TempParm, - Converted, - QualifierLoc); + TemplateName Name = SubstDefaultTemplateArgument( + *this, Template, TemplateLoc, RAngleLoc, TempParm, SugaredConverted, + QualifierLoc); if (Name.isNull()) return true; @@ -5921,14 +7249,16 @@ // the default template argument. We're not actually instantiating a // template here, we just create this object to put a note into the // context stack. - InstantiatingTemplate Inst(*this, RAngleLoc, Template, *Param, Converted, + InstantiatingTemplate Inst(*this, RAngleLoc, Template, *Param, + SugaredConverted, SourceRange(TemplateLoc, RAngleLoc)); if (Inst.isInvalid()) return true; // Check the default template argument. - if (CheckTemplateArgument(*Param, Arg, Template, TemplateLoc, - RAngleLoc, 0, Converted)) + if (CheckTemplateArgument(*Param, Arg, Template, TemplateLoc, RAngleLoc, 0, + SugaredConverted, CanonicalConverted, + CTAK_Specified)) return true; // Core issue 150 (assumed resolution): if this is a template template @@ -5948,8 +7278,12 @@ // still dependent). if (ArgIdx < NumArgs && CurrentInstantiationScope && CurrentInstantiationScope->getPartiallySubstitutedPack()) { - while (ArgIdx < NumArgs && NewArgs[ArgIdx].getArgument().isPackExpansion()) - Converted.push_back(NewArgs[ArgIdx++].getArgument()); + while (ArgIdx < NumArgs && + NewArgs[ArgIdx].getArgument().isPackExpansion()) { + const TemplateArgument &Arg = NewArgs[ArgIdx++].getArgument(); + SugaredConverted.push_back(Arg); + CanonicalConverted.push_back(Context.getCanonicalTemplateArgument(Arg)); + } } // If we have any leftover arguments, then there were too many arguments. @@ -5972,8 +7306,8 @@ if (!PartialTemplateArgs && EnsureTemplateArgumentListConstraints( - Template, Converted, SourceRange(TemplateLoc, - TemplateArgs.getRAngleLoc()))) { + Template, SugaredConverted, + SourceRange(TemplateLoc, TemplateArgs.getRAngleLoc()))) { if (ConstraintsNotSatisfied) *ConstraintsNotSatisfied = true; return true; @@ -6453,12 +7787,9 @@ /// Checks whether the given template argument is the address /// of an object or function according to C++ [temp.arg.nontype]p1. -static bool -CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, - NonTypeTemplateParmDecl *Param, - QualType ParamType, - Expr *ArgIn, - TemplateArgument &Converted) { +static bool CheckTemplateArgumentAddressOfObjectOrFunction( + Sema &S, NonTypeTemplateParmDecl *Param, QualType ParamType, Expr *ArgIn, + TemplateArgument &SugaredConverted, TemplateArgument &CanonicalConverted) { bool Invalid = false; Expr *Arg = ArgIn; QualType ArgType = Arg->getType(); @@ -6562,8 +7893,11 @@ Entity)) { case NPV_NullPointer: S.Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null); - Converted = TemplateArgument(S.Context.getCanonicalType(ParamType), - /*isNullPtr=*/true); + SugaredConverted = TemplateArgument(ParamType, + /*isNullPtr=*/true); + CanonicalConverted = + TemplateArgument(S.Context.getCanonicalType(ParamType), + /*isNullPtr=*/true); return false; case NPV_Error: @@ -6577,7 +7911,9 @@ // Stop checking the precise nature of the argument if it is value dependent, // it should be checked when instantiated. if (Arg->isValueDependent()) { - Converted = TemplateArgument(ArgIn); + SugaredConverted = TemplateArgument(ArgIn); + CanonicalConverted = + S.Context.getCanonicalTemplateArgument(SugaredConverted); return false; } @@ -6707,19 +8043,21 @@ return true; // Create the template argument. - Converted = TemplateArgument(cast(Entity->getCanonicalDecl()), - S.Context.getCanonicalType(ParamType)); + SugaredConverted = TemplateArgument(Entity, ParamType); + CanonicalConverted = + TemplateArgument(cast(Entity->getCanonicalDecl()), + S.Context.getCanonicalType(ParamType)); S.MarkAnyDeclReferenced(Arg->getBeginLoc(), Entity, false); return false; } /// Checks whether the given template argument is a pointer to /// member constant according to C++ [temp.arg.nontype]p1. -static bool CheckTemplateArgumentPointerToMember(Sema &S, - NonTypeTemplateParmDecl *Param, - QualType ParamType, - Expr *&ResultArg, - TemplateArgument &Converted) { +static bool +CheckTemplateArgumentPointerToMember(Sema &S, NonTypeTemplateParmDecl *Param, + QualType ParamType, Expr *&ResultArg, + TemplateArgument &SugaredConverted, + TemplateArgument &CanonicalConverted) { bool Invalid = false; Expr *Arg = ResultArg; @@ -6767,10 +8105,14 @@ if (VD->getType()->isMemberPointerType()) { if (isa(VD)) { if (Arg->isTypeDependent() || Arg->isValueDependent()) { - Converted = TemplateArgument(Arg); + SugaredConverted = TemplateArgument(Arg); + CanonicalConverted = + S.Context.getCanonicalTemplateArgument(SugaredConverted); } else { - VD = cast(VD->getCanonicalDecl()); - Converted = TemplateArgument(VD, ParamType); + SugaredConverted = TemplateArgument(VD, ParamType); + CanonicalConverted = + TemplateArgument(cast(VD->getCanonicalDecl()), + S.Context.getCanonicalType(ParamType)); } return Invalid; } @@ -6788,8 +8130,10 @@ return true; case NPV_NullPointer: S.Diag(ResultArg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null); - Converted = TemplateArgument(S.Context.getCanonicalType(ParamType), - /*isNullPtr*/true); + SugaredConverted = TemplateArgument(ParamType, + /*isNullPtr*/ true); + CanonicalConverted = TemplateArgument(S.Context.getCanonicalType(ParamType), + /*isNullPtr*/ true); return false; case NPV_NotNullPointer: break; @@ -6826,10 +8170,15 @@ // Okay: this is the address of a non-static member, and therefore // a member pointer constant. if (Arg->isTypeDependent() || Arg->isValueDependent()) { - Converted = TemplateArgument(Arg); + SugaredConverted = TemplateArgument(Arg); + CanonicalConverted = + S.Context.getCanonicalTemplateArgument(SugaredConverted); } else { - ValueDecl *D = cast(DRE->getDecl()->getCanonicalDecl()); - Converted = TemplateArgument(D, S.Context.getCanonicalType(ParamType)); + ValueDecl *D = DRE->getDecl(); + SugaredConverted = TemplateArgument(D, ParamType); + CanonicalConverted = + TemplateArgument(cast(D->getCanonicalDecl()), + S.Context.getCanonicalType(ParamType)); } return Invalid; } @@ -6850,7 +8199,8 @@ /// type of the non-type template parameter after it has been instantiated. ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, QualType ParamType, Expr *Arg, - TemplateArgument &Converted, + TemplateArgument &SugaredConverted, + TemplateArgument &CanonicalConverted, CheckTemplateArgumentKind CTAK) { SourceLocation StartLoc = Arg->getBeginLoc(); @@ -6865,7 +8215,9 @@ if (CTAK == CTAK_Deduced && Arg->isTypeDependent()) { auto *AT = dyn_cast(DeducedT); if (AT && AT->isDecltypeAuto()) { - Converted = TemplateArgument(Arg); + SugaredConverted = TemplateArgument(Arg); + CanonicalConverted = TemplateArgument( + Context.getCanonicalTemplateArgument(SugaredConverted)); return Arg; } } @@ -6940,7 +8292,9 @@ // work. Similarly for CTAD, when comparing 'A' against 'A'. if ((ParamType->isDependentType() || Arg->isTypeDependent()) && !Arg->getType()->getContainedDeducedType()) { - Converted = TemplateArgument(Arg); + SugaredConverted = TemplateArgument(Arg); + CanonicalConverted = TemplateArgument( + Context.getCanonicalTemplateArgument(SugaredConverted)); return Arg; } // FIXME: This attempts to implement C++ [temp.deduct.type]p17. Per DR1770, @@ -6977,7 +8331,9 @@ PackExpansionExpr(E.get()->getType(), E.get(), PE->getEllipsisLoc(), PE->getNumExpansions()); } - Converted = TemplateArgument(E.get()); + SugaredConverted = TemplateArgument(E.get()); + CanonicalConverted = TemplateArgument( + Context.getCanonicalTemplateArgument(SugaredConverted)); return E; } @@ -7002,11 +8358,16 @@ Context.hasSameUnqualifiedType(ParamType, InnerArg->getType())) { NamedDecl *ND = cast(InnerArg)->getDecl(); if (auto *TPO = dyn_cast(ND)) { - Converted = TemplateArgument(TPO, CanonParamType); + + SugaredConverted = TemplateArgument(TPO, ParamType); + CanonicalConverted = + TemplateArgument(TPO->getCanonicalDecl(), CanonParamType); return Arg; } if (isa(ND)) { - Converted = TemplateArgument(Arg); + SugaredConverted = TemplateArgument(Arg); + CanonicalConverted = + Context.getCanonicalTemplateArgument(SugaredConverted); return Arg; } } @@ -7023,7 +8384,9 @@ // For a value-dependent argument, CheckConvertedConstantExpression is // permitted (and expected) to be unable to determine a value. if (ArgResult.get()->isValueDependent()) { - Converted = TemplateArgument(ArgResult.get()); + SugaredConverted = TemplateArgument(ArgResult.get()); + CanonicalConverted = + Context.getCanonicalTemplateArgument(SugaredConverted); return ArgResult; } @@ -7031,14 +8394,17 @@ switch (Value.getKind()) { case APValue::None: assert(ParamType->isNullPtrType()); - Converted = TemplateArgument(CanonParamType, /*isNullPtr*/true); + SugaredConverted = TemplateArgument(ParamType, /*isNullPtr=*/true); + CanonicalConverted = TemplateArgument(CanonParamType, /*isNullPtr=*/true); break; case APValue::Indeterminate: llvm_unreachable("result of constant evaluation should be initialized"); break; case APValue::Int: assert(ParamType->isIntegralOrEnumerationType()); - Converted = TemplateArgument(Context, Value.getInt(), CanonParamType); + SugaredConverted = TemplateArgument(Context, Value.getInt(), ParamType); + CanonicalConverted = + TemplateArgument(Context, Value.getInt(), CanonParamType); break; case APValue::MemberPointer: { assert(ParamType->isMemberPointerType()); @@ -7053,8 +8419,12 @@ } auto *VD = const_cast(Value.getMemberPointerDecl()); - Converted = VD ? TemplateArgument(VD, CanonParamType) - : TemplateArgument(CanonParamType, /*isNullPtr*/true); + SugaredConverted = VD ? TemplateArgument(VD, ParamType) + : TemplateArgument(ParamType, /*isNullPtr=*/true); + CanonicalConverted = + VD ? TemplateArgument(cast(VD->getCanonicalDecl()), + CanonParamType) + : TemplateArgument(CanonParamType, /*isNullPtr=*/true); break; } case APValue::LValue: { @@ -7094,17 +8464,25 @@ "null reference should not be a constant expression"); assert((!VD || !ParamType->isNullPtrType()) && "non-null value of type nullptr_t?"); - Converted = VD ? TemplateArgument(VD, CanonParamType) - : TemplateArgument(CanonParamType, /*isNullPtr*/true); + // FIXME: copy pasta from case above. + SugaredConverted = VD ? TemplateArgument(VD, ParamType) + : TemplateArgument(ParamType, /*isNullPtr=*/true); + CanonicalConverted = + VD ? TemplateArgument(cast(VD->getCanonicalDecl()), + CanonParamType) + : TemplateArgument(CanonParamType, /*isNullPtr=*/true); break; } case APValue::Struct: - case APValue::Union: + case APValue::Union: { // Get or create the corresponding template parameter object. - Converted = TemplateArgument( - Context.getTemplateParamObjectDecl(CanonParamType, Value), - CanonParamType); + TemplateParamObjectDecl *D = + Context.getTemplateParamObjectDecl(ParamType, Value); + SugaredConverted = TemplateArgument(D, ParamType); + CanonicalConverted = + TemplateArgument(D->getCanonicalDecl(), CanonParamType); break; + } case APValue::AddrLabelDiff: return Diag(StartLoc, diag::err_non_type_template_arg_addr_label_diff); case APValue::FixedPoint: @@ -7154,7 +8532,9 @@ // We can't check arbitrary value-dependent arguments. if (ArgResult.get()->isValueDependent()) { - Converted = TemplateArgument(ArgResult.get()); + SugaredConverted = TemplateArgument(ArgResult.get()); + CanonicalConverted = + Context.getCanonicalTemplateArgument(SugaredConverted); return ArgResult; } @@ -7168,8 +8548,9 @@ ? Context.getIntWidth(IntegerType) : Context.getTypeSize(IntegerType)); - Converted = TemplateArgument(Context, Value, - Context.getCanonicalType(ParamType)); + SugaredConverted = TemplateArgument(Context, Value, ParamType); + CanonicalConverted = + TemplateArgument(Context, Value, Context.getCanonicalType(ParamType)); return ArgResult; } @@ -7239,13 +8620,16 @@ if (Arg->isValueDependent()) { // The argument is value-dependent. Create a new // TemplateArgument with the converted expression. - Converted = TemplateArgument(Arg); + SugaredConverted = TemplateArgument(Arg); + CanonicalConverted = + Context.getCanonicalTemplateArgument(SugaredConverted); return Arg; } - QualType IntegerType = Context.getCanonicalType(ParamType); - if (const EnumType *Enum = IntegerType->getAs()) - IntegerType = Context.getCanonicalType(Enum->getDecl()->getIntegerType()); + QualType IntegerType = ParamType; + if (const EnumType *Enum = IntegerType->getAs()) { + IntegerType = Enum->getDecl()->getIntegerType(); + } if (ParamType->isBooleanType()) { // Value must be zero or one. @@ -7291,10 +8675,10 @@ } } - Converted = TemplateArgument(Context, Value, - ParamType->isEnumeralType() - ? Context.getCanonicalType(ParamType) - : IntegerType); + QualType T = ParamType->isEnumeralType() ? ParamType : IntegerType; + SugaredConverted = TemplateArgument(Context, Value, T); + CanonicalConverted = + TemplateArgument(Context, Value, Context.getCanonicalType(T)); return Arg; } @@ -7332,22 +8716,23 @@ if (DiagnoseUseOfDecl(Fn, Arg->getBeginLoc())) return ExprError(); - Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn); + // FIXME: resugar + Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn, nullptr); ArgType = Arg->getType(); } else return ExprError(); } if (!ParamType->isMemberPointerType()) { - if (CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param, - ParamType, - Arg, Converted)) + if (CheckTemplateArgumentAddressOfObjectOrFunction( + *this, Param, ParamType, Arg, SugaredConverted, + CanonicalConverted)) return ExprError(); return Arg; } - if (CheckTemplateArgumentPointerToMember(*this, Param, ParamType, Arg, - Converted)) + if (CheckTemplateArgumentPointerToMember( + *this, Param, ParamType, Arg, SugaredConverted, CanonicalConverted)) return ExprError(); return Arg; } @@ -7360,9 +8745,8 @@ assert(ParamType->getPointeeType()->isIncompleteOrObjectType() && "Only object pointers allowed here"); - if (CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param, - ParamType, - Arg, Converted)) + if (CheckTemplateArgumentAddressOfObjectOrFunction( + *this, Param, ParamType, Arg, SugaredConverted, CanonicalConverted)) return ExprError(); return Arg; } @@ -7385,15 +8769,15 @@ if (DiagnoseUseOfDecl(Fn, Arg->getBeginLoc())) return ExprError(); - Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn); + // FIXME: resugar + Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn, nullptr); ArgType = Arg->getType(); } else return ExprError(); } - if (CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param, - ParamType, - Arg, Converted)) + if (CheckTemplateArgumentAddressOfObjectOrFunction( + *this, Param, ParamType, Arg, SugaredConverted, CanonicalConverted)) return ExprError(); return Arg; } @@ -7401,7 +8785,9 @@ // Deal with parameters of type std::nullptr_t. if (ParamType->isNullPtrType()) { if (Arg->isTypeDependent() || Arg->isValueDependent()) { - Converted = TemplateArgument(Arg); + SugaredConverted = TemplateArgument(Arg); + CanonicalConverted = + Context.getCanonicalTemplateArgument(SugaredConverted); return Arg; } @@ -7417,8 +8803,10 @@ case NPV_NullPointer: Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null); - Converted = TemplateArgument(Context.getCanonicalType(ParamType), - /*isNullPtr*/true); + SugaredConverted = TemplateArgument(ParamType, + /*isNullPtr*/ true); + CanonicalConverted = TemplateArgument(Context.getCanonicalType(ParamType), + /*isNullPtr*/ true); return Arg; } } @@ -7427,8 +8815,8 @@ // member, qualification conversions (4.4) are applied. assert(ParamType->isMemberPointerType() && "Only pointers to members remain"); - if (CheckTemplateArgumentPointerToMember(*this, Param, ParamType, Arg, - Converted)) + if (CheckTemplateArgumentPointerToMember( + *this, Param, ParamType, Arg, SugaredConverted, CanonicalConverted)) return ExprError(); return Arg; } @@ -8415,9 +9803,9 @@ // Check that the template argument list is well-formed for this // template. - SmallVector Converted; - if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, - TemplateArgs, false, Converted, + SmallVector SugaredConverted, CanonicalConverted; + if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, TemplateArgs, + false, SugaredConverted, CanonicalConverted, /*UpdateArgsWithConversions=*/true)) return true; @@ -8425,14 +9813,15 @@ // corresponds to these arguments. if (isPartialSpecialization) { if (CheckTemplatePartialSpecializationArgs(TemplateNameLoc, ClassTemplate, - TemplateArgs.size(), Converted)) + TemplateArgs.size(), + CanonicalConverted)) return true; // FIXME: Move this to CheckTemplatePartialSpecializationArgs so we // also do it during instantiation. if (!Name.isDependent() && - !TemplateSpecializationType::anyDependentTemplateArguments(TemplateArgs, - Converted)) { + !TemplateSpecializationType::anyDependentTemplateArguments( + TemplateArgs, CanonicalConverted)) { Diag(TemplateNameLoc, diag::err_partial_spec_fully_specialized) << ClassTemplate->getDeclName(); isPartialSpecialization = false; @@ -8443,11 +9832,10 @@ ClassTemplateSpecializationDecl *PrevDecl = nullptr; if (isPartialSpecialization) - PrevDecl = ClassTemplate->findPartialSpecialization(Converted, - TemplateParams, - InsertPos); + PrevDecl = ClassTemplate->findPartialSpecialization( + CanonicalConverted, TemplateParams, InsertPos); else - PrevDecl = ClassTemplate->findSpecialization(Converted, InsertPos); + PrevDecl = ClassTemplate->findSpecialization(CanonicalConverted, InsertPos); ClassTemplateSpecializationDecl *Specialization = nullptr; @@ -8459,17 +9847,15 @@ isPartialSpecialization)) return true; - // The canonical type - QualType CanonType; + QualType T; if (isPartialSpecialization) { - // Build the canonical type that describes the converted template + // Build the sugared type that describes the converted template // arguments of the class template partial specialization. - TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name); - CanonType = Context.getTemplateSpecializationType(CanonTemplate, - Converted); + T = Context.getTemplateSpecializationType( + Name, TemplateArgs.arguments(), SugaredConverted, CanonicalConverted); - if (Context.hasSameType(CanonType, - ClassTemplate->getInjectedClassNameSpecialization()) && + if (Context.hasSameType( + T, ClassTemplate->getInjectedClassNameSpecialization()) && (!Context.getLangOpts().CPlusPlus20 || !TemplateParams->hasAssociatedConstraints())) { // C++ [temp.class.spec]p9b3: @@ -8496,16 +9882,12 @@ // Create a new class template partial specialization declaration node. ClassTemplatePartialSpecializationDecl *PrevPartial = cast_or_null(PrevDecl); - ClassTemplatePartialSpecializationDecl *Partial - = ClassTemplatePartialSpecializationDecl::Create(Context, Kind, - ClassTemplate->getDeclContext(), - KWLoc, TemplateNameLoc, - TemplateParams, - ClassTemplate, - Converted, - TemplateArgs, - CanonType, - PrevPartial); + // FIXME: Use SugaredConverted here. + ClassTemplatePartialSpecializationDecl *Partial = + ClassTemplatePartialSpecializationDecl::Create( + Context, Kind, ClassTemplate->getDeclContext(), KWLoc, + TemplateNameLoc, TemplateParams, ClassTemplate, CanonicalConverted, + TemplateArgs, T, PrevPartial); SetNestedNameSpecifier(*this, Partial, SS); if (TemplateParameterLists.size() > 1 && SS.isSet()) { Partial->setTemplateParameterListsInfo( @@ -8525,13 +9907,9 @@ } else { // Create a new class template specialization declaration node for // this explicit specialization or friend declaration. - Specialization - = ClassTemplateSpecializationDecl::Create(Context, Kind, - ClassTemplate->getDeclContext(), - KWLoc, TemplateNameLoc, - ClassTemplate, - Converted, - PrevDecl); + Specialization = ClassTemplateSpecializationDecl::Create( + Context, Kind, ClassTemplate->getDeclContext(), KWLoc, TemplateNameLoc, + ClassTemplate, CanonicalConverted, PrevDecl); SetNestedNameSpecifier(*this, Specialization, SS); if (TemplateParameterLists.size() > 0) { Specialization->setTemplateParameterListsInfo(Context, @@ -8542,11 +9920,10 @@ ClassTemplate->AddSpecialization(Specialization, InsertPos); if (CurContext->isDependentContext()) { - TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name); - CanonType = Context.getTemplateSpecializationType( - CanonTemplate, Converted); + T = Context.getCanonicalTemplateSpecializationType(Name, + CanonicalConverted); } else { - CanonType = Context.getTypeDeclType(Specialization); + T = Context.getTypeDeclType(Specialization); } } @@ -8579,6 +9956,17 @@ } } + // Build the fully-sugared type for this class template + // specialization as the user wrote in the specialization + // itself. This means that we'll pretty-print the type retrieved + // from the specialization's declaration the way that the user + // actually wrote the specialization, rather than formatting the + // name based on the "canonical" representation used to store the + // template arguments in the specialization. + TypeSourceInfo *WrittenTy = Context.getTemplateSpecializationTypeInfo( + Name, TemplateNameLoc, TemplateArgs, SugaredConverted, + /*CanonicalConverted=*/{}, T); + // If this is not a friend, note that this is an explicit specialization. if (TUK != TUK_Friend) Specialization->setSpecializationKind(TSK_ExplicitSpecialization); @@ -8614,16 +10002,6 @@ << (isPartialSpecialization? 1 : 0) << FixItHint::CreateRemoval(ModulePrivateLoc); - // Build the fully-sugared type for this class template - // specialization as the user wrote in the specialization - // itself. This means that we'll pretty-print the type retrieved - // from the specialization's declaration the way that the user - // actually wrote the specialization, rather than formatting the - // name based on the "canonical" representation used to store the - // template arguments in the specialization. - TypeSourceInfo *WrittenTy - = Context.getTemplateSpecializationTypeInfo(Name, TemplateNameLoc, - TemplateArgs, CanonType); if (TUK != TUK_Friend) { Specialization->setTypeAsWritten(WrittenTy); Specialization->setTemplateKeywordLoc(TemplateKWLoc); @@ -9703,17 +11081,17 @@ // Check that the template argument list is well-formed for this // template. - SmallVector Converted; - if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, - TemplateArgs, false, Converted, + SmallVector SugaredConverted, CanonicalConverted; + if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, TemplateArgs, + false, SugaredConverted, CanonicalConverted, /*UpdateArgsWithConversions=*/true)) return true; // Find the class template specialization declaration that // corresponds to these arguments. void *InsertPos = nullptr; - ClassTemplateSpecializationDecl *PrevDecl - = ClassTemplate->findSpecialization(Converted, InsertPos); + ClassTemplateSpecializationDecl *PrevDecl = + ClassTemplate->findSpecialization(CanonicalConverted, InsertPos); TemplateSpecializationKind PrevDecl_TSK = PrevDecl ? PrevDecl->getTemplateSpecializationKind() : TSK_Undeclared; @@ -9770,13 +11148,9 @@ if (!Specialization) { // Create a new class template specialization declaration node for // this explicit specialization. - Specialization - = ClassTemplateSpecializationDecl::Create(Context, Kind, - ClassTemplate->getDeclContext(), - KWLoc, TemplateNameLoc, - ClassTemplate, - Converted, - PrevDecl); + Specialization = ClassTemplateSpecializationDecl::Create( + Context, Kind, ClassTemplate->getDeclContext(), KWLoc, TemplateNameLoc, + ClassTemplate, CanonicalConverted, PrevDecl); SetNestedNameSpecifier(*this, Specialization, SS); if (!HasNoEffect && !PrevDecl) { @@ -9792,10 +11166,9 @@ // the explicit instantiation, rather than formatting the name based // on the "canonical" representation used to store the template // arguments in the specialization. - TypeSourceInfo *WrittenTy - = Context.getTemplateSpecializationTypeInfo(Name, TemplateNameLoc, - TemplateArgs, - Context.getTypeDeclType(Specialization)); + TypeSourceInfo *WrittenTy = Context.getTemplateSpecializationTypeInfo( + Name, TemplateNameLoc, TemplateArgs, SugaredConverted, CanonicalConverted, + Context.getTypeDeclType(Specialization)); Specialization->setTypeAsWritten(WrittenTy); // Set source locations for keywords. @@ -10516,7 +11889,7 @@ // 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 = + const auto *LookupRD = dyn_cast_or_null(computeDeclContext(SS, false)); if (LookupRD && LookupRD->getIdentifier() == TemplateII) { Diag(TemplateIILoc, @@ -10535,10 +11908,9 @@ // Construct a dependent template specialization type. assert(DTN && "dependent template has non-dependent name?"); assert(DTN->getQualifier() == SS.getScopeRep()); - QualType T = Context.getDependentTemplateSpecializationType(ETK_Typename, - DTN->getQualifier(), - DTN->getIdentifier(), - TemplateArgs); + QualType T = Context.getDependentTemplateSpecializationType( + ETK_Typename, DTN->getQualifier(), DTN->getIdentifier(), + TemplateArgs.arguments()); // Create source-location information for this type. TypeLocBuilder Builder; @@ -10555,7 +11927,7 @@ return CreateParsedType(T, Builder.getTypeSourceInfo(Context, T)); } - QualType T = CheckTemplateIdType(Template, TemplateIILoc, TemplateArgs); + QualType T = CheckTemplateIdType(SS, Template, TemplateIILoc, TemplateArgs); if (T.isNull()) return true; @@ -10575,8 +11947,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)); } @@ -10782,9 +12153,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, 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 @@ -559,10 +559,10 @@ QualType UP = P; if (const auto *IP = P->getAs()) UP = IP->getInjectedSpecializationType(); - // FIXME: Try to preserve type sugar here, which is hard - // because of the unresolved template arguments. - const auto *TP = UP.getCanonicalType()->castAs(); - ArrayRef PResolved = TP->template_arguments(); + assert(isa(UP.getCanonicalType())); + const TemplateSpecializationType *TP = + UP->castAsNonAliasTemplateSpecializationType(); + ArrayRef PResolved = TP->getConvertedArguments(); QualType UA = A; // Treat an injected-class-name as its underlying template-id. @@ -570,9 +570,7 @@ UA = Injected->getInjectedSpecializationType(); // Check whether the template argument is a dependent template-id. - // FIXME: Should not lose sugar here. - if (const auto *SA = - dyn_cast(UA.getCanonicalType())) { + if (const auto *SA = UA->getAsNonAliasTemplateSpecializationType()) { // Perform template argument deduction for the template name. if (auto Result = DeduceTemplateArguments(S, TemplateParams, TP->getTemplateName(), @@ -582,7 +580,7 @@ // 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, + SA->getConvertedArguments(), Info, Deduced, /*NumberOfArgumentsMustMatch=*/false); } @@ -2574,13 +2572,11 @@ /// Convert the given deduced template argument and add it to the set of /// fully-converted template arguments. -static bool -ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param, - DeducedTemplateArgument Arg, - NamedDecl *Template, - TemplateDeductionInfo &Info, - bool IsDeduced, - SmallVectorImpl &Output) { +static bool ConvertDeducedTemplateArgument( + Sema &S, NamedDecl *Param, DeducedTemplateArgument Arg, NamedDecl *Template, + TemplateDeductionInfo &Info, bool IsDeduced, + SmallVectorImpl &SugaredOutput, + SmallVectorImpl &CanonicalOutput) { auto ConvertArg = [&](DeducedTemplateArgument Arg, unsigned ArgumentPackIndex) { // Convert the deduced template argument into a template @@ -2592,7 +2588,8 @@ // Check the template argument, converting it as necessary. return S.CheckTemplateArgument( Param, ArgLoc, Template, Template->getLocation(), - Template->getSourceRange().getEnd(), ArgumentPackIndex, Output, + Template->getSourceRange().getEnd(), ArgumentPackIndex, SugaredOutput, + CanonicalOutput, IsDeduced ? (Arg.wasDeducedFromArrayBound() ? Sema::CTAK_DeducedFromArrayBound : Sema::CTAK_Deduced) @@ -2602,7 +2599,8 @@ if (Arg.getKind() == TemplateArgument::Pack) { // This is a template argument pack, so check each of its arguments against // the template parameter. - SmallVector PackedArgsBuilder; + SmallVector SugaredPackedArgsBuilder, + CanonicalPackedArgsBuilder; for (const auto &P : Arg.pack_elements()) { // When converting the deduced template argument, append it to the // general output list. We need to do this so that the template argument @@ -2621,23 +2619,25 @@ << Arg << Param; return true; } - if (ConvertArg(InnerArg, PackedArgsBuilder.size())) + if (ConvertArg(InnerArg, SugaredPackedArgsBuilder.size())) return true; // Move the converted template argument into our argument pack. - PackedArgsBuilder.push_back(Output.pop_back_val()); + SugaredPackedArgsBuilder.push_back(SugaredOutput.pop_back_val()); + CanonicalPackedArgsBuilder.push_back(CanonicalOutput.pop_back_val()); } // If the pack is empty, we still need to substitute into the parameter // itself, in case that substitution fails. - if (PackedArgsBuilder.empty()) { + if (SugaredPackedArgsBuilder.empty()) { LocalInstantiationScope Scope(S); - TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Output); - MultiLevelTemplateArgumentList Args(TemplateArgs); + TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, + SugaredOutput); + MultiLevelTemplateArgumentList Args(Template, TemplateArgs.asArray()); if (auto *NTTP = dyn_cast(Param)) { Sema::InstantiatingTemplate Inst(S, Template->getLocation(), Template, - NTTP, Output, + NTTP, SugaredOutput, Template->getSourceRange()); if (Inst.isInvalid() || S.SubstType(NTTP->getType(), Args, NTTP->getLocation(), @@ -2645,7 +2645,7 @@ return true; } else if (auto *TTP = dyn_cast(Param)) { Sema::InstantiatingTemplate Inst(S, Template->getLocation(), Template, - TTP, Output, + TTP, SugaredOutput, Template->getSourceRange()); if (Inst.isInvalid() || !S.SubstDecl(TTP, S.CurContext, Args)) return true; @@ -2654,8 +2654,10 @@ } // Create the resulting argument pack. - Output.push_back( - TemplateArgument::CreatePackCopy(S.Context, PackedArgsBuilder)); + SugaredOutput.push_back( + TemplateArgument::CreatePackCopy(S.Context, SugaredPackedArgsBuilder)); + CanonicalOutput.push_back(TemplateArgument::CreatePackCopy( + S.Context, CanonicalPackedArgsBuilder)); return false; } @@ -2665,11 +2667,13 @@ // FIXME: This should not be a template, but // ClassTemplatePartialSpecializationDecl sadly does not derive from // TemplateDecl. -template +template static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments( Sema &S, TemplateDeclT *Template, bool IsDeduced, SmallVectorImpl &Deduced, - TemplateDeductionInfo &Info, SmallVectorImpl &Builder, + TemplateDeductionInfo &Info, + SmallVectorImpl &SugaredBuilder, + SmallVectorImpl &CanonicalBuilder, LocalInstantiationScope *CurrentInstantiationScope = nullptr, unsigned NumAlreadyConverted = 0, bool PartialOverloading = false) { TemplateParameterList *TemplateParams = Template->getTemplateParameters(); @@ -2703,7 +2707,9 @@ // We have already fully type-checked and converted this // argument, because it was explicitly-specified. Just record the // presence of this argument. - Builder.push_back(Deduced[I]); + SugaredBuilder.push_back(Deduced[I]); + CanonicalBuilder.push_back( + S.Context.getCanonicalTemplateArgument(Deduced[I])); continue; } } @@ -2711,10 +2717,13 @@ // We may have deduced this argument, so it still needs to be // checked and converted. if (ConvertDeducedTemplateArgument(S, Param, Deduced[I], Template, Info, - IsDeduced, Builder)) { + IsDeduced, SugaredBuilder, + CanonicalBuilder)) { Info.Param = makeTemplateParameter(Param); // FIXME: These template arguments are temporary. Free them! - Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder)); + Info.reset( + TemplateArgumentList::CreateCopy(S.Context, SugaredBuilder), + TemplateArgumentList::CreateCopy(S.Context, CanonicalBuilder)); return Sema::TDK_SubstitutionFailure; } @@ -2745,15 +2754,16 @@ S.getLangOpts().CPlusPlus17); DefArg = S.SubstDefaultTemplateArgumentIfAvailable( - TD, TD->getLocation(), TD->getSourceRange().getEnd(), Param, Builder, - HasDefaultArg); + TD, TD->getLocation(), TD->getSourceRange().getEnd(), Param, + CanonicalBuilder, HasDefaultArg); } // If there was no default argument, deduction is incomplete. if (DefArg.getArgument().isNull()) { Info.Param = makeTemplateParameter( const_cast(TemplateParams->getParam(I))); - Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder)); + Info.reset(TemplateArgumentList::CreateCopy(S.Context, SugaredBuilder), + TemplateArgumentList::CreateCopy(S.Context, CanonicalBuilder)); if (PartialOverloading) break; return HasDefaultArg ? Sema::TDK_SubstitutionFailure @@ -2761,13 +2771,14 @@ } // Check whether we can actually use the default argument. - if (S.CheckTemplateArgument(Param, DefArg, TD, TD->getLocation(), - TD->getSourceRange().getEnd(), 0, Builder, - Sema::CTAK_Specified)) { + if (S.CheckTemplateArgument( + Param, DefArg, TD, TD->getLocation(), TD->getSourceRange().getEnd(), + 0, SugaredBuilder, CanonicalBuilder, Sema::CTAK_Specified)) { Info.Param = makeTemplateParameter( const_cast(TemplateParams->getParam(I))); // FIXME: These template arguments are temporary. Free them! - Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder)); + Info.reset(TemplateArgumentList::CreateCopy(S.Context, SugaredBuilder), + TemplateArgumentList::CreateCopy(S.Context, CanonicalBuilder)); return Sema::TDK_SubstitutionFailure; } @@ -2795,18 +2806,22 @@ static constexpr bool value = true; }; -template +template static Sema::TemplateDeductionResult -CheckDeducedArgumentConstraints(Sema& S, TemplateDeclT *Template, - ArrayRef DeducedArgs, - TemplateDeductionInfo& Info) { +CheckDeducedArgumentConstraints(Sema &S, TemplateDeclT *Template, + ArrayRef SugaredDeducedArgs, + ArrayRef CanonicalDeducedArgs, + TemplateDeductionInfo &Info) { llvm::SmallVector AssociatedConstraints; Template->getAssociatedConstraints(AssociatedConstraints); + // FIXME: Use SugaredDeducedArgs? if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints, - DeducedArgs, Info.getLocation(), + CanonicalDeducedArgs, Info.getLocation(), Info.AssociatedConstraintsSatisfaction) || !Info.AssociatedConstraintsSatisfaction.IsSatisfied) { - Info.reset(TemplateArgumentList::CreateCopy(S.Context, DeducedArgs)); + Info.reset( + TemplateArgumentList::CreateCopy(S.Context, SugaredDeducedArgs), + TemplateArgumentList::CreateCopy(S.Context, CanonicalDeducedArgs)); return Sema::TDK_ConstraintsNotSatisfied; } return Sema::TDK_Success; @@ -2831,16 +2846,19 @@ // C++ [temp.deduct.type]p2: // [...] or if any template argument remains neither deduced nor // explicitly specified, template argument deduction fails. - SmallVector Builder; + SmallVector SugaredBuilder, CanonicalBuilder; if (auto Result = ConvertDeducedTemplateArguments( - S, Partial, IsPartialOrdering, Deduced, Info, Builder)) + S, Partial, IsPartialOrdering, Deduced, Info, SugaredBuilder, + CanonicalBuilder)) return Result; // Form the template argument list from the deduced template arguments. - TemplateArgumentList *DeducedArgumentList - = TemplateArgumentList::CreateCopy(S.Context, Builder); + TemplateArgumentList *SugaredDeducedArgumentList = + TemplateArgumentList::CreateCopy(S.Context, SugaredBuilder); + TemplateArgumentList *CanonicalDeducedArgumentList = + TemplateArgumentList::CreateCopy(S.Context, CanonicalBuilder); - Info.reset(DeducedArgumentList); + Info.reset(SugaredDeducedArgumentList, CanonicalDeducedArgumentList); // Substitute the deduced template arguments into the template // arguments of the class template partial specialization, and @@ -2855,9 +2873,11 @@ TemplateArgumentListInfo InstArgs(PartialTemplArgInfo->LAngleLoc, PartialTemplArgInfo->RAngleLoc); - if (S.SubstTemplateArguments( - PartialTemplArgInfo->arguments(), - MultiLevelTemplateArgumentList(*DeducedArgumentList), InstArgs)) { + if (S.SubstTemplateArguments(PartialTemplArgInfo->arguments(), + MultiLevelTemplateArgumentList( + Partial, // FIXME: Partial or Template? + CanonicalDeducedArgumentList->asArray()), + InstArgs)) { unsigned ArgIdx = InstArgs.size(), ParamIdx = ArgIdx; if (ParamIdx >= Partial->getTemplateParameters()->size()) ParamIdx = Partial->getTemplateParameters()->size() - 1; @@ -2870,17 +2890,18 @@ } bool ConstraintsNotSatisfied; - SmallVector ConvertedInstArgs; - if (S.CheckTemplateArgumentList(Template, Partial->getLocation(), InstArgs, - false, ConvertedInstArgs, - /*UpdateArgsWithConversions=*/true, - &ConstraintsNotSatisfied)) - return ConstraintsNotSatisfied ? Sema::TDK_ConstraintsNotSatisfied : - Sema::TDK_SubstitutionFailure; + SmallVector SugaredConvertedInstArgs, + CanonicalConvertedInstArgs; + if (S.CheckTemplateArgumentList( + Template, Partial->getLocation(), InstArgs, false, + SugaredConvertedInstArgs, CanonicalConvertedInstArgs, + /*UpdateArgsWithConversions=*/true, &ConstraintsNotSatisfied)) + return ConstraintsNotSatisfied ? Sema::TDK_ConstraintsNotSatisfied + : Sema::TDK_SubstitutionFailure; TemplateParameterList *TemplateParams = Template->getTemplateParameters(); for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) { - TemplateArgument InstArg = ConvertedInstArgs.data()[I]; + TemplateArgument InstArg = SugaredConvertedInstArgs.data()[I]; if (!isSameTemplateArg(S.Context, TemplateArgs[I], InstArg)) { Info.Param = makeTemplateParameter(TemplateParams->getParam(I)); Info.FirstArg = TemplateArgs[I]; @@ -2892,7 +2913,8 @@ if (Trap.hasErrorOccurred()) return Sema::TDK_SubstitutionFailure; - if (auto Result = CheckDeducedArgumentConstraints(S, Partial, Builder, Info)) + if (auto Result = CheckDeducedArgumentConstraints(S, Partial, SugaredBuilder, + CanonicalBuilder, Info)) return Result; return Sema::TDK_Success; @@ -2916,15 +2938,18 @@ // C++ [temp.deduct.type]p2: // [...] or if any template argument remains neither deduced nor // explicitly specified, template argument deduction fails. - SmallVector Builder; + SmallVector SugaredBuilder, CanonicalBuilder; if (auto Result = ConvertDeducedTemplateArguments( - S, Template, /*IsDeduced*/PartialOrdering, Deduced, Info, Builder)) + S, Template, /*IsDeduced*/ PartialOrdering, Deduced, Info, + SugaredBuilder, CanonicalBuilder, + /*CurrentInstantiationScope=*/nullptr, + /*NumAlreadyConverted=*/0U, /*PartialOverloading=*/false)) return Result; // Check that we produced the correct argument list. TemplateParameterList *TemplateParams = Template->getTemplateParameters(); for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) { - TemplateArgument InstArg = Builder[I]; + TemplateArgument InstArg = CanonicalBuilder[I]; if (!isSameTemplateArg(S.Context, TemplateArgs[I], InstArg, /*PackExpansionMatchesPack*/true)) { Info.Param = makeTemplateParameter(TemplateParams->getParam(I)); @@ -2937,8 +2962,8 @@ if (Trap.hasErrorOccurred()) return Sema::TDK_SubstitutionFailure; - if (auto Result = CheckDeducedArgumentConstraints(S, Template, Builder, - Info)) + if (auto Result = CheckDeducedArgumentConstraints(S, Template, SugaredBuilder, + CanonicalBuilder, Info)) return Result; return Sema::TDK_Success; @@ -3090,14 +3115,12 @@ /// /// \returns TDK_Success if substitution was successful, or some failure /// condition. -Sema::TemplateDeductionResult -Sema::SubstituteExplicitTemplateArguments( - FunctionTemplateDecl *FunctionTemplate, - TemplateArgumentListInfo &ExplicitTemplateArgs, - SmallVectorImpl &Deduced, - SmallVectorImpl &ParamTypes, - QualType *FunctionType, - TemplateDeductionInfo &Info) { +Sema::TemplateDeductionResult Sema::SubstituteExplicitTemplateArguments( + FunctionTemplateDecl *FunctionTemplate, + TemplateArgumentListInfo &ExplicitTemplateArgs, + SmallVectorImpl &Deduced, + SmallVectorImpl &ParamTypes, QualType *FunctionType, + TemplateDeductionInfo &Info) { FunctionDecl *Function = FunctionTemplate->getTemplatedDecl(); TemplateParameterList *TemplateParams = FunctionTemplate->getTemplateParameters(); @@ -3123,7 +3146,7 @@ // declaration order of their corresponding template-parameters. The // template argument list shall not specify more template-arguments than // there are corresponding template-parameters. - SmallVector Builder; + SmallVector SugaredBuilder, CanonicalBuilder; // Enter a new template instantiation context where we check the // explicitly-specified template arguments against this function template, @@ -3136,9 +3159,11 @@ return TDK_InstantiationDepth; if (CheckTemplateArgumentList(FunctionTemplate, SourceLocation(), - ExplicitTemplateArgs, true, Builder, false) || + ExplicitTemplateArgs, true, SugaredBuilder, + CanonicalBuilder, + /*UpdateArgsWithConversions=*/false) || Trap.hasErrorOccurred()) { - unsigned Index = Builder.size(); + unsigned Index = SugaredBuilder.size(); if (Index >= TemplateParams->size()) return TDK_SubstitutionFailure; Info.Param = makeTemplateParameter(TemplateParams->getParam(Index)); @@ -3147,9 +3172,12 @@ // Form the template argument list from the explicitly-specified // template arguments. - TemplateArgumentList *ExplicitArgumentList - = TemplateArgumentList::CreateCopy(Context, Builder); - Info.setExplicitArgs(ExplicitArgumentList); + TemplateArgumentList *SugaredExplicitArgumentList = + TemplateArgumentList::CreateCopy(Context, SugaredBuilder); + TemplateArgumentList *CanonicalExplicitArgumentList = + TemplateArgumentList::CreateCopy(Context, CanonicalBuilder); + Info.setExplicitArgs(SugaredExplicitArgumentList, + CanonicalExplicitArgumentList); // Template argument deduction and the final substitution should be // done in the context of the templated declaration. Explicit @@ -3162,15 +3190,15 @@ // the explicit template arguments. They'll be used as part of deduction // for this template parameter pack. unsigned PartiallySubstitutedPackIndex = -1u; - if (!Builder.empty()) { - const TemplateArgument &Arg = Builder.back(); + if (!CanonicalBuilder.empty()) { + const TemplateArgument &Arg = CanonicalBuilder.back(); if (Arg.getKind() == TemplateArgument::Pack) { - auto *Param = TemplateParams->getParam(Builder.size() - 1); + auto *Param = TemplateParams->getParam(CanonicalBuilder.size() - 1); // If this is a fully-saturated fixed-size pack, it should be // fully-substituted, not partially-substituted. Optional Expansions = getExpandedPackSize(Param); if (!Expansions || Arg.pack_size() < *Expansions) { - PartiallySubstitutedPackIndex = Builder.size() - 1; + PartiallySubstitutedPackIndex = CanonicalBuilder.size() - 1; CurrentInstantiationScope->SetPartiallySubstitutedPack( Param, Arg.pack_begin(), Arg.pack_size()); } @@ -3191,10 +3219,12 @@ // return type, substitute it after the arguments to ensure we substitute // in lexical order. if (Proto->hasTrailingReturn()) { - if (SubstParmTypes(Function->getLocation(), Function->parameters(), - Proto->getExtParameterInfosOrNull(), - MultiLevelTemplateArgumentList(*ExplicitArgumentList), - ParamTypes, /*params*/ nullptr, ExtParamInfos)) + if (SubstParmTypes( + Function->getLocation(), Function->parameters(), + Proto->getExtParameterInfosOrNull(), + MultiLevelTemplateArgumentList( + FunctionTemplate, CanonicalExplicitArgumentList->asArray()), + ParamTypes, /*params*/ nullptr, ExtParamInfos)) return TDK_SubstitutionFailure; } @@ -3217,10 +3247,11 @@ CXXThisScopeRAII ThisScope(*this, ThisContext, ThisTypeQuals, getLangOpts().CPlusPlus11); - ResultType = - SubstType(Proto->getReturnType(), - MultiLevelTemplateArgumentList(*ExplicitArgumentList), - Function->getTypeSpecStartLoc(), Function->getDeclName()); + ResultType = SubstType( + Proto->getReturnType(), + MultiLevelTemplateArgumentList( + FunctionTemplate, CanonicalExplicitArgumentList->asArray()), + Function->getTypeSpecStartLoc(), Function->getDeclName()); if (ResultType.isNull() || Trap.hasErrorOccurred()) return TDK_SubstitutionFailure; // CUDA: Kernel function must have 'void' return type. @@ -3235,10 +3266,12 @@ // Instantiate the types of each of the function parameters given the // explicitly-specified template arguments if we didn't do so earlier. if (!Proto->hasTrailingReturn() && - SubstParmTypes(Function->getLocation(), Function->parameters(), - Proto->getExtParameterInfosOrNull(), - MultiLevelTemplateArgumentList(*ExplicitArgumentList), - ParamTypes, /*params*/ nullptr, ExtParamInfos)) + SubstParmTypes( + Function->getLocation(), Function->parameters(), + Proto->getExtParameterInfosOrNull(), + MultiLevelTemplateArgumentList( + FunctionTemplate, CanonicalExplicitArgumentList->asArray()), + ParamTypes, /*params*/ nullptr, ExtParamInfos)) return TDK_SubstitutionFailure; if (FunctionType) { @@ -3252,7 +3285,8 @@ if (getLangOpts().CPlusPlus17 && SubstExceptionSpec( Function->getLocation(), EPI.ExceptionSpec, ExceptionStorage, - MultiLevelTemplateArgumentList(*ExplicitArgumentList))) + MultiLevelTemplateArgumentList( + FunctionTemplate, CanonicalExplicitArgumentList->asArray()))) return TDK_SubstitutionFailure; *FunctionType = BuildFunctionType(ResultType, ParamTypes, @@ -3274,8 +3308,8 @@ // parameter pack, however, will be set to NULL since the deduction // mechanism handles the partially-substituted argument pack directly. Deduced.reserve(TemplateParams->size()); - for (unsigned I = 0, N = ExplicitArgumentList->size(); I != N; ++I) { - const TemplateArgument &Arg = ExplicitArgumentList->get(I); + for (unsigned I = 0, N = SugaredExplicitArgumentList->size(); I != N; ++I) { + const TemplateArgument &Arg = SugaredExplicitArgumentList->get(I); if (I == PartiallySubstitutedPackIndex) Deduced.push_back(DeducedTemplateArgument()); else @@ -3463,11 +3497,11 @@ // C++ [temp.deduct.type]p2: // [...] or if any template argument remains neither deduced nor // explicitly specified, template argument deduction fails. - SmallVector Builder; + SmallVector SugaredBuilder, CanonicalBuilder; if (auto Result = ConvertDeducedTemplateArguments( - *this, FunctionTemplate, /*IsDeduced*/true, Deduced, Info, Builder, - CurrentInstantiationScope, NumExplicitlySpecified, - PartialOverloading)) + *this, FunctionTemplate, /*IsDeduced*/ true, Deduced, Info, + SugaredBuilder, CanonicalBuilder, CurrentInstantiationScope, + NumExplicitlySpecified, PartialOverloading)) return Result; // C++ [temp.deduct.call]p10: [DR1391] @@ -3483,16 +3517,19 @@ return TDK_NonDependentConversionFailure; // Form the template argument list from the deduced template arguments. - TemplateArgumentList *DeducedArgumentList - = TemplateArgumentList::CreateCopy(Context, Builder); - Info.reset(DeducedArgumentList); + TemplateArgumentList *SugaredDeducedArgumentList = + TemplateArgumentList::CreateCopy(Context, SugaredBuilder); + TemplateArgumentList *CanonicalDeducedArgumentList = + TemplateArgumentList::CreateCopy(Context, CanonicalBuilder); + Info.reset(SugaredDeducedArgumentList, CanonicalDeducedArgumentList); // Substitute the deduced template arguments into the function template // declaration to produce the function template specialization. DeclContext *Owner = FunctionTemplate->getDeclContext(); if (FunctionTemplate->getFriendObjectKind()) Owner = FunctionTemplate->getLexicalDeclContext(); - MultiLevelTemplateArgumentList SubstArgs(*DeducedArgumentList); + MultiLevelTemplateArgumentList SubstArgs( + FunctionTemplate, CanonicalDeducedArgumentList->asArray()); Specialization = cast_or_null( SubstDecl(FunctionTemplate->getTemplatedDecl(), Owner, SubstArgs)); if (!Specialization || Specialization->isInvalidDecl()) @@ -3503,9 +3540,10 @@ // If the template argument list is owned by the function template // specialization, release it. - if (Specialization->getTemplateSpecializationArgs() == DeducedArgumentList && + if (Specialization->getTemplateSpecializationArgs() == + CanonicalDeducedArgumentList && !Trap.hasErrorOccurred()) - Info.take(); + Info.takeCanonical(); // There may have been an error that did not prevent us from constructing a // declaration. Mark the declaration invalid and return with a substitution @@ -3524,13 +3562,16 @@ // ([temp.constr.constr]). If the constraints are not satisfied, type // deduction fails. if (!PartialOverloading || - (Builder.size() == FunctionTemplate->getTemplateParameters()->size())) { - if (CheckInstantiatedFunctionTemplateConstraints(Info.getLocation(), - Specialization, Builder, Info.AssociatedConstraintsSatisfaction)) + (CanonicalBuilder.size() == + FunctionTemplate->getTemplateParameters()->size())) { + if (CheckInstantiatedFunctionTemplateConstraints( + Info.getLocation(), Specialization, CanonicalBuilder, + Info.AssociatedConstraintsSatisfaction)) return TDK_MiscellaneousDeductionFailure; if (!Info.AssociatedConstraintsSatisfaction.IsSatisfied) { - Info.reset(TemplateArgumentList::CreateCopy(Context, Builder)); + Info.reset(Info.takeSugared(), + TemplateArgumentList::CreateCopy(Context, CanonicalBuilder)); return TDK_ConstraintsNotSatisfied; } } @@ -3598,12 +3639,18 @@ /// Gets the type of a function for template-argument-deducton /// purposes when it's considered as part of an overload set. static QualType GetTypeOfFunction(Sema &S, const OverloadExpr::FindResult &R, - FunctionDecl *Fn) { + FunctionDecl *Fn, + const TemplateArgumentListInfo *Args) { // We may need to deduce the return type of the function now. if (S.getLangOpts().CPlusPlus14 && Fn->getReturnType()->isUndeducedType() && S.DeduceReturnType(Fn, R.Expression->getExprLoc(), /*Diagnose*/ false)) return {}; + // FIXME: get SS. + QualType FT = Fn->getType(); + if (Args) + FT = S.resugar(CXXScopeSpec(), Fn, Args->arguments(), FT); + if (CXXMethodDecl *Method = dyn_cast(Fn)) if (Method->isInstance()) { // An instance method that's referenced in a form that doesn't @@ -3611,12 +3658,14 @@ if (!R.HasFormOfMemberPointer) return {}; - return S.Context.getMemberPointerType(Fn->getType(), - S.Context.getTypeDeclType(Method->getParent()).getTypePtr()); + // FIXME: resugar the class type here. + return S.Context.getMemberPointerType( + FT, S.Context.getTypeDeclType(Method->getParent()).getTypePtr()); } - if (!R.IsAddressOfOperand) return Fn->getType(); - return S.Context.getPointerType(Fn->getType()); + if (!R.IsAddressOfOperand) + return FT; + return S.Context.getPointerType(FT); } /// Apply the deduction rules for overload sets. @@ -3639,6 +3688,11 @@ if (R.IsAddressOfOperand) TDF |= TDF_IgnoreQualifiers; + // Gather the explicit template arguments, if any. + TemplateArgumentListInfo ExplicitTemplateArgs; + if (Ovl->hasExplicitTemplateArgs()) + Ovl->copyTemplateArgumentsInto(ExplicitTemplateArgs); + // C++0x [temp.deduct.call]p6: // When P is a function type, pointer to function type, or pointer // to member function type: @@ -3648,23 +3702,20 @@ !ParamType->isMemberFunctionPointerType()) { if (Ovl->hasExplicitTemplateArgs()) { // But we can still look for an explicit specialization. - if (FunctionDecl *ExplicitSpec - = S.ResolveSingleFunctionTemplateSpecialization(Ovl)) - return GetTypeOfFunction(S, R, ExplicitSpec); + if (FunctionDecl *ExplicitSpec = + S.ResolveSingleFunctionTemplateSpecialization( + Ovl, ExplicitTemplateArgs)) + return GetTypeOfFunction(S, R, ExplicitSpec, &ExplicitTemplateArgs); } DeclAccessPair DAP; if (FunctionDecl *Viable = S.resolveAddressOfSingleOverloadCandidate(Arg, DAP)) - return GetTypeOfFunction(S, R, Viable); + return GetTypeOfFunction(S, R, Viable, nullptr); return {}; } - // Gather the explicit template arguments, if any. - TemplateArgumentListInfo ExplicitTemplateArgs; - if (Ovl->hasExplicitTemplateArgs()) - Ovl->copyTemplateArgumentsInto(ExplicitTemplateArgs); QualType Match; for (UnresolvedSetIterator I = Ovl->decls_begin(), E = Ovl->decls_end(); I != E; ++I) { @@ -3688,7 +3739,7 @@ } FunctionDecl *Fn = cast(D); - QualType ArgType = GetTypeOfFunction(S, R, Fn); + QualType ArgType = GetTypeOfFunction(S, R, Fn, &ExplicitTemplateArgs); if (ArgType.isNull()) continue; // Function-to-pointer conversion. @@ -4544,13 +4595,15 @@ for (unsigned I = 0, C = TypeLoc.getNumArgs(); I != C; ++I) TemplateArgs.addArgument(TypeLoc.getArgLoc(I)); - llvm::SmallVector Converted; + llvm::SmallVector SugaredConverted, CanonicalConverted; if (S.CheckTemplateArgumentList(Concept, SourceLocation(), TemplateArgs, - /*PartialTemplateArgs=*/false, Converted)) + /*PartialTemplateArgs=*/false, + SugaredConverted, CanonicalConverted)) return true; - if (S.CheckConstraintSatisfaction(Concept, {Concept->getConstraintExpr()}, - Converted, TypeLoc.getLocalSourceRange(), - Satisfaction)) + // FIXME: use SugaredConverted. + if (S.CheckConstraintSatisfaction( + Concept, {Concept->getConstraintExpr()}, CanonicalConverted, + TypeLoc.getLocalSourceRange(), Satisfaction)) return true; if (!Satisfaction.IsSatisfied) { std::string Buf; @@ -5317,7 +5370,7 @@ AtLeastAsSpecialized = !FinishTemplateArgumentDeduction( S, P2, /*IsPartialOrdering=*/true, TemplateArgumentList(TemplateArgumentList::OnStack, - TST1->template_arguments()), + TST1->getConvertedArguments()), Deduced, Info); }); return AtLeastAsSpecialized; @@ -5400,9 +5453,9 @@ " the same template."); TemplateName Name(PS1->getSpecializedTemplate()); TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name); - QualType PT1 = Context.getTemplateSpecializationType( + QualType PT1 = Context.getCanonicalTemplateSpecializationType( CanonTemplate, PS1->getTemplateArgs().asArray()); - QualType PT2 = Context.getTemplateSpecializationType( + QualType PT2 = Context.getCanonicalTemplateSpecializationType( CanonTemplate, PS2->getTemplateArgs().asArray()); TemplateDeductionInfo Info(Loc); @@ -5436,13 +5489,18 @@ SmallVector PrimaryArgs; Context.getInjectedTemplateArgs(Primary->getTemplateParameters(), PrimaryArgs); + Context.getCanonicalTemplateArguments(PrimaryArgs, PrimaryArgs); + + SmallVector SpecArgs; + Context.getCanonicalTemplateArguments(Spec->getTemplateArgs().asArray(), + SpecArgs); TemplateName CanonTemplate = Context.getCanonicalTemplateName(TemplateName(Primary)); - QualType PrimaryT = Context.getTemplateSpecializationType( + QualType PrimaryT = Context.getCanonicalTemplateSpecializationType( CanonTemplate, PrimaryArgs); - QualType PartialT = Context.getTemplateSpecializationType( - CanonTemplate, Spec->getTemplateArgs().asArray()); + QualType PartialT = + Context.getCanonicalTemplateSpecializationType(CanonTemplate, SpecArgs); if (!isAtLeastAsSpecializedAs(*this, PartialT, PrimaryT, Primary, Info)) return false; @@ -5485,6 +5543,7 @@ // template parameters from the respective function template SmallVector AArgs; Context.getInjectedTemplateArgs(A, AArgs); + Context.getCanonicalTemplateArguments(AArgs, AArgs); // Check P's arguments against A's parameter list. This will fill in default // template arguments as needed. AArgs are already correct by construction. @@ -5495,6 +5554,7 @@ SFINAETrap Trap(*this); Context.getInjectedTemplateArgs(P, PArgs); + Context.getCanonicalTemplateArguments(PArgs, PArgs); TemplateArgumentListInfo PArgList(P->getLAngleLoc(), P->getRAngleLoc()); for (unsigned I = 0, N = P->size(); I != N; ++I) { @@ -5513,13 +5573,15 @@ // C++1z [temp.arg.template]p3: // If the rewrite produces an invalid type, then P is not at least as // specialized as A. - if (CheckTemplateArgumentList(AArg, Loc, PArgList, false, PArgs) || + SmallVector SugaredPArgs; + if (CheckTemplateArgumentList(AArg, Loc, PArgList, false, SugaredPArgs, + PArgs) || Trap.hasErrorOccurred()) return false; } - QualType AType = Context.getTemplateSpecializationType(X, AArgs); - QualType PType = Context.getTemplateSpecializationType(X, PArgs); + QualType AType = Context.getCanonicalTemplateSpecializationType(X, AArgs); + QualType PType = Context.getCanonicalTemplateSpecializationType(X, PArgs); // ... the function template corresponding to P is at least as specialized // as the function template corresponding to A according to the partial @@ -5791,9 +5853,8 @@ case Type::SubstTemplateTypeParmPack: { const SubstTemplateTypeParmPackType *Subst = cast(T); - MarkUsedTemplateParameters(Ctx, - QualType(Subst->getReplacedParameter(), 0), - OnlyDeduced, Depth, Used); + if (Subst->getReplacedTemplateParam()->getDepth() == Depth) + Used[Subst->getIndex()] = true; MarkUsedTemplateParameters(Ctx, Subst->getArgumentPack(), OnlyDeduced, Depth, Used); break; @@ -5813,13 +5874,11 @@ // 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 (OnlyDeduced && - hasPackExpansionBeforeEnd(Spec->template_arguments())) + if (OnlyDeduced && hasPackExpansionBeforeEnd(Spec->getConvertedArguments())) break; - for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I) - MarkUsedTemplateParameters(Ctx, Spec->getArg(I), OnlyDeduced, Depth, - Used); + for (const TemplateArgument &Arg : Spec->getConvertedArguments()) + MarkUsedTemplateParameters(Ctx, Arg, OnlyDeduced, Depth, Used); break; } 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 @@ -64,7 +64,8 @@ MultiLevelTemplateArgumentList Result; if (Innermost) - Result.addOuterTemplateArguments(Innermost); + Result.addOuterTemplateArguments(const_cast(D), + Innermost->asArray()); const auto *Ctx = dyn_cast(D); if (!Ctx) { @@ -80,8 +81,6 @@ !isa(Spec)) return Result; - Result.addOuterTemplateArguments(&Spec->getTemplateInstantiationArgs()); - // If this variable template specialization was instantiated from a // specialized member that is a variable template, we're done. assert(Spec->getSpecializedTemplate() && "No variable template?"); @@ -90,10 +89,14 @@ = Spec->getSpecializedTemplateOrPartial(); if (VarTemplatePartialSpecializationDecl *Partial = Specialized.dyn_cast()) { + Result.addOuterTemplateArguments( + Partial, Spec->getTemplateInstantiationArgs().asArray()); if (Partial->isMemberSpecialization()) return Result; } else { VarTemplateDecl *Tmpl = Specialized.get(); + Result.addOuterTemplateArguments( + Tmpl, Spec->getTemplateInstantiationArgs().asArray()); if (Tmpl->isMemberSpecialization()) return Result; } @@ -123,7 +126,9 @@ !isa(Spec)) break; - Result.addOuterTemplateArguments(&Spec->getTemplateInstantiationArgs()); + Result.addOuterTemplateArguments( + const_cast(Spec), + Spec->getTemplateInstantiationArgs().asArray()); // If this class template specialization was instantiated from a // specialized member that is a class template, we're done. @@ -146,7 +151,8 @@ } else if (const TemplateArgumentList *TemplateArgs = Function->getTemplateSpecializationArgs()) { // Add the template arguments for this specialization. - Result.addOuterTemplateArguments(TemplateArgs); + Result.addOuterTemplateArguments(const_cast(Function), + TemplateArgs->asArray()); // If this function was instantiated from a specialized member that is // a function template, we're done. @@ -1637,13 +1643,15 @@ // Type=char)), // Type=decltype(2))) // The call to CheckTemplateArgument here produces the ImpCast. - TemplateArgument Converted; - if (SemaRef.CheckTemplateArgument(E->getParameter(), SubstType, - SubstReplacement.get(), - Converted).isInvalid()) + TemplateArgument SugaredConverted, CanonicalConverted; + if (SemaRef + .CheckTemplateArgument(E->getParameter(), SubstType, + SubstReplacement.get(), SugaredConverted, + CanonicalConverted, Sema::CTAK_Specified) + .isInvalid()) return true; - return transformNonTypeTemplateParmRef(E->getParameter(), - E->getExprLoc(), Converted); + return transformNonTypeTemplateParmRef(E->getParameter(), E->getExprLoc(), + CanonicalConverted); } ExprResult TemplateInstantiator::RebuildVarDeclRefExpr(VarDecl *PD, @@ -1778,6 +1786,9 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB, TemplateTypeParmTypeLoc TL) { const TemplateTypeParmType *T = TL.getTypePtr(); + TemplateTypeParmDecl *NewTTPDecl = cast_or_null( + TransformDecl(TL.getNameLoc(), T->getDecl())); + if (T->getDepth() < TemplateArgs.getNumLevels()) { // Replace the template type parameter with its corresponding // template argument. @@ -1813,6 +1824,8 @@ return NewT; } + Decl *ReplacedDecl = TemplateArgs.getReplacedDecl(T->getDepth()); + Optional PackIndex; if (T->isParameterPack()) { assert(Arg.getKind() == TemplateArgument::Pack && @@ -1822,8 +1835,8 @@ // We have the template argument pack, but we're not expanding the // enclosing pack expansion yet. Just save the template argument // pack for later substitution. - QualType Result - = getSema().Context.getSubstTemplateTypeParmPackType(T, Arg); + QualType Result = getSema().Context.getSubstTemplateTypeParmPackType( + ReplacedDecl, T->getIndex(), Arg); SubstTemplateTypeParmPackTypeLoc NewTL = TLB.push(Result); NewTL.setNameLoc(TL.getNameLoc()); @@ -1841,7 +1854,7 @@ // TODO: only do this uniquing once, at the start of instantiation. QualType Result = getSema().Context.getSubstTemplateTypeParmType( - T, Replacement, PackIndex); + Replacement, ReplacedDecl, T->getIndex(), PackIndex); SubstTemplateTypeParmTypeLoc NewTL = TLB.push(Result); NewTL.setNameLoc(TL.getNameLoc()); @@ -1852,11 +1865,6 @@ // the template parameter list of a member template inside the // template we are instantiating). Create a new template type // parameter with the template "level" reduced by one. - TemplateTypeParmDecl *NewTTPDecl = nullptr; - if (TemplateTypeParmDecl *OldTTPDecl = T->getDecl()) - NewTTPDecl = cast_or_null( - TransformDecl(TL.getNameLoc(), OldTTPDecl)); - QualType Result = getSema().Context.getTemplateTypeParmType( T->getDepth() - TemplateArgs.getNumSubstitutedLevels(), T->getIndex(), T->isParameterPack(), NewTTPDecl); @@ -1865,26 +1873,32 @@ return Result; } -QualType -TemplateInstantiator::TransformSubstTemplateTypeParmPackType( - TypeLocBuilder &TLB, - SubstTemplateTypeParmPackTypeLoc TL) { +QualType TemplateInstantiator::TransformSubstTemplateTypeParmPackType( + TypeLocBuilder &TLB, SubstTemplateTypeParmPackTypeLoc TL) { + const SubstTemplateTypeParmPackType *T = TL.getTypePtr(); + + Decl *NewReplaced = TransformDecl(TL.getNameLoc(), T->getReplacedDecl()); + if (getSema().ArgumentPackSubstitutionIndex == -1) { // We aren't expanding the parameter pack, so just return ourselves. - SubstTemplateTypeParmPackTypeLoc NewTL - = TLB.push(TL.getType()); + QualType Result = TL.getType(); + if (NewReplaced != T->getReplacedDecl()) + Result = getSema().Context.getSubstTemplateTypeParmPackType( + NewReplaced, T->getIndex(), T->getArgumentPack()); + SubstTemplateTypeParmPackTypeLoc NewTL = + TLB.push(Result); NewTL.setNameLoc(TL.getNameLoc()); - return TL.getType(); + return Result; } - TemplateArgument Arg = TL.getTypePtr()->getArgumentPack(); - Arg = getPackSubstitutedTemplateArgument(getSema(), Arg); + TemplateArgument Arg = + getPackSubstitutedTemplateArgument(getSema(), T->getArgumentPack()); QualType Result = getSema().Context.getSubstTemplateTypeParmType( - TL.getTypePtr()->getReplacedParameter(), Arg.getAsType(), + Arg.getAsType(), NewReplaced, T->getIndex(), getSema().ArgumentPackSubstitutionIndex); - SubstTemplateTypeParmTypeLoc NewTL - = TLB.push(Result); + SubstTemplateTypeParmTypeLoc NewTL = + TLB.push(Result); NewTL.setNameLoc(TL.getNameLoc()); return Result; } @@ -3131,7 +3145,7 @@ } else { Matched.push_back(PartialSpecMatchResult()); Matched.back().Partial = Partial; - Matched.back().Args = Info.take(); + Matched.back().Args = Info.takeCanonical(); } } 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 @@ -3691,12 +3691,10 @@ // Check that the template argument list is well-formed for this // class template. - SmallVector Converted; - if (SemaRef.CheckTemplateArgumentList(InstClassTemplate, - D->getLocation(), - InstTemplateArgs, - false, - Converted, + SmallVector SugaredConverted, CanonicalConverted; + if (SemaRef.CheckTemplateArgumentList(InstClassTemplate, D->getLocation(), + InstTemplateArgs, false, + SugaredConverted, CanonicalConverted, /*UpdateArgsWithConversions=*/true)) return nullptr; @@ -3704,7 +3702,7 @@ // in the member template's set of class template explicit specializations. void *InsertPos = nullptr; ClassTemplateSpecializationDecl *PrevDecl = - InstClassTemplate->findSpecialization(Converted, InsertPos); + InstClassTemplate->findSpecialization(CanonicalConverted, InsertPos); // Check whether we've already seen a conflicting instantiation of this // declaration (for instance, if there was a prior implicit instantiation). @@ -3742,7 +3740,7 @@ ClassTemplateSpecializationDecl *InstD = ClassTemplateSpecializationDecl::Create( SemaRef.Context, D->getTagKind(), Owner, D->getBeginLoc(), - D->getLocation(), InstClassTemplate, Converted, PrevDecl); + D->getLocation(), InstClassTemplate, CanonicalConverted, PrevDecl); // Add this partial specialization to the set of class template partial // specializations. @@ -3756,8 +3754,9 @@ // Build the canonical type that describes the converted template // arguments of the class template explicit specialization. QualType CanonType = SemaRef.Context.getTemplateSpecializationType( - TemplateName(InstClassTemplate), Converted, - SemaRef.Context.getRecordType(InstD)); + TemplateName(InstClassTemplate), + /*SpecifiedArgs=*/ArrayRef{}, CanonicalConverted, + /*CanonicalConverted=*/{}, SemaRef.Context.getRecordType(InstD)); // Build the fully-sugared type for this class template // specialization as the user wrote in the specialization @@ -3768,7 +3767,7 @@ // template arguments in the specialization. TypeSourceInfo *WrittenTy = SemaRef.Context.getTemplateSpecializationTypeInfo( TemplateName(InstClassTemplate), D->getLocation(), InstTemplateArgs, - CanonType); + SugaredConverted, /*CanonicalConverted=*/{}, CanonType); InstD->setAccess(D->getAccess()); InstD->setInstantiationOfMemberClass(D, TSK_ImplicitInstantiation); @@ -3818,16 +3817,17 @@ } // Check that the template argument list is well-formed for this template. - SmallVector Converted; + SmallVector SugaredConverted, CanonicalConverted; if (SemaRef.CheckTemplateArgumentList(InstVarTemplate, D->getLocation(), - VarTemplateArgsInfo, false, Converted, + VarTemplateArgsInfo, false, + SugaredConverted, CanonicalConverted, /*UpdateArgsWithConversions=*/true)) return nullptr; // Check whether we've already seen a declaration of this specialization. void *InsertPos = nullptr; VarTemplateSpecializationDecl *PrevDecl = - InstVarTemplate->findSpecialization(Converted, InsertPos); + InstVarTemplate->findSpecialization(CanonicalConverted, InsertPos); // Check whether we've already seen a conflicting instantiation of this // declaration (for instance, if there was a prior implicit instantiation). @@ -3839,7 +3839,7 @@ return nullptr; return VisitVarTemplateSpecializationDecl( - InstVarTemplate, D, VarTemplateArgsInfo, Converted, PrevDecl); + InstVarTemplate, D, VarTemplateArgsInfo, CanonicalConverted, PrevDecl); } Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl( @@ -4087,33 +4087,25 @@ // Check that the template argument list is well-formed for this // class template. - SmallVector Converted; - if (SemaRef.CheckTemplateArgumentList(ClassTemplate, - PartialSpec->getLocation(), - InstTemplateArgs, - false, - Converted)) + SmallVector SugaredConverted, CanonicalConverted; + if (SemaRef.CheckTemplateArgumentList( + ClassTemplate, PartialSpec->getLocation(), InstTemplateArgs, + /*PartialTemplateArgs=*/false, SugaredConverted, CanonicalConverted)) return nullptr; // Check these arguments are valid for a template partial specialization. if (SemaRef.CheckTemplatePartialSpecializationArgs( PartialSpec->getLocation(), ClassTemplate, InstTemplateArgs.size(), - Converted)) + CanonicalConverted)) return nullptr; // Figure out where to insert this class template partial specialization // in the member template's set of class template partial specializations. void *InsertPos = nullptr; - ClassTemplateSpecializationDecl *PrevDecl - = ClassTemplate->findPartialSpecialization(Converted, InstParams, + ClassTemplateSpecializationDecl *PrevDecl = + ClassTemplate->findPartialSpecialization(CanonicalConverted, InstParams, InsertPos); - // Build the canonical type that describes the converted template - // arguments of the class template partial specialization. - QualType CanonType - = SemaRef.Context.getTemplateSpecializationType(TemplateName(ClassTemplate), - Converted); - // Build the fully-sugared type for this class template // specialization as the user wrote in the specialization // itself. This means that we'll pretty-print the type retrieved @@ -4121,12 +4113,9 @@ // actually wrote the specialization, rather than formatting the // name based on the "canonical" representation used to store the // template arguments in the specialization. - TypeSourceInfo *WrittenTy - = SemaRef.Context.getTemplateSpecializationTypeInfo( - TemplateName(ClassTemplate), - PartialSpec->getLocation(), - InstTemplateArgs, - CanonType); + TypeSourceInfo *WrittenTy = SemaRef.Context.getTemplateSpecializationTypeInfo( + TemplateName(ClassTemplate), PartialSpec->getLocation(), InstTemplateArgs, + SugaredConverted, CanonicalConverted); if (PrevDecl) { // We've already seen a partial specialization with the same template @@ -4157,7 +4146,8 @@ ClassTemplatePartialSpecializationDecl::Create( SemaRef.Context, PartialSpec->getTagKind(), Owner, PartialSpec->getBeginLoc(), PartialSpec->getLocation(), InstParams, - ClassTemplate, Converted, InstTemplateArgs, CanonType, nullptr); + ClassTemplate, CanonicalConverted, InstTemplateArgs, + WrittenTy->getType(), nullptr); // Substitute the nested name specifier, if any. if (SubstQualifier(PartialSpec, InstPartialSpec)) return nullptr; @@ -4214,27 +4204,24 @@ // Check that the template argument list is well-formed for this // class template. - SmallVector Converted; - if (SemaRef.CheckTemplateArgumentList(VarTemplate, PartialSpec->getLocation(), - InstTemplateArgs, false, Converted)) + SmallVector SugaredConverted, CanonicalConverted; + if (SemaRef.CheckTemplateArgumentList( + VarTemplate, PartialSpec->getLocation(), InstTemplateArgs, + /*PartialTemplateArgs=*/false, SugaredConverted, CanonicalConverted)) return nullptr; // Check these arguments are valid for a template partial specialization. if (SemaRef.CheckTemplatePartialSpecializationArgs( PartialSpec->getLocation(), VarTemplate, InstTemplateArgs.size(), - Converted)) + CanonicalConverted)) return nullptr; // Figure out where to insert this variable template partial specialization // in the member template's set of variable template partial specializations. void *InsertPos = nullptr; VarTemplateSpecializationDecl *PrevDecl = - VarTemplate->findPartialSpecialization(Converted, InstParams, InsertPos); - - // Build the canonical type that describes the converted template - // arguments of the variable template partial specialization. - QualType CanonType = SemaRef.Context.getTemplateSpecializationType( - TemplateName(VarTemplate), Converted); + VarTemplate->findPartialSpecialization(CanonicalConverted, InstParams, + InsertPos); // Build the fully-sugared type for this variable template // specialization as the user wrote in the specialization @@ -4245,7 +4232,7 @@ // template arguments in the specialization. TypeSourceInfo *WrittenTy = SemaRef.Context.getTemplateSpecializationTypeInfo( TemplateName(VarTemplate), PartialSpec->getLocation(), InstTemplateArgs, - CanonType); + SugaredConverted, CanonicalConverted); if (PrevDecl) { // We've already seen a partial specialization with the same template @@ -4290,7 +4277,8 @@ VarTemplatePartialSpecializationDecl::Create( SemaRef.Context, Owner, PartialSpec->getInnerLocStart(), PartialSpec->getLocation(), InstParams, VarTemplate, DI->getType(), - DI, PartialSpec->getStorageClass(), Converted, InstTemplateArgs); + DI, PartialSpec->getStorageClass(), CanonicalConverted, + InstTemplateArgs); // Substitute the nested name specifier, if any. if (SubstQualifier(PartialSpec, InstPartialSpec)) @@ -4767,7 +4755,7 @@ return nullptr; ContextRAII SavedContext(*this, FD); - MultiLevelTemplateArgumentList MArgs(*Args); + MultiLevelTemplateArgumentList MArgs(FTD, Args->asArray()); return cast_or_null(SubstDecl(FD, FD->getParent(), MArgs)); } @@ -4963,6 +4951,7 @@ Rec->isLocalClass() && !Function->isFunctionTemplateSpecialization(); LocalInstantiationScope Scope(*this, MergeWithParentScope); + auto RebuildTypeSourceInfoForDefaultSpecialMembers = [&]() { // Special members might get their TypeSourceInfo set up w.r.t the // PatternDecl context, in which case parameters could still be pointing @@ -5113,9 +5102,6 @@ if (Inst.isInvalid()) return nullptr; - MultiLevelTemplateArgumentList TemplateArgLists; - TemplateArgLists.addOuterTemplateArguments(&TemplateArgList); - // Instantiate the first declaration of the variable template: for a partial // specialization of a static data member template, the first declaration may // or may not be the declaration in the class; if it's in the class, we want @@ -5134,7 +5120,8 @@ if (!IsMemberSpec) FromVar = FromVar->getFirstDecl(); - MultiLevelTemplateArgumentList MultiLevelList(TemplateArgList); + MultiLevelTemplateArgumentList MultiLevelList(VarTemplate, + TemplateArgList.asArray()); TemplateDeclInstantiator Instantiator(*this, FromVar->getDeclContext(), MultiLevelList); @@ -6167,7 +6154,8 @@ Args.addArgument( getTrivialTemplateArgumentLoc(UnpackedArg, QualType(), Loc)); } - QualType T = CheckTemplateIdType(TemplateName(TD), Loc, Args); + QualType T = + CheckTemplateIdType(CXXScopeSpec(), TemplateName(TD), Loc, Args); if (T.isNull()) return nullptr; auto *SubstRecord = T->getAsCXXRecordDecl(); 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 @@ -9118,6 +9118,56 @@ return Context.getTypeOfExprType(E); } +static QualType getSameReferencedType(ASTContext &Context, QualType VT, + QualType ET) { + assert(!ET->isReferenceType()); + if (const auto *VTL = VT->getAs()) + ET = Context.getLValueReferenceType(ET, VTL->isSpelledAsLValue()); + else if (VT->isRValueReferenceType()) + ET = Context.getRValueReferenceType(ET); + + if (!Context.hasSameUnqualifiedType(ET, VT)) { + ET.dump(); + VT.dump(); + assert(false && "!hasSameUnqualifiedType"); + } + + Qualifiers ToAdd = VT.getQualifiers(), ToRemove = ET.getQualifiers(); + (void)Qualifiers::removeCommonQualifiers(ToAdd, ToRemove); + + SplitQualType Split = ET.split(); + while (!ToRemove.empty()) { + (void)Qualifiers::removeCommonQualifiers(Split.Quals, ToRemove); + if (ToRemove.empty()) + break; + QualType Next; + switch (ET->getTypeClass()) { +#define ABSTRACT_TYPE(Class, Parent) +#define TYPE(Class, Parent) \ + case Type::Class: { \ + const auto *ty = cast(ET); \ + if (!ty->isSugared()) \ + goto done; \ + Next = ty->desugar(); \ + break; \ + } +#include "clang/AST/TypeNodes.inc" + } + Split = Next.split(); + } +done: + assert(ToRemove.empty()); + Split.Quals += ToAdd; + ET = Context.getQualifiedType(Split); + + if (!Context.hasSameType(ET, VT)) { + ET.dump(); + VT.dump(); + assert(false && "!hasSameType"); + } + return ET; +} + /// 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. @@ -9150,18 +9200,20 @@ // We apply the same rules for Objective-C ivar and property references. if (const auto *DRE = dyn_cast(IDExpr)) { const ValueDecl *VD = DRE->getDecl(); - QualType T = VD->getType(); + QualType T = getSameReferencedType(Context, VD->getType(), DRE->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(); + return getSameReferencedType(Context, VD->getType(), ME->getType()); } else if (const auto *IR = dyn_cast(IDExpr)) { + // FIXME: Sugar these. Breaks Modules/odr_hash.mm. return IR->getDecl()->getType(); } else if (const auto *PR = dyn_cast(IDExpr)) { if (PR->isExplicitProperty()) - return PR->getExplicitProperty()->getType(); + return getSameReferencedType( + Context, PR->getExplicitProperty()->getType(), PR->getType()); } else if (const auto *PE = dyn_cast(IDExpr)) { return PE->getType(); } 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(const CXXScopeSpec &SS, + TemplateName Template, SourceLocation TemplateLoc, TemplateArgumentListInfo &Args); @@ -1061,15 +1062,14 @@ // If it's still dependent, make a dependent specialization. if (InstName.getAsDependentTemplateName()) - return SemaRef.Context.getDependentTemplateSpecializationType(Keyword, - QualifierLoc.getNestedNameSpecifier(), - Name, - Args); + return SemaRef.Context.getDependentTemplateSpecializationType( + Keyword, QualifierLoc.getNestedNameSpecifier(), Name, + Args.arguments()); // Otherwise, make an elaborated type wrapping a non-dependent // specialization. - QualType T = - getDerived().RebuildTemplateSpecializationType(InstName, NameLoc, Args); + QualType T = getDerived().RebuildTemplateSpecializationType(SS, InstName, + NameLoc, Args); if (T.isNull()) return QualType(); return SemaRef.Context.getElaboratedType( @@ -2674,6 +2674,9 @@ NamedDecl *FirstQualifierInScope) { ExprResult BaseResult = getSema().PerformMemberExprBaseConversion(Base, isArrow); + CXXScopeSpec SS; + SS.Adopt(QualifierLoc); + if (!Member->getDeclName()) { // We have a reference to an unnamed field. This is always the // base of an anonymous struct/union member access, i.e. the @@ -2689,15 +2692,14 @@ return ExprError(); Base = BaseResult.get(); - CXXScopeSpec EmptySS; + // FIXME: resugar. return getSema().BuildFieldReferenceExpr( - Base, isArrow, OpLoc, EmptySS, cast(Member), - DeclAccessPair::make(FoundDecl, FoundDecl->getAccess()), MemberNameInfo); + Base, isArrow, OpLoc, NestedNameSpecifierLoc(), + cast(Member), Member->getType(), + DeclAccessPair::make(FoundDecl, FoundDecl->getAccess()), + MemberNameInfo); } - CXXScopeSpec SS; - SS.Adopt(QualifierLoc); - Base = BaseResult.get(); QualType BaseType = Base->getType(); @@ -4854,8 +4856,8 @@ Replacement = SemaRef.Context.getQualifiedType( Replacement.getUnqualifiedType(), Qs); T = SemaRef.Context.getSubstTemplateTypeParmType( - SubstTypeParam->getReplacedParameter(), Replacement, - SubstTypeParam->getPackIndex()); + Replacement, SubstTypeParam->getReplacedDecl(), + SubstTypeParam->getIndex(), SubstTypeParam->getPackIndex()); } else if ((AutoTy = dyn_cast(T)) && AutoTy->isDeduced()) { // 'auto' types behave the same way as template parameters. QualType Deduced = AutoTy->getDeducedType(); @@ -4891,7 +4893,7 @@ return TL; TypeSourceInfo *TSI = - TransformTSIInObjectScope(TL, ObjectType, UnqualLookup, SS); + getDerived().TransformTSIInObjectScope(TL, ObjectType, UnqualLookup, SS); if (TSI) return TSI->getTypeLoc(); return TypeLoc(); @@ -4906,8 +4908,8 @@ if (getDerived().AlreadyTransformed(TSInfo->getType())) return TSInfo; - return TransformTSIInObjectScope(TSInfo->getTypeLoc(), ObjectType, - UnqualLookup, SS); + return getDerived().TransformTSIInObjectScope(TSInfo->getTypeLoc(), + ObjectType, UnqualLookup, SS); } template @@ -5511,7 +5513,8 @@ TypeLocBuilder &TLB, DependentAddressSpaceTypeLoc TL) { const DependentAddressSpaceType *T = TL.getTypePtr(); - QualType pointeeType = getDerived().TransformType(T->getPointeeType()); + QualType pointeeType = + getDerived().TransformType(TLB, TL.getPointeeTypeLoc()); if (pointeeType.isNull()) return QualType(); @@ -5544,9 +5547,8 @@ NewTL.setAttrNameLoc(TL.getAttrNameLoc()); } else { - TypeSourceInfo *DI = getSema().Context.getTrivialTypeSourceInfo( - Result, getDerived().getBaseLocation()); - TransformType(TLB, DI->getTypeLoc()); + // Result is just the pointee type with an extended qualifier added. + TLB.TypeWasModifiedSafely(Result); } return Result; @@ -6401,6 +6403,9 @@ SubstTemplateTypeParmTypeLoc TL) { const SubstTemplateTypeParmType *T = TL.getTypePtr(); + Decl *NewReplaced = + getDerived().TransformDecl(TL.getNameLoc(), T->getReplacedDecl()); + // Substitute into the replacement type, which itself might involve something // that needs to be transformed. This only tends to occur with default // template arguments of template template parameters. @@ -6412,7 +6417,7 @@ // Always canonicalize the replacement type. Replacement = SemaRef.Context.getCanonicalType(Replacement); QualType Result = SemaRef.Context.getSubstTemplateTypeParmType( - T->getReplacedParameter(), Replacement, T->getPackIndex()); + Replacement, NewReplaced, T->getIndex(), T->getPackIndex()); // Propagate type-source information. SubstTemplateTypeParmTypeLoc NewTL @@ -6681,19 +6686,29 @@ TemplateArgumentListInfo NewTemplateArgs; NewTemplateArgs.setLAngleLoc(TL.getLAngleLoc()); NewTemplateArgs.setRAngleLoc(TL.getRAngleLoc()); - typedef TemplateArgumentLocContainerIterator - ArgIterator; - if (getDerived().TransformTemplateArguments(ArgIterator(TL, 0), - ArgIterator(TL, TL.getNumArgs()), - NewTemplateArgs)) - return QualType(); + + const auto *T = cast(TL.getType()); + if (T->isCanonicalUnqualified()) { + ArrayRef ConvertedArgs = T->getConvertedArguments(); + using ArgIterator = + TemplateArgumentLocInventIterator; + if (getDerived().TransformTemplateArguments( + ArgIterator(*this, ConvertedArgs.begin()), + ArgIterator(*this, ConvertedArgs.end()), NewTemplateArgs)) + return QualType(); + } else { + using ArgIterator = + TemplateArgumentLocContainerIterator; + if (getDerived().TransformTemplateArguments( + ArgIterator(TL, 0), ArgIterator(TL, TL.getNumArgs()), + NewTemplateArgs)) + return QualType(); + } // 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( + CXXScopeSpec(), Template, TL.getTemplateNameLoc(), NewTemplateArgs); if (!Result.isNull()) { // Specializations of template template parameters are represented as @@ -6746,12 +6761,9 @@ // FIXME: maybe don't rebuild if all the template arguments are the same. if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) { - QualType Result - = getSema().Context.getDependentTemplateSpecializationType( - TL.getTypePtr()->getKeyword(), - DTN->getQualifier(), - DTN->getIdentifier(), - NewTemplateArgs); + QualType Result = getSema().Context.getDependentTemplateSpecializationType( + TL.getTypePtr()->getKeyword(), DTN->getQualifier(), + DTN->getIdentifier(), NewTemplateArgs.arguments()); DependentTemplateSpecializationTypeLoc NewTL = TLB.push(Result); @@ -6766,10 +6778,8 @@ return Result; } - QualType Result - = getDerived().RebuildTemplateSpecializationType(Template, - TL.getTemplateNameLoc(), - NewTemplateArgs); + QualType Result = getDerived().RebuildTemplateSpecializationType( + SS, Template, TL.getTemplateNameLoc(), NewTemplateArgs); if (!Result.isNull()) { /// FIXME: Wrap this in an elaborated-type-specifier? @@ -11071,8 +11081,7 @@ getSema().FpPragmaStack.CurrentValue = NewOverrides; } - return getDerived().RebuildCallExpr(Callee.get(), FakeLParenLoc, - Args, + return getDerived().RebuildCallExpr(Callee.get(), FakeLParenLoc, Args, E->getRParenLoc()); } @@ -14751,12 +14760,12 @@ return SemaRef.BuildUnaryTransformType(BaseType, UKind, Loc); } -template +template QualType TreeTransform::RebuildTemplateSpecializationType( - TemplateName Template, - SourceLocation TemplateNameLoc, - TemplateArgumentListInfo &TemplateArgs) { - return SemaRef.CheckTemplateIdType(Template, TemplateNameLoc, TemplateArgs); + const CXXScopeSpec &SS, TemplateName Template, + SourceLocation TemplateNameLoc, TemplateArgumentListInfo &TemplateArgs) { + return SemaRef.CheckTemplateIdType(SS, Template, TemplateNameLoc, + TemplateArgs); } template diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -6739,9 +6739,8 @@ TL.setRAngleLoc(readSourceLocation()); for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) TL.setArgLocInfo( - i, - Reader.readTemplateArgumentLocInfo( - TL.getTypePtr()->getArg(i).getKind())); + i, Reader.readTemplateArgumentLocInfo( + TL.getTypePtr()->getSpecifiedArguments()[i].getKind())); } void TypeLocReader::VisitParenTypeLoc(ParenTypeLoc TL) { @@ -8846,6 +8845,15 @@ TemplArgs.push_back(readTemplateArgument(Canonicalize)); } +const TemplateArgumentList * +ASTRecordReader::readTemplateArgumentList(bool Canonicalize) { + SmallVector Args; + readTemplateArgumentList(Args, Canonicalize); + if (Args.size() == 0) + return nullptr; + return TemplateArgumentList::CreateCopy(getContext(), Args); +} + /// Read a UnresolvedSet structure. void ASTRecordReader::readUnresolvedSet(LazyASTUnresolvedSet &Set) { unsigned NumDecls = readInt(); diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -2390,8 +2390,6 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarTemplateSpecializationDeclImpl( VarTemplateSpecializationDecl *D) { - RedeclarableResult Redecl = VisitVarDeclImpl(D); - ASTContext &C = Reader.getContext(); if (Decl *InstD = readDecl()) { if (auto *VTD = dyn_cast(InstD)) { @@ -2428,6 +2426,8 @@ D->SpecializationKind = (TemplateSpecializationKind)Record.readInt(); D->IsCompleteDefinition = Record.readInt(); + RedeclarableResult Redecl = VisitVarDeclImpl(D); + bool writtenAsCanonicalDecl = Record.readInt(); if (writtenAsCanonicalDecl) { auto *CanonPattern = readDeclAs(); diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -1027,6 +1027,7 @@ E->MemberExprBits.HadMultipleCandidates = Record.readInt(); E->MemberExprBits.NonOdrUseReason = Record.readInt(); E->MemberExprBits.OperatorLoc = Record.readSourceLocation(); + E->Deduced = Record.readTemplateArgumentList(); if (HasQualifier || HasFoundDecl) { DeclAccessPair FoundDecl; diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -1607,8 +1607,6 @@ VarTemplateSpecializationDecl *D) { RegisterTemplateSpecialization(D->getSpecializedTemplate(), D); - VisitVarDecl(D); - llvm::PointerUnion InstFrom = D->getSpecializedTemplateOrPartial(); if (Decl *InstFromD = InstFrom.dyn_cast()) { @@ -1629,6 +1627,9 @@ Record.AddSourceLocation(D->getPointOfInstantiation()); Record.push_back(D->getSpecializationKind()); Record.push_back(D->IsCompleteDefinition); + + VisitVarDecl(D); + Record.push_back(D->isCanonicalDecl()); if (D->isCanonicalDecl()) { diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -911,6 +911,10 @@ Record.push_back(E->hadMultipleCandidates()); Record.push_back(E->isNonOdrUse()); Record.AddSourceLocation(E->getOperatorLoc()); + if (E->Deduced) + Record.AddTemplateArgumentList(E->Deduced); + else + Record.push_back(0); if (HasFoundDecl) { DeclAccessPair FoundDecl = E->getFoundDecl(); diff --git a/clang/lib/StaticAnalyzer/Checkers/MismatchedIteratorChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MismatchedIteratorChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/MismatchedIteratorChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MismatchedIteratorChecker.cpp @@ -176,8 +176,10 @@ const auto *Param = Func->getParamDecl(J); const auto *ParamType = Param->getType()->getAs(); - if (!ParamType || - ParamType->getReplacedParameter()->getDecl() != TPDecl) + if (!ParamType) + continue; + const TemplateTypeParmDecl *D = ParamType->getReplacedTemplateParam(); + if (D != TPDecl) continue; if (LHS.isUndef()) { LHS = Call.getArgSVal(J); diff --git a/clang/lib/StaticAnalyzer/Checkers/PointerSortingChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PointerSortingChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/PointerSortingChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/PointerSortingChecker.cpp @@ -79,12 +79,9 @@ ); // Match only if the container has pointer-type elements. - auto IteratesPointerEltsM = hasArgument(0, - hasType(cxxRecordDecl(has( - fieldDecl(hasType(hasCanonicalType( - pointsTo(hasCanonicalType(pointerType())) - ))) - )))); + auto IteratesPointerEltsM = hasArgument( + 0, hasType(hasCanonicalType(hasDeclaration(cxxRecordDecl(has(fieldDecl( + hasType(hasCanonicalType(pointsTo(pointerType())))))))))); auto PointerSortM = traverse( TK_AsIs, diff --git a/clang/test/AST/ast-dump-openmp-begin-declare-variant_reference.cpp b/clang/test/AST/ast-dump-openmp-begin-declare-variant_reference.cpp --- a/clang/test/AST/ast-dump-openmp-begin-declare-variant_reference.cpp +++ b/clang/test/AST/ast-dump-openmp-begin-declare-variant_reference.cpp @@ -122,9 +122,8 @@ // CHECK-NEXT: | | | `-BuiltinType [[ADDR_8:0x[a-z0-9]*]] 'float' // CHECK-NEXT: | | |-CXXRecordDecl [[ADDR_9:0x[a-z0-9]*]] col:29 implicit struct remove_reference // CHECK-NEXT: | | `-TypedefDecl [[ADDR_10:0x[a-z0-9]*]] col:67 referenced type 'float':'float' -// CHECK-NEXT: | | `-SubstTemplateTypeParmType [[ADDR_11:0x[a-z0-9]*]] 'float' sugar -// CHECK-NEXT: | | |-TemplateTypeParmType [[ADDR_12:0x[a-z0-9]*]] '_Tp' dependent depth 0 index 0 -// CHECK-NEXT: | | | `-TemplateTypeParm [[ADDR_13:0x[a-z0-9]*]] '_Tp' +// CHECK-NEXT: | | `-SubstTemplateTypeParmType [[ADDR_11:0x[a-z0-9]*]] 'float' sugar class depth 0 index 0 _Tp +// CHECK-NEXT: | | |-ClassTemplateSpecialization [[ADDR_6]] 'remove_reference' // CHECK-NEXT: | | `-BuiltinType [[ADDR_8]] 'float' // CHECK-NEXT: | `-ClassTemplateSpecializationDecl [[ADDR_14:0x[a-z0-9]*]] col:29 struct remove_reference definition // CHECK-NEXT: | |-DefinitionData pass_in_registers empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init @@ -139,9 +138,8 @@ // CHECK-NEXT: | | `-BuiltinType [[ADDR_16:0x[a-z0-9]*]] 'short' // CHECK-NEXT: | |-CXXRecordDecl [[ADDR_17:0x[a-z0-9]*]] col:29 implicit struct remove_reference // CHECK-NEXT: | `-TypedefDecl [[ADDR_18:0x[a-z0-9]*]] col:67 referenced type 'short':'short' -// CHECK-NEXT: | `-SubstTemplateTypeParmType [[ADDR_19:0x[a-z0-9]*]] 'short' sugar -// CHECK-NEXT: | |-TemplateTypeParmType [[ADDR_12]] '_Tp' dependent depth 0 index 0 -// CHECK-NEXT: | | `-TemplateTypeParm [[ADDR_13]] '_Tp' +// CHECK-NEXT: | `-SubstTemplateTypeParmType [[ADDR_19:0x[a-z0-9]*]] 'short' sugar class depth 0 index 0 _Tp +// CHECK-NEXT: | |-ClassTemplateSpecialization [[ADDR_14]] 'remove_reference' // CHECK-NEXT: | `-BuiltinType [[ADDR_16]] 'short' // CHECK-NEXT: |-ClassTemplatePartialSpecializationDecl [[ADDR_20:0x[a-z0-9]*]] col:29 struct remove_reference definition // CHECK-NEXT: | |-DefinitionData empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init @@ -154,10 +152,10 @@ // CHECK-NEXT: | |-TemplateArgument type 'type-parameter-0-0 &' // CHECK-NEXT: | | `-LValueReferenceType [[ADDR_21:0x[a-z0-9]*]] 'type-parameter-0-0 &' dependent // CHECK-NEXT: | | `-TemplateTypeParmType [[ADDR_22:0x[a-z0-9]*]] 'type-parameter-0-0' dependent depth 0 index 0 -// CHECK-NEXT: | |-TemplateTypeParmDecl [[ADDR_13]] col:17 referenced class depth 0 index 0 _Tp +// CHECK-NEXT: | |-TemplateTypeParmDecl [[ADDR_13:0x[a-z0-9]*]] col:17 referenced class depth 0 index 0 _Tp // CHECK-NEXT: | |-CXXRecordDecl [[ADDR_23:0x[a-z0-9]*]] col:29 implicit struct remove_reference // CHECK-NEXT: | `-TypedefDecl [[ADDR_24:0x[a-z0-9]*]] col:67 type '_Tp' -// CHECK-NEXT: | `-TemplateTypeParmType [[ADDR_12]] '_Tp' dependent depth 0 index 0 +// CHECK-NEXT: | `-TemplateTypeParmType [[ADDR_12:0x[a-z0-9]*]] '_Tp' dependent depth 0 index 0 // CHECK-NEXT: | `-TemplateTypeParm [[ADDR_13]] '_Tp' // CHECK-NEXT: |-ClassTemplatePartialSpecializationDecl [[ADDR_25:0x[a-z0-9]*]] col:29 struct remove_reference definition // CHECK-NEXT: | |-DefinitionData empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init @@ -197,9 +195,8 @@ // CHECK-NEXT: | | | `-ElaboratedType [[ADDR_47:0x[a-z0-9]*]] 'typename remove_reference::type' sugar // CHECK-NEXT: | | | `-TypedefType [[ADDR_48:0x[a-z0-9]*]] 'remove_reference::type' sugar // CHECK-NEXT: | | | |-Typedef [[ADDR_10]] 'type' -// CHECK-NEXT: | | | `-SubstTemplateTypeParmType [[ADDR_11]] 'float' sugar -// CHECK-NEXT: | | | |-TemplateTypeParmType [[ADDR_12]] '_Tp' dependent depth 0 index 0 -// CHECK-NEXT: | | | | `-TemplateTypeParm [[ADDR_13]] '_Tp' +// CHECK-NEXT: | | | `-SubstTemplateTypeParmType [[ADDR_11]] 'float' sugar class depth 0 index 0 _Tp +// CHECK-NEXT: | | | |-ClassTemplateSpecialization [[ADDR_6]] 'remove_reference' // CHECK-NEXT: | | | `-BuiltinType [[ADDR_8]] 'float' // CHECK-NEXT: | | `-ReturnStmt [[ADDR_49:0x[a-z0-9]*]] // CHECK-NEXT: | | `-CXXStaticCastExpr [[ADDR_50:0x[a-z0-9]*]] '_Up':'float' xvalue static_cast<_Up &&> @@ -215,9 +212,8 @@ // CHECK-NEXT: | | `-ElaboratedType [[ADDR_57:0x[a-z0-9]*]] 'typename remove_reference::type' sugar // CHECK-NEXT: | | `-TypedefType [[ADDR_58:0x[a-z0-9]*]] 'remove_reference::type' sugar // CHECK-NEXT: | | |-Typedef [[ADDR_18]] 'type' -// CHECK-NEXT: | | `-SubstTemplateTypeParmType [[ADDR_19]] 'short' sugar -// CHECK-NEXT: | | |-TemplateTypeParmType [[ADDR_12]] '_Tp' dependent depth 0 index 0 -// CHECK-NEXT: | | | `-TemplateTypeParm [[ADDR_13]] '_Tp' +// CHECK-NEXT: | | `-SubstTemplateTypeParmType [[ADDR_19]] 'short' sugar class depth 0 index 0 _Tp +// CHECK-NEXT: | | |-ClassTemplateSpecialization [[ADDR_14]] 'remove_reference' // CHECK-NEXT: | | `-BuiltinType [[ADDR_16]] 'short' // CHECK-NEXT: | `-ReturnStmt [[ADDR_59:0x[a-z0-9]*]] // CHECK-NEXT: | `-CXXStaticCastExpr [[ADDR_60:0x[a-z0-9]*]] '_Up':'short' xvalue static_cast<_Up &&> diff --git a/clang/test/AST/ast-dump-template-decls.cpp b/clang/test/AST/ast-dump-template-decls.cpp --- a/clang/test/AST/ast-dump-template-decls.cpp +++ b/clang/test/AST/ast-dump-template-decls.cpp @@ -120,12 +120,12 @@ // CHECK-NEXT: TemplateArgument type 'void' // CHECK-NEXT: BuiltinType 0x{{[^ ]*}} 'void' // CHECK-NEXT: FunctionProtoType 0x{{[^ ]*}} 'void (int)' cdecl -// CHECK-NEXT: SubstTemplateTypeParmType 0x{{[^ ]*}} 'void' sugar -// CHECK-NEXT: TemplateTypeParmType 0x{{[^ ]*}} 'U' dependent depth 0 index 0 -// CHECK-NEXT: TemplateTypeParm 0x{{[^ ]*}} 'U' +// CHECK-NEXT: SubstTemplateTypeParmType 0x{{[^ ]*}} 'void' sugar class depth 0 index 0 U +// CHECK-NEXT: TypeAliasTemplate 0x{{[^ ]*}} 'type1' // CHECK-NEXT: BuiltinType 0x{{[^ ]*}} 'void' -// CHECK-NEXT: SubstTemplateTypeParmType 0x{{[^ ]*}} 'int' sugar -// CHECK-NEXT: TemplateTypeParmType 0x{{[^ ]*}} 'T' dependent depth 0 index 0 +// CHECK-NEXT: SubstTemplateTypeParmType 0x{{[^ ]*}} 'int' sugar class depth 0 index 0 T +// CHECK-NEXT: ClassTemplateSpecialization 0x{{[^ ]*}} 'C' +// CHECK-NEXT: BuiltinType 0x{{[^ ]*}} 'int' } // namespace PR55886 namespace PR56099 { @@ -136,14 +136,14 @@ }; using t1 = foo::bind; // CHECK: TemplateSpecializationType 0x{{[^ ]*}} 'Y' sugar Y -// CHECK: SubstTemplateTypeParmType 0x{{[^ ]*}} 'char' sugar pack_index 0 -// CHECK-NEXT: TemplateTypeParmType 0x{{[^ ]*}} 'Bs' dependent contains_unexpanded_pack depth 0 index 0 pack -// CHECK: SubstTemplateTypeParmType 0x{{[^ ]*}} 'float' sugar pack_index 1 -// CHECK-NEXT: TemplateTypeParmType 0x{{[^ ]*}} 'Bs' dependent contains_unexpanded_pack depth 0 index 0 pack -// CHECK: SubstTemplateTypeParmType 0x{{[^ ]*}} 'int' sugar pack_index 2 -// CHECK-NEXT: TemplateTypeParmType 0x{{[^ ]*}} 'Bs' dependent contains_unexpanded_pack depth 0 index 0 pack -// CHECK: SubstTemplateTypeParmType 0x{{[^ ]*}} 'short' sugar pack_index 3 -// CHECK-NEXT: TemplateTypeParmType 0x{{[^ ]*}} 'Bs' dependent contains_unexpanded_pack depth 0 index 0 pack +// CHECK: SubstTemplateTypeParmType 0x{{[^ ]*}} 'char' sugar typename depth 0 index 0 ... Bs pack_index 0 +// CHECK-NEXT: TypeAliasTemplate 0x{{[^ ]*}} 'Z' +// CHECK: SubstTemplateTypeParmType 0x{{[^ ]*}} 'float' sugar typename depth 0 index 0 ... Bs pack_index 1 +// CHECK-NEXT: TypeAliasTemplate 0x{{[^ ]*}} 'Z' +// CHECK: SubstTemplateTypeParmType 0x{{[^ ]*}} 'int' sugar typename depth 0 index 0 ... Bs pack_index 2 +// CHECK-NEXT: TypeAliasTemplate 0x{{[^ ]*}} 'Z' +// CHECK: SubstTemplateTypeParmType 0x{{[^ ]*}} 'short' sugar typename depth 0 index 0 ... Bs pack_index 3 +// CHECK-NEXT: TypeAliasTemplate 0x{{[^ ]*}} 'Z' template struct D { template using B = int(int (*...p)(T, U)); @@ -152,13 +152,13 @@ // CHECK: TemplateSpecializationType 0x{{[^ ]*}} 'B' sugar alias B // CHECK: FunctionProtoType 0x{{[^ ]*}} 'int (int (*)(float, int), int (*)(char, short))' cdecl // CHECK: FunctionProtoType 0x{{[^ ]*}} 'int (float, int)' cdecl -// CHECK: SubstTemplateTypeParmType 0x{{[^ ]*}} 'float' sugar pack_index 0 -// CHECK-NEXT: TemplateTypeParmType 0x{{[^ ]*}} 'T' dependent contains_unexpanded_pack depth 0 index 0 pack -// CHECK: SubstTemplateTypeParmType 0x{{[^ ]*}} 'int' sugar pack_index 0 -// CHECK-NEXT: TemplateTypeParmType 0x{{[^ ]*}} 'U' dependent contains_unexpanded_pack depth 0 index 0 pack +// CHECK: SubstTemplateTypeParmType 0x{{[^ ]*}} 'float' sugar typename depth 0 index 0 ... T pack_index 0 +// CHECK-NEXT: ClassTemplateSpecialization 0x{{[^ ]*}} 'D' +// CHECK: SubstTemplateTypeParmType 0x{{[^ ]*}} 'int' sugar typename depth 0 index 0 ... U pack_index 0 +// CHECK-NEXT: TypeAliasTemplate 0x{{[^ ]*}} 'B' // CHECK: FunctionProtoType 0x{{[^ ]*}} 'int (char, short)' cdecl -// CHECK: SubstTemplateTypeParmType 0x{{[^ ]*}} 'char' sugar pack_index 1 -// CHECK-NEXT: TemplateTypeParmType 0x{{[^ ]*}} 'T' dependent contains_unexpanded_pack depth 0 index 0 pack -// CHECK: SubstTemplateTypeParmType 0x{{[^ ]*}} 'short' sugar pack_index 1 -// CHECK-NEXT: TemplateTypeParmType 0x{{[^ ]*}} 'U' dependent contains_unexpanded_pack depth 0 index 0 pack +// CHECK: SubstTemplateTypeParmType 0x{{[^ ]*}} 'char' sugar typename depth 0 index 0 ... T pack_index 1 +// CHECK-NEXT: ClassTemplateSpecialization 0x{{[^ ]*}} 'D' +// CHECK: SubstTemplateTypeParmType 0x{{[^ ]*}} 'short' sugar typename depth 0 index 0 ... U pack_index 1 +// CHECK-NEXT: TypeAliasTemplate 0x{{[^ ]*}} 'B' } // namespace PR56099 diff --git a/clang/test/AST/deduction-guides.cpp b/clang/test/AST/deduction-guides.cpp --- a/clang/test/AST/deduction-guides.cpp +++ b/clang/test/AST/deduction-guides.cpp @@ -67,9 +67,8 @@ // CHECK-NEXT: ElaboratedType {{.*}} 'typename Derived::type_alias' sugar // CHECK-NEXT: TypedefType {{.*}} 'PR48177::Base::type_alias' sugar // CHECK-NEXT: TypeAlias {{.*}} 'type_alias' -// CHECK-NEXT: SubstTemplateTypeParmType {{.*}} 'int' sugar -// CHECK-NEXT: TemplateTypeParmType {{.*}} 'A' -// CHECK-NEXT: TemplateTypeParm {{.*}} 'A' +// CHECK-NEXT: SubstTemplateTypeParmType {{.*}} 'int' sugar class depth 0 index 0 A +// CHECK-NEXT: ClassTemplateSpecialization {{.*}} 'Base' // CHECK-NEXT: BuiltinType {{.*}} 'int' // CHECK: CXXDeductionGuideDecl {{.*}} implicit 'auto (Derived &&, const typename Derived::type_alias &) -> Derived' diff --git a/clang/test/Analysis/cast-value-notes.cpp b/clang/test/Analysis/cast-value-notes.cpp --- a/clang/test/Analysis/cast-value-notes.cpp +++ b/clang/test/Analysis/cast-value-notes.cpp @@ -73,7 +73,7 @@ #if defined(X86) void evalReferences(const Shape &S) { const auto &C = dyn_cast(S); - // expected-note@-1 {{Assuming 'S' is not a 'const class clang::Circle &'}} + // expected-note@-1 {{Assuming 'S' is not a 'const Circle &'}} // expected-note@-2 {{Dereference of null pointer}} // expected-warning@-3 {{Dereference of null pointer}} clang_analyzer_printState(); @@ -86,26 +86,26 @@ const auto &C = dyn_cast(S); clang_analyzer_printState(); // X86-CHECK-SUPPRESSED: "dynamic_types": [ - // X86-CHECK-SUPPRESSED-NEXT: { "region": "SymRegion{reg_$0}", "dyn_type": "const __attribute__((address_space(3))) class clang::Circle &", "sub_classable": true } + // X86-CHECK-SUPPRESSED-NEXT: { "region": "SymRegion{reg_$0}", "dyn_type": "DEVICE Circle const &", "sub_classable": true } (void)C; } #endif #if defined(NOT_SUPPRESSED) void evalReferences_addrspace(const Shape &S) { const auto &C = dyn_cast(S); - // expected-note@-1 {{Assuming 'S' is not a 'const __attribute__((address_space(3))) class clang::Circle &'}} + // expected-note@-1 {{Assuming 'S' is not a 'DEVICE Circle const &'}} // expected-note@-2 {{Dereference of null pointer}} // expected-warning@-3 {{Dereference of null pointer}} clang_analyzer_printState(); // X86-CHECK: "dynamic_types": [ - // X86-CHECK-NEXT: { "region": "SymRegion{reg_$0}", "dyn_type": "const __attribute__((address_space(3))) class clang::Circle &", "sub_classable": true } + // X86-CHECK-NEXT: { "region": "SymRegion{reg_$0}", "dyn_type": "DEVICE Circle const &", "sub_classable": true } (void)C; } #endif #elif defined(MIPS) void evalReferences(const Shape &S) { const auto &C = dyn_cast(S); - // expected-note@-1 {{Assuming 'S' is not a 'const class clang::Circle &'}} + // expected-note@-1 {{Assuming 'S' is not a 'const Circle &'}} // expected-note@-2 {{Dereference of null pointer}} // expected-warning@-3 {{Dereference of null pointer}} } @@ -122,25 +122,25 @@ // expected-note@-1 {{'C' initialized here}} if (!dyn_cast_or_null(C)) { - // expected-note@-1 {{Assuming 'C' is a 'const class clang::Circle *'}} + // expected-note@-1 {{Assuming 'C' is a 'const Circle *'}} // expected-note@-2 {{Taking false branch}} return; } if (dyn_cast_or_null(C)) { - // expected-note@-1 {{Assuming 'C' is not a 'const class clang::Triangle *'}} + // expected-note@-1 {{Assuming 'C' is not a 'const Triangle *'}} // expected-note@-2 {{Taking false branch}} return; } if (dyn_cast_or_null(C)) { - // expected-note@-1 {{Assuming 'C' is not a 'const class clang::Rectangle *'}} + // expected-note@-1 {{Assuming 'C' is not a 'const Rectangle *'}} // expected-note@-2 {{Taking false branch}} return; } if (dyn_cast_or_null(C)) { - // expected-note@-1 {{Assuming 'C' is not a 'const class clang::Hexagon *'}} + // expected-note@-1 {{Assuming 'C' is not a 'const Hexagon *'}} // expected-note@-2 {{Taking false branch}} return; } @@ -176,29 +176,29 @@ void evalNonNullParamNonNullReturn(const Shape *S) { const auto *C = cast(S); - // expected-note@-1 {{'S' is a 'const class clang::Circle *'}} + // expected-note@-1 {{'S' is a 'const Circle *'}} // expected-note@-2 {{'C' initialized here}} if (!dyn_cast_or_null(C)) { - // expected-note@-1 {{Assuming 'C' is a 'const class clang::Circle *'}} + // expected-note@-1 {{Assuming 'C' is a 'const Circle *'}} // expected-note@-2 {{Taking false branch}} return; } if (dyn_cast_or_null(C)) { - // expected-note@-1 {{Assuming 'C' is not a 'const class clang::Triangle *'}} + // expected-note@-1 {{Assuming 'C' is not a 'const Triangle *'}} // expected-note@-2 {{Taking false branch}} return; } if (dyn_cast_or_null(C)) { - // expected-note@-1 {{Assuming 'C' is not a 'const class clang::Rectangle *'}} + // expected-note@-1 {{Assuming 'C' is not a 'const Rectangle *'}} // expected-note@-2 {{Taking false branch}} return; } if (dyn_cast_or_null(C)) { - // expected-note@-1 {{Assuming 'C' is not a 'const class clang::Hexagon *'}} + // expected-note@-1 {{Assuming 'C' is not a 'const Hexagon *'}} // expected-note@-2 {{Taking false branch}} return; } @@ -234,10 +234,10 @@ void evalNonNullParamNullReturn(const Shape *S) { const auto *C = dyn_cast_or_null(S); - // expected-note@-1 {{Assuming 'S' is not a 'const class clang::Circle *'}} + // expected-note@-1 {{Assuming 'S' is not a 'const Circle *'}} if (const auto *T = dyn_cast_or_null(S)) { - // expected-note@-1 {{Assuming 'S' is a 'const class clang::Triangle *'}} + // expected-note@-1 {{Assuming 'S' is a 'const Triangle *'}} // expected-note@-2 {{'T' initialized here}} // expected-note@-3 {{'T' is non-null}} // expected-note@-4 {{Taking true branch}} @@ -261,7 +261,7 @@ void evalZeroParamNonNullReturnPointer(const Shape *S) { const auto *C = S->castAs(); - // expected-note@-1 {{'S' is a 'const class clang::Circle *'}} + // expected-note@-1 {{'S' is a 'const Circle *'}} // expected-note@-2 {{'C' initialized here}} (void)(1 / !C); @@ -282,12 +282,12 @@ void evalZeroParamNullReturn(const Shape *S) { const auto &C = S->getAs(); - // expected-note@-1 {{Assuming 'S' is not a 'const class clang::Circle *'}} + // expected-note@-1 {{Assuming 'S' is not a 'const Circle *'}} // expected-note@-2 {{Storing null pointer value}} // expected-note@-3 {{'C' initialized here}} if (!dyn_cast_or_null(S)) { - // expected-note@-1 {{Assuming 'S' is a 'const class clang::Triangle *'}} + // expected-note@-1 {{Assuming 'S' is a 'const Triangle *'}} // expected-note@-2 {{Taking false branch}} return; } diff --git a/clang/test/Analysis/cast-value-state-dump.cpp b/clang/test/Analysis/cast-value-state-dump.cpp --- a/clang/test/Analysis/cast-value-state-dump.cpp +++ b/clang/test/Analysis/cast-value-state-dump.cpp @@ -18,12 +18,12 @@ void evalNonNullParamNonNullReturn(const Shape *S) { const auto *C = dyn_cast_or_null(S); - // expected-note@-1 {{Assuming 'S' is a 'const class clang::Circle *'}} + // expected-note@-1 {{Assuming 'S' is a 'const Circle *'}} // expected-note@-2 {{'C' initialized here}} // FIXME: We assumed that 'S' is a 'Circle' therefore it is not a 'Square'. if (dyn_cast_or_null(S)) { - // expected-note@-1 {{Assuming 'S' is not a 'const class clang::Square *'}} + // expected-note@-1 {{Assuming 'S' is not a 'const Square *'}} // expected-note@-2 {{Taking false branch}} return; } @@ -31,7 +31,7 @@ clang_analyzer_printState(); // CHECK: "dynamic_types": [ - // CHECK-NEXT: { "region": "SymRegion{reg_$0}", "dyn_type": "const class clang::Circle", "sub_classable": true } + // CHECK-NEXT: { "region": "SymRegion{reg_$0}", "dyn_type": "const Circle", "sub_classable": true } // CHECK-NEXT: ], // CHECK-NEXT: "dynamic_casts": [ // CHECK: { "region": "SymRegion{reg_$0}", "casts": [ 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,8 +38,8 @@ 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 b4(enum B); // this just doesn't parse; you can't template an enum directly +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); void c2(class B::Member); diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.req/compound-requirement.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.req/compound-requirement.cpp --- a/clang/test/CXX/expr/expr.prim/expr.prim.req/compound-requirement.cpp +++ b/clang/test/CXX/expr/expr.prim/expr.prim.req/compound-requirement.cpp @@ -35,14 +35,14 @@ using r2i3 = r2; using r2i4 = r2; // expected-error{{constraints not satisfied for class template 'r2' [with T = const D]}} -template requires requires { { sizeof(T) }; } // expected-note{{because 'sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'void'}} expected-note{{because 'sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'nonexistent'}} +template requires requires { { sizeof(T) }; } // expected-note{{because 'sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'void'}} expected-note{{because 'sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'class nonexistent'}} struct r3 {}; using r3i1 = r3; using r3i2 = r3; using r3i3 = r3; using r3i4 = r3; // expected-error{{constraints not satisfied for class template 'r3' [with T = void]}} -using r3i4 = r3; // expected-error{{constraints not satisfied for class template 'r3' [with T = nonexistent]}} +using r3i4 = r3; // expected-error{{constraints not satisfied for class template 'r3' [with T = class nonexistent]}} // Non-dependent expressions @@ -173,9 +173,9 @@ int operator *() { return 0; } }; static_assert(C2); - template struct C2_check {}; // expected-note{{because 'int' does not satisfy 'C2'}} expected-note{{because 'std_example::T2' does not satisfy 'C2'}} + template struct C2_check {}; // expected-note{{because 'int' does not satisfy 'C2'}} expected-note{{because 'T2' does not satisfy 'C2'}} using c2c1 = C2_check; // expected-error{{constraints not satisfied for class template 'C2_check' [with T = int]}} - using c2c2 = C2_check; // expected-error{{constraints not satisfied for class template 'C2_check' [with T = std_example::T2]}} + using c2c2 = C2_check; // expected-error{{constraints not satisfied for class template 'C2_check' [with T = T2]}} template void g(T t) noexcept(sizeof(T) == 1) {} diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp --- a/clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp +++ b/clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp @@ -39,14 +39,14 @@ template requires requires { sizeof(T); } // expected-note@-1{{because 'sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'void'}} -// expected-note@-2{{because 'sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'nonexistent'}} +// expected-note@-2{{because 'sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'class nonexistent'}} struct r3 {}; using r3i1 = r3; using r3i2 = r3; using r3i3 = r3; using r3i4 = r3; // expected-error{{constraints not satisfied for class template 'r3' [with T = void]}} -using r3i4 = r3; // expected-error{{constraints not satisfied for class template 'r3' [with T = nonexistent]}} +using r3i4 = r3; // expected-error{{constraints not satisfied for class template 'r3' [with T = class nonexistent]}} template requires requires (T t) { 0; "a"; (void)'a'; } struct r4 {}; diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.req/type-requirement.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.req/type-requirement.cpp --- a/clang/test/CXX/expr/expr.prim/expr.prim.req/type-requirement.cpp +++ b/clang/test/CXX/expr/expr.prim/expr.prim.req/type-requirement.cpp @@ -182,14 +182,14 @@ static_assert(C1 && C2 && C3); template struct C1_check {}; // expected-note@-1 {{because 'int' does not satisfy 'C1'}} - // expected-note@-2 {{because 'std_example::has_type' does not satisfy 'C1'}} + // expected-note@-2 {{because 'has_type' does not satisfy 'C1'}} template struct C2_check {}; - // expected-note@-1 {{because 'std_example::has_inner' does not satisfy 'C2'}} + // expected-note@-1 {{because 'has_inner' does not satisfy 'C2'}} template struct C3_check {}; // expected-note@-1 {{because 'void' does not satisfy 'C3'}} using c1 = C1_check; // expected-error{{constraints not satisfied for class template 'C1_check' [with T = int]}} - using c2 = C1_check; // expected-error{{constraints not satisfied for class template 'C1_check' [with T = std_example::has_type]}} - using c3 = C2_check; // expected-error{{constraints not satisfied for class template 'C2_check' [with T = std_example::has_inner]}} + using c2 = C1_check; // expected-error{{constraints not satisfied for class template 'C1_check' [with T = has_type]}} + using c3 = C2_check; // expected-error{{constraints not satisfied for class template 'C2_check' [with T = has_inner]}} using c4 = C3_check; // expected-error{{constraints not satisfied for class template 'C3_check' [with T = void]}} } @@ -199,10 +199,10 @@ // expected-note@-1 {{because 'T::a' would be invalid: no member named 'a' in 'PR48656::T1'}} template struct A {}; -// expected-note@-1 {{because 'PR48656::T1' does not satisfy 'C'}} +// expected-note@-1 {{because 'T1' does not satisfy 'C'}} struct T1 {}; -template struct A; // expected-error {{constraints not satisfied for class template 'A' [with $0 = ]}} +template struct A; // expected-error {{constraints not satisfied for class template 'A' [with $0 = ]}} struct T2 { static constexpr bool a = false; }; template struct A; diff --git a/clang/test/CXX/temp/temp.decls/temp.class.spec/p6.cpp b/clang/test/CXX/temp/temp.decls/temp.class.spec/p6.cpp --- a/clang/test/CXX/temp/temp.decls/temp.class.spec/p6.cpp +++ b/clang/test/CXX/temp/temp.decls/temp.class.spec/p6.cpp @@ -38,7 +38,7 @@ template struct Outer { template struct Inner; - template struct Inner {}; // expected-note{{previous declaration of class template partial specialization 'Inner' is here}} + template struct Inner {}; // expected-note{{previous declaration of class template partial specialization 'Inner' is here}} template struct Inner {}; // expected-error{{cannot be redeclared}} }; @@ -80,7 +80,7 @@ template struct Foo { template struct Bar; template struct Bar<0, T, Y> {}; - // expected-note-re@-1 {{previous declaration {{.*}} 'Bar<0, int, type-parameter-0-0>' is here}} + // expected-note-re@-1 {{previous declaration {{.*}} 'Bar<0, int, Y>' is here}} template struct Bar<0, U, Y> {}; // expected-error@-1 {{partial specialization 'Bar<0, int, Y>' cannot be redeclared}} }; 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 {}; @@ -1172,7 +1169,7 @@ // CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper>' to 'Wrapper>' Wrapper> W13 = MakeWrapper>(); -// CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper>' to 'Wrapper>' +// CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper>' to 'Wrapper>' Wrapper> W14 = MakeWrapper>(); // CHECK-ELIDE-NOTREE: no viable conversion from 'Wrapper>' to 'Wrapper>' } @@ -1384,8 +1381,8 @@ template struct A {}; template > R bar(); A<> &foo() { return bar(); } -// CHECK-ELIDE-NOTREE: error: non-const lvalue reference to type 'A<...>' cannot bind to a temporary of type 'A<...>' -// CHECK-NOELIDE-NOTREE: error: non-const lvalue reference to type 'A' cannot bind to a temporary of type 'A' +// CHECK-ELIDE-NOTREE: error: non-const lvalue reference to type 'A<>' cannot bind to a temporary of type 'A<>' +// CHECK-NOELIDE-NOTREE: error: non-const lvalue reference to type 'A<>' cannot bind to a temporary of type 'A<>' } namespace PR24587 { diff --git a/clang/test/Sema/Resugar/resugar-expr.cpp b/clang/test/Sema/Resugar/resugar-expr.cpp new file mode 100644 --- /dev/null +++ b/clang/test/Sema/Resugar/resugar-expr.cpp @@ -0,0 +1,244 @@ +// RUN: %clang_cc1 -std=c++2b -fsyntax-only -verify=Y %s +// RUN: %clang_cc1 -std=c++2b -fsyntax-only -fno-resugar -verify=N %s + +enum class Z; + +struct bar {}; + +using Int = int; +using Float = float; +using Bar = bar; + +namespace t1 { +template struct A { + static constexpr A1 a = {}; +}; + +Z x1 = A::a; +// Y-error@-1 {{with an lvalue of type 'const Int' (aka 'const int')}} +// N-error@-2 {{with an lvalue of type 'const int'}} +} // namespace t1 + +namespace t2 { +template struct A { + static constexpr A1 A2::*a = {}; +}; + +Z x1 = A::a; +// Y-error@-1 {{with an lvalue of type 'Int Bar::*const'}} +// N-error@-2 {{with an lvalue of type 'int bar::*const'}} +} // namespace t2 + +namespace t3 { +template struct A { + template struct B { + static constexpr A1 B1::*a = {}; + }; +}; + +Z x1 = A::B::a; +// Y-error@-1 {{with an lvalue of type 'Float Bar::*const'}} +// N-error@-2 {{with an lvalue of type 'float bar::*const'}} +} // namespace t3 + +namespace t4 { +template A1 (*a) +(); + +Z x1 = decltype(a){}(); +// Y-error@-1 {{with an rvalue of type 'Int' (aka 'int')}} +// N-error@-2 {{with an rvalue of type 'int'}} +} // namespace t4 + +namespace t5 { +template struct A { + A1(*a) + (); +}; + +Z x1 = decltype(A().a){}(); +// Y-error@-1 {{with an rvalue of type 'Int' (aka 'int')}} +// N-error@-2 {{with an rvalue of type 'int'}} +} // namespace t5 + +namespace t6 { +template struct A { A2 A1::*f(); }; + +using M = int; +using N = int; + +struct B {}; +using X = B; +using Y = B; + +auto a = &A::f; +Z x1 = a; +// Y-error@-1 {{with an lvalue of type 'M X::*(A::*)()'}} +// N-error@-2 {{with an lvalue of type 'int t6::B::*(A::*)()'}} + +A b; +Z x2 = (b.*a)(); +// Y-error@-1 {{with an rvalue of type 'M X::*'}} +// N-error@-2 {{with an rvalue of type 'int t6::B::*'}} + +Z x3 = decltype((b.*a)()){}; +// Y-error@-1 {{with an rvalue of type 'decltype((b .* a)())' (aka 'M X::*')}} +// N-error@-2 {{with an rvalue of type 'decltype((b .* a)())' (aka 'int t6::B::*')}} +} // namespace t6 + +namespace t7 { +template struct A { A1 a; }; +auto [a] = A{}; + +Z x1 = a; +// Y-error@-1 {{with an lvalue of type 'Int' (aka 'int')}} +// N-error@-2 {{with an lvalue of type 'int'}} +} // namespace t7 + +namespace t8 { +template struct A { + template static constexpr B1 (*b)(A1) = nullptr; +}; + +Z x1 = A::b; +// Y-error@-1 {{with an lvalue of type 'Int (*const)(Float)' (aka 'int (*const)(float)')}} +// N-error@-2 {{with an lvalue of type 'int (*const)(float)'}} +} // namespace t8 + +namespace t9 { +template struct A { + template static constexpr auto b = (B1(*)(A1)){}; +}; + +Z x1 = A::b; +// Y-error@-1 {{with an lvalue of type 'Int (*const)(Float)' (aka 'int (*const)(float)'}} +// N-error@-2 {{with an lvalue of type 'int (*const)(float)'}} +} // namespace t9 + +namespace t10 { +template struct A { + template static constexpr A1 (*m)(B1) = nullptr; +}; + +Z x1 = A().template m; +// Y-error@-1 {{with an lvalue of type 'Int (*const)(Float)' (aka 'int (*const)(float)'}} +// N-error@-2 {{with an lvalue of type 'int (*const)(float)'}} +} // namespace t10 + +namespace t11 { +template A1 a; +template A2 a; + +Z x1 = a; +// Y-error@-1 {{with an lvalue of type 'Int' (aka 'int')}} +// N-error@-2 {{with an lvalue of type 'int'}} + +Z x2 = a; +// Y-error@-1 {{with an lvalue of type 'Float' (aka 'float'}} +// N-error@-2 {{with an lvalue of type 'float'}} +} // namespace t11 + +namespace t12 { +template struct A { A1 foo(); }; + +Z x1 = A().foo(); +// Y-error@-1 {{with an rvalue of type 'Int' (aka 'int')}} +// N-error@-2 {{with an rvalue of type 'int'}} +} // namespace t12 + +namespace t13 { +template struct A { + auto foo() { return A1(); }; +}; + +Z x1 = A().foo(); +// Y-error@-1 {{with an rvalue of type 'Int' (aka 'int')}} +// N-error@-2 {{with an rvalue of type 'int'}} +} // namespace t13 + +namespace t14 { +template struct A { + template auto foo1() -> A1 (*)(B1); + template auto foo2(B1) -> A1 (*)(B1); +}; + +Z x1 = A().foo1(); +// Y-error@-1 {{with an rvalue of type 'Int (*)(Float)' (aka 'int (*)(float)'}} +// N-error@-2 {{with an rvalue of type 'int (*)(float)'}} + +Z x2 = A().foo2(Float()); +// Y-error@-1 {{with an rvalue of type 'Int (*)(Float)' (aka 'int (*)(float)'}} +// N-error@-2 {{with an rvalue of type 'int (*)(float)'}} +} // namespace t14 + +namespace t15 { +template struct A { + static auto foo() -> A1; +}; + +Z x1 = A().foo(); +// Y-error@-1 {{with an rvalue of type 'Int' (aka 'int')}} +// N-error@-2 {{with an rvalue of type 'int'}} +} // namespace t15 + +namespace t16 { +template static auto foo() -> A1; + +Z x1 = foo(); +// Y-error@-1 {{with an rvalue of type 'Int' (aka 'int')}} +// N-error@-2 {{with an rvalue of type 'int'}} +} // namespace t16 + +namespace t17 { +template static auto foo(A1) -> A1*; + +Z x1 = foo(Int()); +// Y-error@-1 {{with an rvalue of type 'Int *' (aka 'int *')}} +// N-error@-2 {{with an rvalue of type 'int *'}} +} // namespace t16 + +namespace t18 { +template struct A { + template static auto foo() -> A1 (*)(B1); +}; + +Z x1 = A().template foo(); +// Y-error@-1 {{with an rvalue of type 'Int (*)(Float)' (aka 'int (*)(float)'}} +// N-error@-2 {{with an rvalue of type 'int (*)(float)'}} + +Z x2 = A::template foo(); +// Y-error@-1 {{with an rvalue of type 'Int (*)(Float)' (aka 'int (*)(float)'}} +// N-error@-2 {{with an rvalue of type 'int (*)(float)'}} +} // namespace t18 + +namespace t19 { +template struct A { + A1 m; +}; + +Z x1 = A().m; +// Y-error@-1 {{with an rvalue of type 'Int' (aka 'int')}} +// N-error@-2 {{with an rvalue of type 'int'}} +} // namespace t19 + +namespace t20 { +template struct A { + static A1 m; +}; + +Z x1 = A().m; +// Y-error@-1 {{with an lvalue of type 'Int' (aka 'int')}} +// N-error@-2 {{with an lvalue of type 'int'}} +} // namespace t20 + +namespace t21 { +template struct A { + struct { + A1 m; + }; +}; + +Z x1 = A().m; +// Y-error@-1 {{with an rvalue of type 'Int' (aka 'int')}} +// N-error@-2 {{with an rvalue of type 'int'}} +} // namespace t21 diff --git a/clang/test/Sema/Resugar/resugar-types.cpp b/clang/test/Sema/Resugar/resugar-types.cpp new file mode 100644 --- /dev/null +++ b/clang/test/Sema/Resugar/resugar-types.cpp @@ -0,0 +1,195 @@ +// 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(typename foo::type); +} // 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 struct A { using type1 = A2; }; +TEST(A::type1); +} // namespace t11 + +namespace t12 { +template struct W { + template class TT> + struct X { + using type1 = TT; + }; +}; + +template struct Y { + using type2 = Y2; + using type3 = Y3; +}; + +using T1 = typename W::X::type1; +TEST_NOT(typename T1::type2); // FIXME +TEST(typename T1::type3); +} // namespace t12 + +namespace t13 { +template