diff --git a/BROKEN b/BROKEN new file mode 100644 --- /dev/null +++ b/BROKEN @@ -0,0 +1,5 @@ +CXX/temp/temp.decls/temp.variadic/example-tuple.cpp +CXX/temp/temp.decls/temp.variadic/metafunctions.cpp +PCH/cxx-chain-function-template.cpp +SemaCXX/calling-conv-compat.cpp +SemaTemplate/example-typelist.cpp 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/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -443,6 +443,8 @@ TemplatedDecl->getSourceRange().getEnd()); } + bool isTypeAlias() const; + protected: NamedDecl *TemplatedDecl; TemplateParameterList *TemplateParams; 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; 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,6 +1790,24 @@ 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; @@ -1876,6 +1894,8 @@ ConstantArrayTypeBitfields ConstantArrayTypeBits; AttributedTypeBitfields AttributedTypeBits; AutoTypeBitfields AutoTypeBits; + TypedefBitfields TypedefBits; + UsingBitfields UsingBits; BuiltinTypeBitfields BuiltinTypeBits; FunctionTypeBitfields FunctionTypeBits; ObjCObjectTypeBitfields ObjCObjectTypeBits; @@ -4461,15 +4481,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; } }; @@ -4485,6 +4511,9 @@ public: TypedefNameDecl *getDecl() const { return Decl; } + bool hasDifferentUnderlyingType() const { + return TypedefBits.hasDifferentUnderlyingType; + } bool isSugared() const { return true; } QualType desugar() const; @@ -4986,11 +5015,13 @@ // The original type parameter. const TemplateTypeParmType *Replaced; + QualType Replacement; - SubstTemplateTypeParmType(const TemplateTypeParmType *Param, QualType Canon, - Optional PackIndex) - : Type(SubstTemplateTypeParm, Canon, Canon->getDependence()), - Replaced(Param) { + SubstTemplateTypeParmType(const TemplateTypeParmType *Param, + QualType Replacement, Optional PackIndex) + : Type(SubstTemplateTypeParm, Replacement.getCanonicalType(), + Replacement->getDependence()), + Replaced(Param), Replacement(Replacement) { SubstTemplateTypeParmTypeBits.PackIndex = PackIndex ? *PackIndex + 1 : 0; } @@ -5002,9 +5033,7 @@ /// Gets the type that was substituted for the template /// parameter. - QualType getReplacementType() const { - return getCanonicalTypeInternal(); - } + QualType getReplacementType() const { return Replacement; } Optional getPackIndex() const { if (SubstTemplateTypeParmTypeBits.PackIndex == 0U) 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 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); }]>; } @@ -739,10 +735,8 @@ } def : Creator<[{ - // The call to getCanonicalType here existed in ASTReader.cpp, too. return ctx.getSubstTemplateTypeParmType( - cast(replacedParameter), - ctx.getCanonicalType(replacementType), PackIndex); + cast(replacedParameter), replacementType, PackIndex); }]>; } diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -469,6 +469,9 @@ /// forward slash (/) elsewhere. bool UseTargetPathSeparator = false; + /// Resugar template specializations. + bool Resugar = true; + LangOptions(); /// Set language defaults for the given input language and diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -5744,6 +5744,9 @@ LangOpts<"RecoveryASTType">, DefaultTrue, NegFlag, PosFlag>; +def fno_resugar : Flag<["-"], "fno-resugar">, + HelpText<"Do not resugar template specializations">, + MarshallingInfoNegativeFlag>; let Group = Action_Group in { diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h --- a/clang/include/clang/Sema/Overload.h +++ b/clang/include/clang/Sema/Overload.h @@ -881,6 +881,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 @@ -3774,7 +3774,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, @@ -3789,16 +3790,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, @@ -3934,10 +3935,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, @@ -3947,13 +3947,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, @@ -5564,6 +5564,7 @@ ExprResult BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow, SourceLocation OpLoc, const CXXScopeSpec &SS, FieldDecl *Field, + QualType FieldType, DeclAccessPair FoundDecl, const DeclarationNameInfo &MemberNameInfo); @@ -7841,9 +7842,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, @@ -7994,14 +7995,13 @@ CTAK_DeducedFromArrayBound }; - bool CheckTemplateArgument(NamedDecl *Param, - TemplateArgumentLoc &Arg, - NamedDecl *Template, - SourceLocation TemplateLoc, + bool CheckTemplateArgument(NamedDecl *Param, TemplateArgumentLoc &Arg, + NamedDecl *Template, SourceLocation TemplateLoc, SourceLocation RAngleLoc, unsigned ArgumentPackIndex, - SmallVectorImpl &Converted, - CheckTemplateArgumentKind CTAK = CTAK_Specified); + SmallVectorImpl &Converted, + CheckTemplateArgumentKind CTAK, + bool DontCanonicalize); /// Check that the given template arguments can be be provided to /// the given template, converting the arguments along the way. @@ -8038,17 +8038,20 @@ bool PartialTemplateArgs, SmallVectorImpl &Converted, bool UpdateArgsWithConversions = true, - bool *ConstraintsNotSatisfied = nullptr); + bool *ConstraintsNotSatisfied = nullptr, + bool DontCanonicalize = false); bool CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, TemplateArgumentLoc &Arg, - SmallVectorImpl &Converted); + SmallVectorImpl &Converted, + bool DontCanonizalize); bool CheckTemplateArgument(TypeSourceInfo *Arg); ExprResult CheckTemplateArgument(NonTypeTemplateParmDecl *Param, QualType InstantiatedParamType, Expr *Arg, TemplateArgument &Converted, - CheckTemplateArgumentKind CTAK = CTAK_Specified); + CheckTemplateArgumentKind CTAK, + bool DontCanonizalize); bool CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param, TemplateParameterList *Params, TemplateArgumentLoc &Arg); @@ -8661,12 +8664,14 @@ TemplateDeductionResult DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, const TemplateArgumentList &TemplateArgs, - sema::TemplateDeductionInfo &Info); + sema::TemplateDeductionInfo &Info, + bool DontCanonicalize = false); TemplateDeductionResult DeduceTemplateArguments(VarTemplatePartialSpecializationDecl *Partial, const TemplateArgumentList &TemplateArgs, - sema::TemplateDeductionInfo &Info); + sema::TemplateDeductionInfo &Info, + bool DontCanonicalize = false); TemplateDeductionResult SubstituteExplicitTemplateArguments( FunctionTemplateDecl *FunctionTemplate, @@ -9533,6 +9538,13 @@ } }; + QualType resugar(const CXXScopeSpec &SS, NamedDecl *ND, + const TemplateArgumentListInfo *Args, QualType T, + bool Escapes = false, bool AsWritten = true); + QualType resugarEscapes(QualType T); + bool resugarTemplateArguments(const CXXScopeSpec &SS, + TemplateArgumentListInfo &Args); + void PerformPendingInstantiations(bool LocalOnly = false); TypeSourceInfo *SubstType(TypeSourceInfo *T, diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -2358,12 +2358,12 @@ return getTypeInfo(cast(T)->desugar().getTypePtr()); case Type::Typedef: { - const TypedefNameDecl *Typedef = cast(T)->getDecl(); - TypeInfo Info = getTypeInfo(Typedef->getUnderlyingType().getTypePtr()); + const auto *TT = cast(T); + TypeInfo Info = getTypeInfo(TT->desugar().getTypePtr()); // If the typedef has an aligned attribute on it, it overrides any computed // alignment we have. This violates the GCC documentation (which says that // attribute(aligned) can only round up) but matches its implementation. - if (unsigned AttrAlign = Typedef->getMaxAlignment()) { + if (unsigned AttrAlign = TT->getDecl()->getMaxAlignment()) { Align = AttrAlign; AlignRequirement = AlignRequirementKind::RequiredByTypedef; } else { @@ -4617,14 +4617,24 @@ /// specified typedef name decl. QualType ASTContext::getTypedefType(const TypedefNameDecl *Decl, QualType Underlying) const { - if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); - + if (!Decl->TypeForDecl) { + if (Underlying.isNull()) + Underlying = Decl->getUnderlyingType(); + auto *newType = new (*this, TypeAlignment) TypedefType( + Type::Typedef, Decl, QualType(), getCanonicalType(Underlying)); + Decl->TypeForDecl = newType; + Types.push_back(newType); + return QualType(newType, 0); + } if (Underlying.isNull()) - Underlying = Decl->getUnderlyingType(); - QualType Canonical = getCanonicalType(Underlying); - auto *newType = new (*this, TypeAlignment) - TypedefType(Type::Typedef, Decl, Underlying, Canonical); - Decl->TypeForDecl = newType; + return QualType(Decl->TypeForDecl, 0); + if (Decl->getUnderlyingType() == Underlying) + return QualType(Decl->TypeForDecl, 0); + + // FIXME: Unique + void *Mem = Allocate(sizeof(TypedefType) + sizeof(QualType), TypeAlignment); + auto *newType = new (Mem) TypedefType(Type::Typedef, Decl, Underlying, + getCanonicalType(Underlying)); Types.push_back(newType); return QualType(newType, 0); } @@ -4632,7 +4642,7 @@ 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); @@ -4640,11 +4650,14 @@ return QualType(T, 0); assert(!Underlying.hasLocalQualifiers()); - assert(Underlying == getTypeDeclType(cast(Found->getTargetDecl()))); QualType Canon = Underlying.getCanonicalType(); - - UsingType *NewType = - new (*this, TypeAlignment) UsingType(Found, Underlying, Canon); + if (Underlying.getTypePtr() == + cast(Found->getTargetDecl())->getTypeForDecl()) + 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); @@ -4737,9 +4750,6 @@ ASTContext::getSubstTemplateTypeParmType(const TemplateTypeParmType *Parm, QualType Replacement, Optional PackIndex) const { - assert(Replacement.isCanonical() - && "replacement types must always be canonical"); - llvm::FoldingSetNodeID ID; SubstTemplateTypeParmType::Profile(ID, Parm, Replacement, PackIndex); void *InsertPos = nullptr; @@ -4879,8 +4889,8 @@ 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); @@ -7194,8 +7204,7 @@ void ASTContext::setCFConstantStringType(QualType T) { const auto *TD = T->castAs(); CFConstantStringTypeDecl = cast(TD->getDecl()); - const auto *TagType = - CFConstantStringTypeDecl->getUnderlyingType()->castAs(); + const auto *TagType = TD->castAs(); CFConstantStringTagDecl = TagType->getDecl(); } diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -1361,8 +1361,12 @@ Expected ToDeclOrErr = import(T->getDecl()); if (!ToDeclOrErr) return ToDeclOrErr.takeError(); + ExpectedType ToUnderlyingTypeOrErr = import(T->desugar()); + if (!ToUnderlyingTypeOrErr) + return ToUnderlyingTypeOrErr.takeError(); - return Importer.getToContext().getTypeDeclType(*ToDeclOrErr); + return Importer.getToContext().getTypedefType(*ToDeclOrErr, + *ToUnderlyingTypeOrErr); } ExpectedType ASTNodeImporter::VisitTypeOfExprType(const TypeOfExprType *T) { @@ -1529,8 +1533,7 @@ return ToReplacementTypeOrErr.takeError(); return Importer.getToContext().getSubstTemplateTypeParmType( - *ReplacedOrErr, ToReplacementTypeOrErr->getCanonicalType(), - T->getPackIndex()); + *ReplacedOrErr, *ToReplacementTypeOrErr, T->getPackIndex()); } ExpectedType ASTNodeImporter::VisitSubstTemplateTypeParmPackType( 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 @@ -957,11 +957,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; 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 //===----------------------------------------------------------------------===// diff --git a/clang/lib/AST/FormatString.cpp b/clang/lib/AST/FormatString.cpp --- a/clang/lib/AST/FormatString.cpp +++ b/clang/lib/AST/FormatString.cpp @@ -976,10 +976,10 @@ bool FormatSpecifier::namedTypeToLengthModifier(QualType QT, LengthModifier &LM) { assert(isa(QT) && "Expected a TypedefType"); - const TypedefNameDecl *Typedef = cast(QT)->getDecl(); + const auto *TT = cast(QT); - for (;;) { - const IdentifierInfo *Identifier = Typedef->getIdentifier(); + do { + const IdentifierInfo *Identifier = TT->getDecl()->getIdentifier(); if (Identifier->getName() == "size_t") { LM.setKind(LengthModifier::AsSizeT); return true; @@ -997,12 +997,6 @@ LM.setKind(LengthModifier::AsPtrDiff); return true; } - - QualType T = Typedef->getUnderlyingType(); - if (!isa(T)) - break; - - Typedef = cast(T)->getDecl(); - } + } while ((TT = TT->desugar()->getAs())); return false; } diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp --- a/clang/lib/AST/JSONNodeDumper.cpp +++ b/clang/lib/AST/JSONNodeDumper.cpp @@ -530,6 +530,8 @@ void JSONNodeDumper::VisitTypedefType(const TypedefType *TT) { JOS.attribute("decl", createBareDeclRef(TT->getDecl())); + if (TT->hasDifferentUnderlyingType()) + JOS.attribute("type", createQualType(TT->desugar())); } void JSONNodeDumper::VisitFunctionType(const FunctionType *T) { diff --git a/clang/lib/AST/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) { diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -3434,25 +3434,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(); } diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -1264,10 +1264,11 @@ assert(Ty->isTypeAlias()); llvm::DIType *Src = getOrCreateType(Ty->getAliasedType(), Unit); - auto *AliasDecl = - cast(Ty->getTemplateName().getAsTemplateDecl()) - ->getTemplatedDecl(); + const TemplateDecl *TD = Ty->getTemplateName().getAsTemplateDecl(); + if (isa(TD)) + return Src; + const auto *AliasDecl = cast(TD)->getTemplatedDecl(); if (AliasDecl->hasAttr()) return Src; diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2178,6 +2178,7 @@ } SmallVector DeclsInGroup; + // FIXME: pump SS thorugh from DS. Decl *FirstDecl = ParseDeclarationAfterDeclaratorAndAttributes( D, ParsedTemplateInfo(), FRI); if (LateParsedAttrs.size() > 0) @@ -2467,6 +2468,7 @@ SkipUntil(StopTokens, StopAtSemi | StopBeforeMatch); Actions.ActOnInitializerError(ThisDecl); } else + // FIXME: pump SS through Actions.AddInitializerToDecl(ThisDecl, Init.get(), /*DirectInit=*/false); } diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp --- a/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -736,6 +736,7 @@ QualType T = Context.getTypeDeclType(cast(SD->getUnderlyingDecl())); + T = resugar(SS, /*NamedDecl=*/nullptr, /*Args=*/nullptr, T); if (T->isEnumeralType()) Diag(IdInfo.IdentifierLoc, diag::warn_cxx98_compat_enum_nested_name_spec); @@ -875,17 +876,19 @@ QualType T = BuildDecltypeType(DS.getRepAsExpr()); if (T.isNull()) return true; + T = resugar(SS, /*NamedDecl=*/nullptr, /*Args=*/nullptr, 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,6 +934,7 @@ // Handle a dependent template specialization for which we cannot resolve // the template name. assert(DTN->getQualifier() == SS.getScopeRep()); + resugarTemplateArguments(SS, TemplateArgs); QualType T = Context.getDependentTemplateSpecializationType(ETK_None, DTN->getQualifier(), DTN->getIdentifier(), @@ -975,18 +979,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 +994,13 @@ for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I) SpecTL.setArgLocInfo(I, TemplateArgs[I].getLocInfo()); + // Alias template specializations can produce types which are not valid + // nested name specifiers. + if (!T->isDependentType() && !T->getAs()) { + Diag(TemplateNameLoc, diag::err_nested_name_spec_non_tag) << T; + NoteAllFoundTemplates(Template); + return true; + } SS.Extend(Context, TemplateKWLoc, Builder.getTypeLocInContext(Context, T), CCLoc); diff --git a/clang/lib/Sema/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 @@ -555,9 +555,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()) { @@ -576,12 +578,12 @@ DeclAccessPair::make(IFD, AS_public), RecordArg, Loc) : S.BuildFieldReferenceExpr( RecordArg, RecordArgIsPtr, Loc, CXXScopeSpec(), FD, - DeclAccessPair::make(FD, AS_public), + 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. @@ -590,7 +592,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/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 @@ -491,6 +491,8 @@ DiagnoseUseOfDecl(IIDecl, NameLoc); T = Context.getTypeDeclType(TD); + T = resugar(SS && SS->isValid() ? *SS : CXXScopeSpec(), TD, + /*Args=*/nullptr, T); MarkAnyDeclReferenced(TD->getLocation(), TD, /*OdrUse=*/false); } else if (ObjCInterfaceDecl *IDecl = dyn_cast(IIDecl)) { (void)DiagnoseUseOfDecl(IDecl, NameLoc); @@ -12135,9 +12137,12 @@ // is present, e has type cv A if (VDecl && isa(VDecl) && Context.hasSameUnqualifiedType(Type, Context.getAutoDeductType()) && - DeduceInit->getType()->isConstantArrayType()) - return Context.getQualifiedType(DeduceInit->getType(), - Type.getQualifiers()); + DeduceInit->getType()->isConstantArrayType()) { + QualType T = DeduceInit->getType(); + // Remove any substitution sugar. + T = resugarEscapes(T); + return Context.getQualifiedType(T, Type.getQualifiers()); + } QualType DeducedType; if (DeduceAutoType(TSI, DeduceInit, DeducedType) == DAR_Failed) { @@ -12938,6 +12943,7 @@ (LangOpts.OpenMPIsDevice || !LangOpts.OMPTargetTriples.empty()) && VDecl->isFileVarDecl()) DeclsToCheckForDeferredDiags.insert(VDecl); + // FIXME: wire SS through CheckCompleteVariableDeclaration(VDecl); } @@ -13644,6 +13650,7 @@ // Build the bindings if this is a structured binding declaration. if (auto *DD = dyn_cast(var)) + // FIXME: wire SS through CheckCompleteDecompositionDeclaration(DD); } 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,11 @@ if (FD->isUnnamedBitfield()) continue; + // FIXME: get SS + QualType FieldType = FD->getType(); + FieldType = + S.resugar(CXXScopeSpec(), FD, nullptr, FieldType, /*Escapes=*/true); + // All the non-static data members are required to be nameable, so they // must all have names. if (!FD->getDeclName()) { @@ -1412,7 +1418,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 +1450,7 @@ if (E.isInvalid()) return true; E = S.BuildFieldReferenceExpr(E.get(), /*IsArrow*/ false, Loc, - CXXScopeSpec(), FD, + CXXScopeSpec(), FD, FieldType, DeclAccessPair::make(FD, FD->getAccess()), DeclarationNameInfo(FD->getDeclName(), Loc)); if (E.isInvalid()) @@ -1458,7 +1464,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()) @@ -1532,6 +1538,7 @@ // C++1z [dcl.decomp]/4: // all of E's non-static data members shall be [...] direct members of // E or of the same unambiguous public base class of E, ... + // FIXME: wire SS through if (checkMemberDecomposition(*this, Bindings, DD, DecompType, RD)) DD->setInvalidDecl(); } @@ -8251,10 +8258,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), + CXXScopeSpec(), Field, FieldType, Found, + NameInfo), S.BuildFieldReferenceExpr(Obj.second.get(), /*IsArrow=*/false, Loc, - CXXScopeSpec(), Field, Found, NameInfo)}; + CXXScopeSpec(), Field, FieldType, Found, + NameInfo)}; } // FIXME: When expanding a subobject, register a note in the code synthesis @@ -11563,8 +11573,8 @@ Args.addArgument(TemplateArgumentLoc(TemplateArgument(Element), Context.getTrivialTypeSourceInfo(Element, Loc))); - return Context.getCanonicalType( - CheckTemplateIdType(TemplateName(StdInitializerList), Loc, Args)); + return Context.getCanonicalType(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 @@ -3310,6 +3310,12 @@ 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 = resugar(SS, VD, TemplateArgs, type, /*Escapes=*/true); ExprValueKind valueKind = VK_PRValue; // In 'T ...V;', the type of the declaration 'V' is 'T...', but the type of @@ -9978,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; } @@ -14252,14 +14259,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) @@ -20621,6 +20632,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 @@ -4239,7 +4239,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. 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 @@ -849,10 +849,13 @@ // Make a nameInfo that properly uses the anonymous name. DeclarationNameInfo memberNameInfo(field->getDeclName(), loc); + QualType FieldType = field->getType(); + FieldType = resugar(SS, field, nullptr, FieldType, /*Escapes=*/true); + // Build the first member access in the chain with full information. result = BuildFieldReferenceExpr(result, baseObjectIsPointer, SourceLocation(), - SS, field, foundDecl, memberNameInfo) + SS, field, FieldType, foundDecl, memberNameInfo) .get(); if (!result) return ExprError(); @@ -869,9 +872,13 @@ DeclAccessPair fakeFoundDecl = DeclAccessPair::make(field, field->getAccess()); + // FIXME: duplication above. Also, is SS right here? + QualType FieldType = field->getType(); + FieldType = resugar(SS, field, nullptr, FieldType, /*Escapes=*/true); + result = BuildFieldReferenceExpr(result, /*isarrow*/ false, SourceLocation(), - (FI == FEnd ? SS : EmptySS), field, + (FI == FEnd ? SS : EmptySS), field, FieldType, fakeFoundDecl, memberNameInfo) .get(); } @@ -1094,11 +1101,19 @@ 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)) { + QualType FieldType = FD->getType(); + // FIXME: Extend SS here with BaseType? + FieldType = resugar(SS, FD, TemplateArgs, FieldType, /*Escapes=*/true); + // FIXME: these should take in BaseType as well, because BaseExpr might be + // null + // in case of implicit access. + return BuildFieldReferenceExpr(BaseExpr, IsArrow, OpLoc, SS, FD, FieldType, + FoundDecl, MemberNameInfo); + } if (MSPropertyDecl *PD = dyn_cast(MemberDecl)) + // FIXME: resugar these. return BuildMSPropertyRefExpr(*this, BaseExpr, IsArrow, SS, PD, MemberNameInfo); @@ -1110,9 +1125,11 @@ OpLoc); if (VarDecl *Var = dyn_cast(MemberDecl)) { + QualType VarType = Var->getType(); + VarType = resugar(SS, Var, TemplateArgs, VarType, /*Escapes=*/true); return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, &SS, TemplateKWLoc, Var, FoundDecl, /*HadMultipleCandidates=*/false, - MemberNameInfo, Var->getType().getNonReferenceType(), + MemberNameInfo, VarType.getNonReferenceType(), VK_LValue, OK_Ordinary); } @@ -1125,6 +1142,7 @@ } else { valueKind = VK_LValue; type = MemberFn->getType(); + type = resugar(SS, MemberFn, TemplateArgs, type, /*Escapes=*/true); } return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, &SS, TemplateKWLoc, @@ -1134,6 +1152,8 @@ assert(!isa(MemberDecl) && "member function not C++ method?"); if (EnumConstantDecl *Enum = dyn_cast(MemberDecl)) { + QualType EnumType = Enum->getType(); + EnumType = resugar(SS, Enum, TemplateArgs, EnumType, /*Escapes=*/true); return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, &SS, TemplateKWLoc, Enum, FoundDecl, /*HadMultipleCandidates=*/false, MemberNameInfo, Enum->getType(), VK_PRValue, @@ -1161,10 +1181,13 @@ if (!Var->getTemplateSpecializationKind()) Var->setTemplateSpecializationKind(TSK_ImplicitInstantiation, MemberLoc); + QualType VarType = Var->getType(); + VarType = resugar(SS, Var, TemplateArgs, VarType, /*Escapes=*/true); + return BuildMemberExpr( BaseExpr, IsArrow, OpLoc, &SS, 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 +1819,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 CXXScopeSpec &SS, + 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 +1839,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,21 +1856,21 @@ 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); @@ -1875,7 +1896,7 @@ return BuildMemberExpr(Base.get(), IsArrow, OpLoc, &SS, /*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 @@ -8214,9 +8214,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()) @@ -10002,6 +10002,8 @@ TSInfo->getType()->getContainedDeducedType()); assert(DeducedTST && "not a deduced template specialization type"); + MultiExprArg OrigInits = Inits; + auto TemplateName = DeducedTST->getTemplateName(); if (TemplateName.isDependent()) return SubstAutoTypeDependent(TSInfo->getType()); @@ -10238,12 +10240,14 @@ MarkFunctionReferenced(Kind.getLocation(), Best->Function); break; } + QualType RT = Best->Function->getReturnType(); + // FIXME: resugar these + RT = resugar(CXXScopeSpec(), Best->Function, nullptr, RT, /*Escapes=*/true); // 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 @@ -3470,8 +3470,9 @@ SmallVector Checked; TemplateArgumentLoc Arg(TemplateArgument(StringLit), StringLit); if (CheckTemplateArgument(Params->getParam(0), Arg, FD, - R.getNameLoc(), R.getNameLoc(), 0, - Checked) || + R.getNameLoc(), R.getNameLoc(), 0, Checked, + CTAK_Specified, + /*DontCanonicalize=*/true) || 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 @@ -5685,9 +5685,6 @@ Sema::CCEKind CCE, bool RequireInt, NamedDecl *Dest) { - assert(S.getLangOpts().CPlusPlus11 && - "converted constant expression outside C++11"); - if (checkPlaceholderForOverload(S, From)) return ExprError(); @@ -6326,7 +6323,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"); @@ -6345,7 +6342,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 @@ -6390,6 +6387,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 @@ -6903,16 +6901,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"); @@ -6943,6 +6938,7 @@ Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; Candidate.ExplicitCallArguments = Args.size(); + Candidate.Deduced = Deduced; unsigned NumParams = Proto->getNumParams(); @@ -7120,7 +7116,7 @@ AddMethodCandidate(cast(Specialization), FoundDecl, ActingContext, ObjectType, ObjectClassification, Args, CandidateSet, SuppressUserConversions, PartialOverloading, - Conversions, PO); + Conversions, PO, Info.take()); } /// Determine whether a given function template has a simple explicit specifier @@ -7200,10 +7196,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.take()); } /// Check that implicit conversion sequences can be formed for each argument @@ -12041,15 +12038,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 @@ -12068,9 +12070,6 @@ return; } - if (OvlExpr->hasExplicitTemplateArgs()) - OvlExpr->copyTemplateArgumentsInto(OvlExplicitTemplateArgs); - if (FindAllFunctionsThatMatchTargetTypeExactly()) { // C++ [over.over]p4: // If more than one function is selected, [...] @@ -12556,7 +12555,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 @@ -12574,10 +12574,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). ] @@ -12585,12 +12584,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 @@ -12666,50 +12662,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; + } + } } } @@ -13222,7 +13222,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); @@ -13280,7 +13281,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); @@ -14552,7 +14554,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. @@ -15167,11 +15170,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; @@ -15179,8 +15184,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"); @@ -15195,8 +15200,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; @@ -15218,6 +15223,17 @@ return GSE; } + QualType Type = Fn->getType(); + TemplateArgumentListInfo Args; + if (Deduced) { + Sema::SFINAETrap Trap(*this); + for (const TemplateArgument &I : Deduced->asArray()) + Args.addArgument( + getTrivialTemplateArgumentLoc(I, QualType(), SourceLocation())); + } + Type = resugar(CXXScopeSpec(), Fn, &Args, Type, /*Escapes=*/true, + /*AsWritten=*/false); + if (UnaryOperator *UnOp = dyn_cast(E)) { assert(UnOp->getOpcode() == UO_AddrOf && "Can only take the address of an overloaded function"); @@ -15230,7 +15246,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; @@ -15244,8 +15260,8 @@ // appropriate pointer to member type. QualType ClassType = Context.getTypeDeclType(cast(Method->getDeclContext())); - QualType MemPtrType - = Context.getMemberPointerType(Fn->getType(), ClassType.getTypePtr()); + 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); @@ -15255,8 +15271,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; @@ -15273,7 +15289,6 @@ TemplateArgs = &TemplateArgsBuffer; } - QualType Type = Fn->getType(); ExprValueKind ValueKind = getLangOpts().CPlusPlus ? VK_LValue : VK_PRValue; // FIXME: Duplicated from BuildDeclarationNameExpr. @@ -15305,10 +15320,10 @@ // 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); + DeclRefExpr *DRE = + BuildDeclRefExpr(Fn, Type, VK_LValue, MemExpr->getNameInfo(), + MemExpr->getQualifierLoc(), Found.getDecl(), + MemExpr->getTemplateKeywordLoc(), TemplateArgs); DRE->setHadMultipleCandidates(MemExpr->getNumDecls() > 1); return DRE; } else { @@ -15322,29 +15337,28 @@ Base = MemExpr->getBase(); ExprValueKind valueKind; - QualType type; if (cast(Fn)->isStatic()) { valueKind = VK_LValue; - type = 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); } 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" @@ -90,6 +91,1183 @@ return Depth; } +static TemplateArgumentLoc +getNullTemplateArgumentLoc(ASTContext &Context, const TemplateArgument &A) { + switch (A.getKind()) { + case TemplateArgument::Type: + return TemplateArgumentLoc( + A, TemplateArgumentLocInfo((TypeSourceInfo *)nullptr)); + case TemplateArgument::Template: + case TemplateArgument::TemplateExpansion: { + const auto &T = A.getAsTemplateOrTemplatePattern(); + + NestedNameSpecifier *NNS = nullptr; + if (const QualifiedTemplateName *QTN = T.getAsQualifiedTemplateName()) + NNS = QTN->getQualifier(); + else if (const DependentTemplateName *DTN = T.getAsDependentTemplateName()) + NNS = DTN->getQualifier(); + NestedNameSpecifierLocBuilder Builder; + Builder.MakeTrivial(Context, NNS, SourceRange()); + + return TemplateArgumentLoc( + A, + TemplateArgumentLocInfo(Context, Builder.getWithLocInContext(Context), + SourceLocation(), SourceLocation())); + } + default: + return TemplateArgumentLoc(A, TemplateArgumentLocInfo()); + } + llvm_unreachable(""); +} + +TemplateDecl *getTemplateDecl(NamedDecl *D) { + if (!D) + return nullptr; + switch (auto K = 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 (auto K = FD->getTemplatedKind()) { + case FunctionDecl::TK_NonTemplate: + 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; + default: + break; + } + 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 { + llvm::SmallPtrSet Parms; + ArrayRef Args; + }; + Inner CurInner; + + using ParmToArgs = + llvm::DenseMap>; + ParmToArgs CurParmToArgs; + + SmallVector, 4> ArgsBuf; + + const TemplateArgument *getArgument(const NamedDecl *ND, unsigned Index, + Optional PackIndex) const { + ArrayRef Args; + if (!CurInner.Args.empty() && CurInner.Parms.contains(ND)) + Args = CurInner.Args; + else { + auto It = CurParmToArgs.find(ND); + if (It == CurParmToArgs.end()) + return nullptr; + Args = It->second; + } + const TemplateArgument &Arg = Args[Index]; + return PackIndex ? &Arg.getPackAsArray()[*PackIndex] : &Arg; + } + + 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::exchange(R.CurInner, {})) {} + ~NonTemplateSemanticContextRAII() { R->CurInner = std::move(OldInner); } + + protected: + Resugarer *R; + + private: + Inner OldInner; + }; + + struct SemanticContextRAII : private NonTemplateSemanticContextRAII { + SemanticContextRAII(Resugarer &R, NamedDecl *ND, + const TemplateArgumentListInfo *Args, + bool AsWritten = true) + : NonTemplateSemanticContextRAII(R), OldArgsBufSize(R.ArgsBuf.size()) { + if (!Args || Args->size() == 0) + return; + TemplateDecl *TD = getTemplateDecl(ND); + if (!TD) + return; + for (const NamedDecl *TP : TD->getTemplateParameters()->asArray()) + R.CurInner.Parms.insert(TP); + + SmallVector ConvertedArgs; + if (!AsWritten) { + ConvertedArgs.reserve(Args->arguments().size()); + for (const TemplateArgumentLoc &I : Args->arguments()) + ConvertedArgs.push_back(I.getArgument()); + R.CurInner.Args = R.ArgsBuf.emplace_back(std::move(ConvertedArgs)); + return; + } + + Sema::SFINAETrap Trap(R.SemaRef); + if (R.SemaRef.CheckTemplateArgumentList( + TD, SourceLocation(), + *const_cast(Args), false, + ConvertedArgs, + /*UpdateArgsWithConversions=*/false, + /*ConstrantsNotSatisfied=*/nullptr, + /*DontCanonicalize=*/true)) + llvm_unreachable("Unexpected conversion failure"); + 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, + /*DontCaninicalize=*/true); + if (Res != Sema::TDK_Success) + break; + R.CurInner.Args = Info.take()->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), OldParmToArgs(std::move(R.CurParmToArgs)), + OldArgsBufSize(R.ArgsBuf.size()) {} + ~NamingContextBase() { + R->CurParmToArgs = std::move(OldParmToArgs); + R->ArgsBuf.resize(OldArgsBufSize); + } + + protected: + void insertTPLToMap(bool Reverse, const TemplateParameterList *TPL, + ArrayRef Args) { + assert(!Args.empty()); + if (Reverse) { + for (const NamedDecl *TP : TPL->asArray()) + if (!R->CurParmToArgs.try_emplace(TP, Args).second) + break; + } else { + for (const NamedDecl *TP : TPL->asArray()) + R->CurParmToArgs[TP] = Args; + } + } + + void deduceClassTemplatePartialSpecialization( + ClassTemplatePartialSpecializationDecl *D, bool Reverse, + ArrayRef Args) { + TemplateParameterList *TPL = D->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( + D, TemplateArgumentList(TemplateArgumentList::OnStackType{}, Args), + Info, + /*DontCaninicalize=*/true); + if (Res != Sema::TDK_Success) + return; + insertTPLToMap(Reverse, TPL, Info.take()->asArray()); + } + + 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()) { + default: + Entity.ND->dumpColor(); + llvm_unreachable(""); + case Decl::CXXRecord: + return; + case Decl::ClassTemplateSpecialization: + case Decl::ClassTemplatePartialSpecialization: + if (!Entity.TS) + return; + assert(!Entity.TS->isTypeAlias()); + ArrayRef Args = Entity.TS->template_arguments(); + + if (NDK == Decl::ClassTemplatePartialSpecialization) + return deduceClassTemplatePartialSpecialization( + cast(Entity.ND), Reverse, + Args); + + auto *CTSD = cast(Entity.ND); + TemplateArgumentListInfo ArgsInfo; + for (auto &&I : Args) + ArgsInfo.addArgument(R->SemaRef.getTrivialTemplateArgumentLoc( + I, /*NTTPType=*/QualType(), SourceLocation())); + + ClassTemplateDecl *TD = CTSD->getSpecializedTemplate(); + SmallVector ConvertedArgs; + if (R->SemaRef.CheckTemplateArgumentList( + TD, SourceLocation(), ArgsInfo, false, ConvertedArgs, + /*UpdateArgsWithConversions=*/false, + /*ConstrantsNotSatisfied=*/nullptr, + /*DontCanonicalize=*/true)) + llvm_unreachable("Unexpected conversion failure"); + if (auto *CTPSD = + CTSD->getSpecializedTemplateOrPartial() + .dyn_cast()) + return deduceClassTemplatePartialSpecialization(CTPSD, Reverse, + ConvertedArgs); + return insertTPLToMap( + Reverse, TD->getTemplateParameters(), + R->ArgsBuf.emplace_back(std::move(ConvertedArgs))); + } + llvm_unreachable("Unhandled IDC Kind"); + } + + Resugarer *R; + ParmToArgs OldParmToArgs; + + private: + size_t OldArgsBufSize; + }; + + struct NamingContextRAII : NamingContextBase { + NamingContextRAII(Resugarer &R, const NestedNameSpecifier *NNS) + : NamingContextBase(R) { + for (/**/; NNS; NNS = NNS->getPrefix()) { + switch (auto NNSK = 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 : OldParmToArgs) { + auto &P = R.CurParmToArgs[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.CurParmToArgs.copyFrom(OldParmToArgs); + + 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 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(); + const TemplateTypeParmType *Replaced = T->getReplacedParameter(); + + Optional PackIndex = T->getPackIndex(); + if (const TemplateArgument *Arg = + getArgument(Replaced->getDecl(), Replaced->getIndex(), PackIndex)) { + QualType Replacement = Arg->getAsType().getNonPackExpansionType(); + if (!SemaRef.Context.hasSameType(Replacement, T->getReplacementType())/* && + Replacement->getTypeClass() != Type::Decltype && + T->getReplacementType()->getTypeClass() != Type::Decltype*/) { + Replacement.dump(); + T->getReplacementType().dump(); + assert(false); + } + if (Replacement != T->getReplacementType()) + QT = SemaRef.Context.getSubstTemplateTypeParmType(Replaced, Replacement, + PackIndex); + } + auto NewTL = TLB.push(QT); + NewTL.setNameLoc(TL.getNameLoc()); + return QT; + } + + using inherited::TransformTemplateSpecializationType; + + template + QualType TransformTemplateSpecializationType( + TemplateName N, bool IsTypeAlias, ArgIterator First, ArgIterator Last, + TemplateArgumentListInfo &NewArgs, QualType Underlying) { + if (const SubstTemplateTemplateParmStorage *STTP = + N.getAsSubstTemplateTemplateParm()) { + // FIXME: Resugar default arguments on template template parameters. + // The AST currently cannot represent this. + if (TransformTemplateArguments(First, Last, NewArgs)) + llvm_unreachable(""); + } else { + if (TransformTemplateArguments(First, Last, NewArgs)) + llvm_unreachable(""); + } + if (IsTypeAlias) { + SemanticContextRAII SemanticScope(*this, N.getAsTemplateDecl(), &NewArgs); + Underlying = TransformType(Underlying); + } + return SemaRef.Context.getTemplateSpecializationType(N, NewArgs, + Underlying); + } + + QualType TransformTemplateSpecializationType(TypeLocBuilder &TLB, + TemplateSpecializationTypeLoc TL, + TemplateName N) { + const TemplateSpecializationType *T = TL.getTypePtr(); + + TemplateArgumentListInfo NewArgs; + NewArgs.setLAngleLoc(TL.getLAngleLoc()); + NewArgs.setRAngleLoc(TL.getRAngleLoc()); + using Iter = + TemplateArgumentLocContainerIterator; + QualType Result = TransformTemplateSpecializationType( + N, T->isTypeAlias(), Iter(TL, 0), Iter(TL, TL.getNumArgs()), NewArgs, + T->desugar()); + 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 = NewArgs.size(); i != e; ++i) + NewTL.setArgLocInfo(i, NewArgs[i].getLocInfo()); + return Result; + } + + template + QualType TransformDependentTemplateSpecializationType( + ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, + const IdentifierInfo *ID, ArgIterator First, ArgIterator Last, + TemplateArgumentListInfo &NewArgs) { + if (TransformTemplateArguments(First, Last, NewArgs)) + llvm_unreachable(""); + // FIXME: don't rebuild if nothing changed. + return SemaRef.Context.getDependentTemplateSpecializationType(Keyword, NNS, + ID, NewArgs); + } + + template + QualType TransformDependentTemplateSpecializationType( + ElaboratedTypeKeyword Keyword, NestedNameSpecifierLoc &NNS, + const IdentifierInfo *ID, ArgIterator First, ArgIterator Last, + TemplateArgumentListInfo &NewArgs) { + NamingContextTransformRAII NamingScope(*this, NNS); + return TransformDependentTemplateSpecializationType( + Keyword, NNS.getNestedNameSpecifier(), ID, First, Last, NewArgs); + } + + QualType TransformDependentTemplateSpecializationType( + TypeLocBuilder &TLB, DependentTemplateSpecializationTypeLoc TL) { + const DependentTemplateSpecializationType *T = TL.getTypePtr(); + TemplateArgumentListInfo NewArgs; + NewArgs.setLAngleLoc(TL.getLAngleLoc()); + NewArgs.setRAngleLoc(TL.getRAngleLoc()); + + using Iter = TemplateArgumentLocContainerIterator< + DependentTemplateSpecializationTypeLoc>; + NestedNameSpecifierLoc NNS = TL.getQualifierLoc(); + QualType Result = TransformDependentTemplateSpecializationType( + T->getKeyword(), NNS, T->getIdentifier(), Iter(TL, 0), + Iter(TL, TL.getNumArgs()), NewArgs); + + 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 = NewArgs.size(); i != e; ++i) + NewTL.setArgLocInfo(i, NewArgs[i].getLocInfo()); + return Result; + } + + TypeSourceInfo *TransformTSIInObjectScope(TypeLoc TL, QualType, NamedDecl *, + CXXScopeSpec &) { + llvm_unreachable("unused"); + } + + QualType TransformDependentTemplateSpecializationType( + TypeLocBuilder &, DependentTemplateSpecializationTypeLoc, TemplateName, + CXXScopeSpec &) { + llvm_unreachable("unused"); + } + + TemplateName TransformTemplateName(CXXScopeSpec &SS, TemplateName Name, + SourceLocation NameLoc, + QualType ObjectType = QualType(), + NamedDecl *FirstQualifierInScope = nullptr, + bool AllowInjectedClassName = false) { + if (Name.getKind() == TemplateName::NameKind::SubstTemplateTemplateParm) + return Name; // 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) { + const TemplateArgument &Arg = Input.getArgument(); + switch (Arg.getKind()) { + case TemplateArgument::Null: + llvm_unreachable("Unexpected Null TemplateArgument"); + case TemplateArgument::Pack: { + TemplateArgumentListInfo Ins; + for (const TemplateArgument &I : Arg.getPackAsArray()) + Ins.addArgument(getNullTemplateArgumentLoc(SemaRef.Context, I)); + TemplateArgumentListInfo Outs; + TransformTemplateArguments(Ins.arguments().begin(), Ins.arguments().end(), + Outs); + SmallVector ROuts(Outs.size()); + for (unsigned I = 0; I < Outs.size(); ++I) + ROuts[I] = Outs[I].getArgument(); + Output = TemplateArgumentLoc( + TemplateArgument::CreatePackCopy(SemaRef.Context, ROuts), + Input.getLocInfo()); + return false; + } + case TemplateArgument::Integral: + case TemplateArgument::NullPtr: + case TemplateArgument::Declaration: { + // Transform a resolved template argument straight to a resolved template + // argument. We get here when substituting into an already-substituted + // template type argument during concept satisfaction checking. + QualType T = Arg.getNonTypeTemplateArgumentType(); + QualType NewT = TransformType(T); + assert(!NewT.isNull()); + if (NewT == T) + Output = Input; + else if (Arg.getKind() == TemplateArgument::Integral) + Output = TemplateArgumentLoc( + TemplateArgument(SemaRef.Context, Arg.getAsIntegral(), NewT), + Input.getLocInfo()); + else if (Arg.getKind() == TemplateArgument::NullPtr) + Output = TemplateArgumentLoc(TemplateArgument(NewT, /*IsNullPtr=*/true), + Input.getLocInfo()); + else + Output = TemplateArgumentLoc(TemplateArgument(Arg.getAsDecl(), NewT), + Input.getLocInfo()); + return false; + } + + case TemplateArgument::Type: { + if (Arg.isPackExpansion()) { + QualType T = TransformType(Arg.getAsType()); + assert(!T.isNull()); + Output = TemplateArgumentLoc(TemplateArgument(T), Input.getLocInfo()); + return false; + } + TypeSourceInfo *DI = Input.getTypeSourceInfo(); + if (!DI) + DI = InventTypeSourceInfo(Arg.getAsType()); + + DI = TransformType(DI); + if (!DI) + return true; + + Output = TemplateArgumentLoc(TemplateArgument(DI->getType()), DI); + return false; + } + + case TemplateArgument::Template: { + NestedNameSpecifierLoc QualifierLoc = Input.getTemplateQualifierLoc(); + NamingContextTransformRAII NamingContext(*this, QualifierLoc); + + CXXScopeSpec SS; + SS.Adopt(QualifierLoc); + TemplateName Template = TransformTemplateName(SS, Arg.getAsTemplate(), + Input.getTemplateNameLoc()); + assert(!Template.isNull()); + + Output = TemplateArgumentLoc(SemaRef.Context, TemplateArgument(Template), + QualifierLoc, Input.getTemplateNameLoc()); + return false; + } + + case TemplateArgument::TemplateExpansion: { + Output = TemplateArgumentLoc( + TemplateArgument(Arg.getAsTemplateOrTemplatePattern(), + Arg.getNumTemplateExpansions()), + Input.getLocInfo()); + return false; + } + case TemplateArgument::Expression: { + // FIXME: convert the type of these. + Output = Input; + return false; + } + } + llvm_unreachable("Unexpected TemplateArgument kind"); + } + + template + bool TransformTemplateArguments(InputIterator First, InputIterator Last, + TemplateArgumentListInfo &Outputs, + bool Uneval = true) { + for (; First != Last; ++First) { + TemplateArgumentLoc Out; + if (TransformTemplateArgument(*First, Out, Uneval)) + llvm_unreachable(""); + Outputs.addArgument(Out); + } + return false; + } + + QualType TransformPackExpansionType(TypeLocBuilder &TLB, + PackExpansionTypeLoc TL) { + QualType Pattern = TransformType(TLB, TL.getPatternLoc()); + assert(!Pattern.isNull()); + + QualType Result = TL.getType(); + if (Pattern != TL.getPatternLoc().getType()) { + Result = SemaRef.Context.getPackExpansionType( + Pattern, TL.getTypePtr()->getNumExpansions(), + /*ExpectPackInType=*/false); + } + + 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(); + + TemplateArgumentListInfo NewArgs; + if (T->isConstrained()) { + NewArgs.setLAngleLoc(TL.getLAngleLoc()); + NewArgs.setRAngleLoc(TL.getRAngleLoc()); + using Iter = TemplateArgumentLocContainerIterator; + if (TransformTemplateArguments(Iter(TL, 0), Iter(TL, TL.getNumArgs()), + NewArgs)) + llvm_unreachable(""); + } + + QualType Deduced = !T->getDeducedType().isNull() + ? TransformType(T->getDeducedType()) + : QualType(); + + QualType Result = TL.getType(); + if (Deduced != T->getDeducedType()) { + NNS = TL.getNestedNameSpecifierLoc(); + NamingContextTransformRAII NamingContext(*this, NNS); + // FIXME: Maybe don't rebuild if all template arguments are the same. + llvm::SmallVector TypeConstraintArgs(NewArgs.size()); + for (const auto &ArgLoc : NewArgs.arguments()) + TypeConstraintArgs.push_back(ArgLoc.getArgument()); + Result = SemaRef.Context.getAutoType( + Deduced, T->getKeyword(), T->isInstantiationDependentType(), + 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, NewArgs[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); + } + auto NewTL = 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, NamedDecl *ND, + const TemplateArgumentListInfo *Args, QualType T, bool, + bool AsWritten) { + if (!getLangOpts().Resugar) + return T; + Resugarer R(*this); + Resugarer::NamingContextRAII NamingScope(R, SS.getScopeRep()); + Resugarer::SemanticContextRAII SemanticScope(R, ND, Args, AsWritten); + return R.TransformType(T); +} + +QualType Sema::resugarEscapes(QualType T) { return T; } + +bool Sema::resugarTemplateArguments(const CXXScopeSpec &SS, + TemplateArgumentListInfo &Args) { + if (!getLangOpts().Resugar) + return false; + + Resugarer R(*this); + Resugarer::NamingContextRAII NamingScope(R, SS.getScopeRep()); + Resugarer::NonTemplateSemanticContextRAII SemanticScope(R); + TemplateArgumentListInfo NewArgs; + if (R.TransformTemplateArguments(Args.arguments().begin(), + Args.arguments().end(), NewArgs)) + llvm_unreachable("Unexpected failure"); + for (unsigned I = 0; I < Args.size(); ++I) + if (!Args[I].getArgument().structurallyEquals(NewArgs[I].getArgument())) { + Args = std::move(NewArgs); + return true; + } + return false; +} + +static QualType getResugaredTemplateSpecializationType( + Sema &S, NestedNameSpecifier *NNS, TemplateName Template, + TemplateArgumentListInfo &Args, QualType Underlying = QualType()) { + if (!S.getLangOpts().Resugar) + return S.Context.getTemplateSpecializationType(Template, Args, Underlying); + Resugarer R(S); + Resugarer::NamingContextRAII NamingScope(R, NNS); + const auto *TD = Template.getAsTemplateDecl(); + bool IsTypeAlias = !Underlying.isNull() && TD && TD->isTypeAlias(); + TemplateArgumentListInfo NewArgs; + QualType Result = R.TransformTemplateSpecializationType( + Template, IsTypeAlias, Args.arguments().begin(), Args.arguments().end(), + NewArgs, Underlying); + Args = std::move(NewArgs); + return Result; +} + /// \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,7 +2769,8 @@ TemplateArgument Converted; ExprResult DefaultRes = - CheckTemplateArgument(Param, Param->getType(), Default, Converted); + CheckTemplateArgument(Param, Param->getType(), Default, Converted, + CTAK_Specified, /*DontCanonicalize=*/false); if (DefaultRes.isInvalid()) { Param->setInvalidDecl(); return Param; @@ -3442,7 +4621,8 @@ } static QualType -checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD, +checkBuiltinTemplateIdType(Sema &SemaRef, const CXXScopeSpec &SS, + TemplateName Name, BuiltinTemplateDecl *BTD, const SmallVectorImpl &Converted, SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs) { @@ -3474,7 +4654,17 @@ TemplateArgumentListInfo SyntheticTemplateArgs; // The type argument gets reused as the first template argument in the // synthetic template argument list. - SyntheticTemplateArgs.addArgument(TemplateArgs[1]); + auto *TTPD = + cast(BTD->getTemplateParameters()->getParam(1)); + const auto *TTP = cast( + SemaRef.Context.getTemplateTypeParmType(0, 1, false, TTPD)); + QualType OrigType = TemplateArgs[1].getArgument().getAsType(); + QualType SyntheticType = + SemaRef.Context.getSubstTemplateTypeParmType(TTP, OrigType, 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) { @@ -3484,8 +4674,10 @@ } // 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, + Result); } case BTK__type_pack_element: @@ -3507,8 +4699,10 @@ } // We simply return the type at index `Index`. + // FIXME: test this auto Nth = std::next(Ts.pack_begin(), Index.getExtValue()); - return Nth->getAsType(); + return getResugaredTemplateSpecializationType( + SemaRef, SS.getScopeRep(), Name, TemplateArgs, Nth->getAsType()); } llvm_unreachable("unexpected BuiltinTemplateDecl!"); } @@ -3652,20 +4846,21 @@ 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 = Name.getUnderlying().getAsDependentTemplateName(); - if (DTN && DTN->isIdentifier()) + if (DTN && DTN->isIdentifier()) { // When building a template-id where the template-name is dependent, // 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); + resugarTemplateArguments(SS, TemplateArgs); + return Context.getDependentTemplateSpecializationType( + ETK_None, DTN->getQualifier(), DTN->getIdentifier(), TemplateArgs); + } if (Name.getAsAssumedTemplateName() && resolveAssumedTemplateNameAsType(/*Scope*/nullptr, Name, TemplateLoc)) @@ -3677,7 +4872,8 @@ // We might have a substituted template template parameter pack. If so, // build a template specialization type for it. if (Name.getAsSubstTemplateTemplateParmPack()) - return Context.getTemplateSpecializationType(Name, TemplateArgs); + return getResugaredTemplateSpecializationType(*this, SS.getScopeRep(), + Name, TemplateArgs); Diag(TemplateLoc, diag::err_template_id_not_a_type) << Name; @@ -3843,14 +5039,15 @@ assert(isa(CanonType) && "type of non-dependent specialization is not a RecordType"); } else if (auto *BTD = dyn_cast(Template)) { - CanonType = checkBuiltinTemplateIdType(*this, BTD, Converted, TemplateLoc, - TemplateArgs); + return checkBuiltinTemplateIdType(*this, SS, Name, BTD, Converted, + TemplateLoc, TemplateArgs); } // Build the fully-sugared type for this class template // specialization, which refers back to the class template // specialization we created or found. - return Context.getTemplateSpecializationType(Name, TemplateArgs, CanonType); + return getResugaredTemplateSpecializationType(*this, SS.getScopeRep(), Name, + TemplateArgs, CanonType); } void Sema::ActOnUndeclaredTypeTemplateName(Scope *S, TemplateTy &ParsedName, @@ -3961,6 +5158,8 @@ translateTemplateArguments(TemplateArgsIn, TemplateArgs); if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) { + assert(SS.getScopeRep() == DTN->getQualifier()); + resugarTemplateArguments(SS, TemplateArgs); QualType T = Context.getDependentTemplateSpecializationType(ETK_None, DTN->getQualifier(), @@ -3981,14 +5180,14 @@ return CreateParsedType(T, TLB.getTypeSourceInfo(Context, T)); } - QualType Result = CheckTemplateIdType(Template, TemplateIILoc, TemplateArgs); - if (Result.isNull()) + QualType T = CheckTemplateIdType(SS, Template, TemplateIILoc, TemplateArgs); + if (T.isNull()) return true; // Build type-source information. TypeLocBuilder TLB; - TemplateSpecializationTypeLoc SpecTL - = TLB.push(Result); + TemplateSpecializationTypeLoc SpecTL = + TLB.push(T); SpecTL.setTemplateKeywordLoc(TemplateKWLoc); SpecTL.setTemplateNameLoc(TemplateIILoc); SpecTL.setLAngleLoc(LAngleLoc); @@ -4000,14 +5199,12 @@ // constructor or destructor name (in such a case, the scope specifier // will be attached to the enclosing Decl or Expr node). if (SS.isNotEmpty() && !IsCtorOrDtorName) { - // Create an elaborated-type-specifier containing the nested-name-specifier. - Result = Context.getElaboratedType(ETK_None, SS.getScopeRep(), Result); - ElaboratedTypeLoc ElabTL = TLB.push(Result); + T = Context.getElaboratedType(ETK_None, SS.getScopeRep(), T); + ElaboratedTypeLoc ElabTL = TLB.push(T); ElabTL.setElaboratedKeywordLoc(SourceLocation()); ElabTL.setQualifierLoc(SS.getWithLocInContext(Context)); } - - return CreateParsedType(Result, TLB.getTypeSourceInfo(Context, Result)); + return CreateParsedType(T, TLB.getTypeSourceInfo(Context, T)); } TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK, @@ -4035,6 +5232,8 @@ = TypeWithKeyword::getKeywordForTagTypeKind(TagKind); if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) { + assert(SS.getScopeRep() == DTN->getQualifier()); + resugarTemplateArguments(SS, TemplateArgs); QualType T = Context.getDependentTemplateSpecializationType(Keyword, DTN->getQualifier(), DTN->getIdentifier(), @@ -4066,30 +5265,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); @@ -4099,11 +5282,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, @@ -4955,9 +6156,9 @@ return TNK_Non_template; } -bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, - TemplateArgumentLoc &AL, - SmallVectorImpl &Converted) { +bool Sema::CheckTemplateTypeArgument( + TemplateTypeParmDecl *Param, TemplateArgumentLoc &AL, + SmallVectorImpl &Converted, bool DontCanonicalize) { const TemplateArgument &Arg = AL.getArgument(); QualType ArgType; TypeSourceInfo *TSI = nullptr; @@ -5051,7 +6252,8 @@ return true; // Add the converted template type argument. - ArgType = Context.getCanonicalType(ArgType); + if (!DontCanonicalize) + ArgType = Context.getCanonicalType(ArgType); // Objective-C ARC: // If an explicitly-specified template argument type is a lifetime type @@ -5370,17 +6572,14 @@ /// 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 &Converted, + CheckTemplateArgumentKind CTAK, bool DontCanonizalize) { // Check template type parameters. if (TemplateTypeParmDecl *TTP = dyn_cast(Param)) - return CheckTemplateTypeArgument(TTP, Arg, Converted); + return CheckTemplateTypeArgument(TTP, Arg, Converted, DontCanonizalize); // Check non-type template parameters. if (NonTypeTemplateParmDecl *NTTP =dyn_cast(Param)) { @@ -5433,11 +6632,16 @@ llvm_unreachable("Should never see a NULL template argument here"); case TemplateArgument::Expression: { + Expr *E = Arg.getArgument().getAsExpr(); + // FIXME: Workaround for double conversion + if (isa(E)) { + Converted.push_back(Arg.getArgument()); + break; + } TemplateArgument Result; unsigned CurSFINAEErrors = NumSFINAEErrors; - ExprResult Res = - CheckTemplateArgument(NTTP, NTTPType, Arg.getArgument().getAsExpr(), - Result, CTAK); + ExprResult Res = CheckTemplateArgument(NTTP, NTTPType, E, Result, CTAK, + DontCanonizalize); if (Res.isInvalid()) return true; // If the current template argument causes an error, give up now. @@ -5497,7 +6701,8 @@ } TemplateArgument Result; - E = CheckTemplateArgument(NTTP, NTTPType, E.get(), Result); + E = CheckTemplateArgument(NTTP, NTTPType, E.get(), Result, + CTAK_Specified, DontCanonizalize); if (E.isInvalid()) return true; @@ -5659,7 +6864,8 @@ TemplateDecl *Template, SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs, bool PartialTemplateArgs, SmallVectorImpl &Converted, - bool UpdateArgsWithConversions, bool *ConstraintsNotSatisfied) { + bool UpdateArgsWithConversions, bool *ConstraintsNotSatisfied, + bool DontCanonicalize) { if (ConstraintsNotSatisfied) *ConstraintsNotSatisfied = false; @@ -5717,9 +6923,9 @@ 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, ArgumentPack.size(), Converted, + CTAK_Specified, DontCanonicalize)) return true; bool PackExpansionIntoNonPack = @@ -5878,8 +7084,8 @@ return true; // Check the default template argument. - if (CheckTemplateArgument(*Param, Arg, Template, TemplateLoc, - RAngleLoc, 0, Converted)) + if (CheckTemplateArgument(*Param, Arg, Template, TemplateLoc, RAngleLoc, 0, + Converted, CTAK_Specified, DontCanonicalize)) return true; // Core issue 150 (assumed resolution): if this is a template template @@ -6404,12 +7610,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 &Converted, bool DontCanonicalize) { bool Invalid = false; Expr *Arg = ArgIn; QualType ArgType = Arg->getType(); @@ -6513,8 +7716,9 @@ Entity)) { case NPV_NullPointer: S.Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null); - Converted = TemplateArgument(S.Context.getCanonicalType(ParamType), - /*isNullPtr=*/true); + Converted = TemplateArgument( + DontCanonicalize ? ParamType : S.Context.getCanonicalType(ParamType), + /*isNullPtr=*/true); return false; case NPV_Error: @@ -6658,19 +7862,18 @@ return true; // Create the template argument. - Converted = TemplateArgument(cast(Entity->getCanonicalDecl()), - S.Context.getCanonicalType(ParamType)); + Converted = TemplateArgument( + cast(DontCanonicalize ? Entity : Entity->getCanonicalDecl()), + DontCanonicalize ? ParamType : 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 &Converted, bool DontCanonicalize) { bool Invalid = false; Expr *Arg = ResultArg; @@ -6720,8 +7923,10 @@ if (Arg->isTypeDependent() || Arg->isValueDependent()) { Converted = TemplateArgument(Arg); } else { - VD = cast(VD->getCanonicalDecl()); - Converted = TemplateArgument(VD, ParamType); + Converted = TemplateArgument( + cast(DontCanonicalize ? VD : VD->getCanonicalDecl()), + DontCanonicalize ? ParamType + : S.Context.getCanonicalType(ParamType)); } return Invalid; } @@ -6739,8 +7944,9 @@ return true; case NPV_NullPointer: S.Diag(ResultArg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null); - Converted = TemplateArgument(S.Context.getCanonicalType(ParamType), - /*isNullPtr*/true); + Converted = TemplateArgument( + DontCanonicalize ? ParamType : S.Context.getCanonicalType(ParamType), + /*isNullPtr*/ true); return false; case NPV_NotNullPointer: break; @@ -6779,8 +7985,10 @@ if (Arg->isTypeDependent() || Arg->isValueDependent()) { Converted = TemplateArgument(Arg); } else { - ValueDecl *D = cast(DRE->getDecl()->getCanonicalDecl()); - Converted = TemplateArgument(D, S.Context.getCanonicalType(ParamType)); + ValueDecl *D = DRE->getDecl(); + Converted = TemplateArgument( + DontCanonicalize ? D : cast(D->getCanonicalDecl()), + DontCanonicalize ? ParamType : S.Context.getCanonicalType(ParamType)); } return Invalid; } @@ -6802,7 +8010,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, QualType ParamType, Expr *Arg, TemplateArgument &Converted, - CheckTemplateArgumentKind CTAK) { + CheckTemplateArgumentKind CTAK, + bool DontCanonicalize) { SourceLocation StartLoc = Arg->getBeginLoc(); // If the parameter type somehow involves auto, deduce the type now. @@ -6947,7 +8156,8 @@ Context.hasSameUnqualifiedType(ParamType, InnerArg->getType())) { NamedDecl *ND = cast(InnerArg)->getDecl(); if (auto *TPO = dyn_cast(ND)) { - Converted = TemplateArgument(TPO, CanonParamType); + Converted = TemplateArgument(TPO, DontCanonicalize ? ParamType + : CanonParamType); return Arg; } if (isa(ND)) { @@ -6976,14 +8186,17 @@ switch (Value.getKind()) { case APValue::None: assert(ParamType->isNullPtrType()); - Converted = TemplateArgument(CanonParamType, /*isNullPtr*/true); + Converted = TemplateArgument( + DontCanonicalize ? ParamType : 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); + Converted = + TemplateArgument(Context, Value.getInt(), + DontCanonicalize ? ParamType : CanonParamType); break; case APValue::MemberPointer: { assert(ParamType->isMemberPointerType()); @@ -6997,9 +8210,10 @@ return ExprError(); } + QualType T = DontCanonicalize ? ParamType : CanonParamType; auto *VD = const_cast(Value.getMemberPointerDecl()); - Converted = VD ? TemplateArgument(VD, CanonParamType) - : TemplateArgument(CanonParamType, /*isNullPtr*/true); + Converted = VD ? TemplateArgument(VD, T) + : TemplateArgument(T, /*isNullPtr=*/true); break; } case APValue::LValue: { @@ -7039,17 +8253,19 @@ "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); + QualType T = DontCanonicalize ? ParamType : CanonParamType; + Converted = VD ? TemplateArgument(VD, T) + : TemplateArgument(T, /*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); + QualType T = DontCanonicalize ? ParamType : CanonParamType; + Converted = + TemplateArgument(Context.getTemplateParamObjectDecl(T, Value), T); break; + } case APValue::AddrLabelDiff: return Diag(StartLoc, diag::err_non_type_template_arg_addr_label_diff); case APValue::FixedPoint: @@ -7113,8 +8329,9 @@ ? Context.getIntWidth(IntegerType) : Context.getTypeSize(IntegerType)); - Converted = TemplateArgument(Context, Value, - Context.getCanonicalType(ParamType)); + Converted = TemplateArgument( + Context, Value, + DontCanonicalize ? ParamType : Context.getCanonicalType(ParamType)); return ArgResult; } @@ -7188,9 +8405,13 @@ return Arg; } - QualType IntegerType = Context.getCanonicalType(ParamType); - if (const EnumType *Enum = IntegerType->getAs()) - IntegerType = Context.getCanonicalType(Enum->getDecl()->getIntegerType()); + QualType IntegerType = + DontCanonicalize ? ParamType : Context.getCanonicalType(ParamType); + if (const EnumType *Enum = IntegerType->getAs()) { + IntegerType = Enum->getDecl()->getIntegerType(); + if (!DontCanonicalize) + IntegerType = Context.getCanonicalType(IntegerType); + } if (ParamType->isBooleanType()) { // Value must be zero or one. @@ -7236,10 +8457,10 @@ } } + QualType T = + DontCanonicalize ? ParamType : Context.getCanonicalType(ParamType); Converted = TemplateArgument(Context, Value, - ParamType->isEnumeralType() - ? Context.getCanonicalType(ParamType) - : IntegerType); + ParamType->isEnumeralType() ? T : IntegerType); return Arg; } @@ -7277,22 +8498,22 @@ 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, Converted, DontCanonicalize)) return ExprError(); return Arg; } if (CheckTemplateArgumentPointerToMember(*this, Param, ParamType, Arg, - Converted)) + Converted, DontCanonicalize)) return ExprError(); return Arg; } @@ -7305,9 +8526,8 @@ assert(ParamType->getPointeeType()->isIncompleteOrObjectType() && "Only object pointers allowed here"); - if (CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param, - ParamType, - Arg, Converted)) + if (CheckTemplateArgumentAddressOfObjectOrFunction( + *this, Param, ParamType, Arg, Converted, DontCanonicalize)) return ExprError(); return Arg; } @@ -7330,15 +8550,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, Converted, DontCanonicalize)) return ExprError(); return Arg; } @@ -7362,8 +8582,9 @@ case NPV_NullPointer: Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null); - Converted = TemplateArgument(Context.getCanonicalType(ParamType), - /*isNullPtr*/true); + Converted = TemplateArgument( + DontCanonicalize ? ParamType : Context.getCanonicalType(ParamType), + /*isNullPtr*/ true); return Arg; } } @@ -7373,7 +8594,7 @@ assert(ParamType->isMemberPointerType() && "Only pointers to members remain"); if (CheckTemplateArgumentPointerToMember(*this, Param, ParamType, Arg, - Converted)) + Converted, DontCanonicalize)) return ExprError(); return Arg; } @@ -10425,7 +11646,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, @@ -10444,6 +11665,7 @@ // Construct a dependent template specialization type. assert(DTN && "dependent template has non-dependent name?"); assert(DTN->getQualifier() == SS.getScopeRep()); + resugarTemplateArguments(SS, TemplateArgs); QualType T = Context.getDependentTemplateSpecializationType(ETK_Typename, DTN->getQualifier(), DTN->getIdentifier(), @@ -10464,7 +11686,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; @@ -10484,8 +11706,7 @@ TL.setElaboratedKeywordLoc(TypenameLoc); TL.setQualifierLoc(SS.getWithLocInContext(Context)); - TypeSourceInfo *TSI = Builder.getTypeSourceInfo(Context, T); - return CreateParsedType(T, TSI); + return CreateParsedType(T, Builder.getTypeSourceInfo(Context, T)); } @@ -10691,9 +11912,10 @@ // 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, /*NamedDecl=*/nullptr, /*Args=*/nullptr, + 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 @@ -2567,13 +2567,10 @@ /// 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 &Output, bool DontCanonicalize) { auto ConvertArg = [&](DeducedTemplateArgument Arg, unsigned ArgumentPackIndex) { // Convert the deduced template argument into a template @@ -2589,7 +2586,8 @@ IsDeduced ? (Arg.wasDeducedFromArrayBound() ? Sema::CTAK_DeducedFromArrayBound : Sema::CTAK_Deduced) - : Sema::CTAK_Specified); + : Sema::CTAK_Specified, + DontCanonicalize); }; if (Arg.getKind() == TemplateArgument::Pack) { @@ -2658,13 +2656,14 @@ // 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, LocalInstantiationScope *CurrentInstantiationScope = nullptr, - unsigned NumAlreadyConverted = 0, bool PartialOverloading = false) { + unsigned NumAlreadyConverted = 0, bool PartialOverloading = false, + bool DontCanonicalize = false) { TemplateParameterList *TemplateParams = Template->getTemplateParameters(); for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) { @@ -2704,7 +2703,8 @@ // 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, Builder, + DontCanonicalize)) { Info.Param = makeTemplateParameter(Param); // FIXME: These template arguments are temporary. Free them! Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder)); @@ -2756,7 +2756,7 @@ // 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)) { + Sema::CTAK_Specified, DontCanonicalize)) { Info.Param = makeTemplateParameter( const_cast(TemplateParams->getParam(I))); // FIXME: These template arguments are temporary. Free them! @@ -2813,7 +2813,7 @@ Sema &S, T *Partial, bool IsPartialOrdering, const TemplateArgumentList &TemplateArgs, SmallVectorImpl &Deduced, - TemplateDeductionInfo &Info) { + TemplateDeductionInfo &Info, bool DontCanonicalize) { // Unevaluated SFINAE context. EnterExpressionEvaluationContext Unevaluated( S, Sema::ExpressionEvaluationContext::Unevaluated); @@ -2826,7 +2826,10 @@ // explicitly specified, template argument deduction fails. SmallVector Builder; if (auto Result = ConvertDeducedTemplateArguments( - S, Partial, IsPartialOrdering, Deduced, Info, Builder)) + S, Partial, IsPartialOrdering, Deduced, Info, Builder, + /*CurrentInstantiationScope=*/nullptr, + /*NumAlreadyConverted=*/0U, + /*PartialOverloading=*/false, DontCanonicalize)) return Result; // Form the template argument list from the deduced template arguments. @@ -2835,6 +2838,9 @@ Info.reset(DeducedArgumentList); + if (DontCanonicalize) + return Sema::TDK_Success; + // Substitute the deduced template arguments into the template // arguments of the class template partial specialization, and // verify that the instantiated template arguments are both valid @@ -2898,7 +2904,7 @@ Sema &S, TemplateDecl *Template, bool PartialOrdering, const TemplateArgumentList &TemplateArgs, SmallVectorImpl &Deduced, - TemplateDeductionInfo &Info) { + TemplateDeductionInfo &Info, bool DontCanonicalize) { // Unevaluated SFINAE context. EnterExpressionEvaluationContext Unevaluated( S, Sema::ExpressionEvaluationContext::Unevaluated); @@ -2911,9 +2917,15 @@ // explicitly specified, template argument deduction fails. SmallVector Builder; if (auto Result = ConvertDeducedTemplateArguments( - S, Template, /*IsDeduced*/PartialOrdering, Deduced, Info, Builder)) + S, Template, /*IsDeduced*/ PartialOrdering, Deduced, Info, Builder, + /*CurrentInstantiationScope=*/nullptr, + /*NumAlreadyConverted=*/0U, /*PartialOverloading=*/false, + DontCanonicalize)) return Result; + if (DontCanonicalize) + return Sema::TDK_Success; + // Check that we produced the correct argument list. TemplateParameterList *TemplateParams = Template->getTemplateParameters(); for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) { @@ -2943,7 +2955,8 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, const TemplateArgumentList &TemplateArgs, - TemplateDeductionInfo &Info) { + TemplateDeductionInfo &Info, + bool DontCanonicalize) { if (Partial->isInvalidDecl()) return TDK_Invalid; @@ -2984,7 +2997,8 @@ runWithSufficientStackSpace(Info.getLocation(), [&] { Result = ::FinishTemplateArgumentDeduction(*this, Partial, /*IsPartialOrdering=*/false, - TemplateArgs, Deduced, Info); + TemplateArgs, Deduced, Info, + DontCanonicalize); }); return Result; } @@ -2995,7 +3009,8 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(VarTemplatePartialSpecializationDecl *Partial, const TemplateArgumentList &TemplateArgs, - TemplateDeductionInfo &Info) { + TemplateDeductionInfo &Info, + bool DontCanonicalize) { if (Partial->isInvalidDecl()) return TDK_Invalid; @@ -3034,7 +3049,8 @@ runWithSufficientStackSpace(Info.getLocation(), [&] { Result = ::FinishTemplateArgumentDeduction(*this, Partial, /*IsPartialOrdering=*/false, - TemplateArgs, Deduced, Info); + TemplateArgs, Deduced, Info, + DontCanonicalize); }); return Result; } @@ -3591,12 +3607,16 @@ /// 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 {}; + QualType FT = Fn->getType(); + FT = S.resugar(CXXScopeSpec(), Fn, Args, FT, /*Escapes=*/true); + if (CXXMethodDecl *Method = dyn_cast(Fn)) if (Method->isInstance()) { // An instance method that's referenced in a form that doesn't @@ -3604,12 +3624,13 @@ if (!R.HasFormOfMemberPointer) return {}; - return S.Context.getMemberPointerType(Fn->getType(), - S.Context.getTypeDeclType(Method->getParent()).getTypePtr()); + 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. @@ -3632,6 +3653,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: @@ -3641,23 +3667,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) { @@ -3681,7 +3704,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. @@ -4637,6 +4660,9 @@ Init->containsUnexpandedParameterPack())) { Result = SubstituteDeducedTypeTransform(*this, DependentResult).Apply(Type); assert(!Result.isNull() && "substituting DependentTy can't fail"); + // Remove any substitution sugar. + // FIXME: might make sense to have SubstituteDeducedTypeTransform do this. + Result = resugarEscapes(Result); return DAR_Succeeded; } @@ -4669,6 +4695,9 @@ Result = SubstituteDeducedTypeTransform(*this, Deduced).Apply(Type); if (Result.isNull()) return DAR_FailedAlreadyDiagnosed; + // Remove any substitution sugar. + // FIXME: might make sense to have SubstituteDeducedTypeTransform do this. + Result = resugarEscapes(Result); return DAR_Succeeded; } else if (!getLangOpts().CPlusPlus) { if (isa(Init)) { @@ -4711,6 +4740,9 @@ Result = SubstituteDeducedTypeTransform(*this, DependentResult).Apply(Type); assert(!Result.isNull() && "substituting DependentTy can't fail"); + // Remove any substitution sugar. + // FIXME: might make sense to have SubstituteDeducedTypeTransform do this. + Result = resugarEscapes(Result); return DAR_Succeeded; } if (diagnoseAutoDeductionFailure(*this, TDK, Info, Ranges)) @@ -4788,6 +4820,9 @@ Result = SubstituteDeducedTypeTransform(*this, DeducedType).Apply(Type); if (Result.isNull()) return DAR_FailedAlreadyDiagnosed; + // Remove any substitution sugar. + // FIXME: might make sense to have SubstituteDeducedTypeTransform do this. + Result = resugarEscapes(Result); // Check that the deduced argument type is compatible with the original // argument type per C++ [temp.deduct.call]p4. @@ -5365,7 +5400,8 @@ S, P2, /*IsPartialOrdering=*/true, TemplateArgumentList(TemplateArgumentList::OnStack, TST1->template_arguments()), - Deduced, Info); + Deduced, Info, + /*DontCanonicalize=*/false); // FIXME }); return AtLeastAsSpecialized; } 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 @@ -1234,8 +1234,12 @@ Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) { if (!D) return nullptr; + Decl *TransD = + SemaRef.FindInstantiatedDecl(Loc, cast(D), TemplateArgs); + if (!TransD) + return nullptr; - if (TemplateTemplateParmDecl *TTP = dyn_cast(D)) { + if (TemplateTemplateParmDecl *TTP = dyn_cast(D)) if (TTP->getDepth() < TemplateArgs.getNumLevels()) { // If the corresponding template argument is NULL or non-existent, it's // because we are performing instantiation from explicitly-specified @@ -1243,7 +1247,7 @@ // arguments left unspecified. if (!TemplateArgs.hasTemplateArgument(TTP->getDepth(), TTP->getPosition())) - return D; + return TransD; TemplateArgument Arg = TemplateArgs(TTP->getDepth(), TTP->getPosition()); @@ -1258,12 +1262,7 @@ "Wrong kind of template template argument"); return Template.getAsTemplateDecl(); } - - // Fall through to find the instantiated declaration for this template - // template parameter. - } - - return SemaRef.FindInstantiatedDecl(Loc, cast(D), TemplateArgs); + return TransD; } Decl *TemplateInstantiator::TransformDefinition(SourceLocation Loc, Decl *D) { @@ -1370,54 +1369,57 @@ CXXScopeSpec &SS, TemplateName Name, SourceLocation NameLoc, QualType ObjectType, NamedDecl *FirstQualifierInScope, bool AllowInjectedClassName) { - if (TemplateTemplateParmDecl *TTP - = dyn_cast_or_null(Name.getAsTemplateDecl())) { - if (TTP->getDepth() < TemplateArgs.getNumLevels()) { - // If the corresponding template argument is NULL or non-existent, it's - // because we are performing instantiation from explicitly-specified - // template arguments in a function template, but there were some - // arguments left unspecified. - if (!TemplateArgs.hasTemplateArgument(TTP->getDepth(), - TTP->getPosition())) - return Name; + if (auto *TTP = dyn_cast_or_null( + Name.getAsTemplateDecl())) { - TemplateArgument Arg = TemplateArgs(TTP->getDepth(), TTP->getPosition()); + auto *TransTTP = cast( + SemaRef.FindInstantiatedDecl(NameLoc, TTP, TemplateArgs)); - if (TemplateArgs.isRewrite()) { - // We're rewriting the template parameter as a reference to another - // template parameter. - if (Arg.getKind() == TemplateArgument::Pack) { - assert(Arg.pack_size() == 1 && Arg.pack_begin()->isPackExpansion() && - "unexpected pack arguments in template rewrite"); - Arg = Arg.pack_begin()->getPackExpansionPattern(); - } - assert(Arg.getKind() == TemplateArgument::Template && - "unexpected nontype template argument kind in template rewrite"); - return Arg.getAsTemplate(); - } + if (TTP->getDepth() >= TemplateArgs.getNumLevels()) + return TemplateName(TransTTP); - if (TTP->isParameterPack()) { - assert(Arg.getKind() == TemplateArgument::Pack && - "Missing argument pack"); + // If the corresponding template argument is NULL or non-existent, it's + // because we are performing instantiation from explicitly-specified + // template arguments in a function template, but there were some + // arguments left unspecified. + if (!TemplateArgs.hasTemplateArgument(TTP->getDepth(), TTP->getPosition())) + return Name; - if (getSema().ArgumentPackSubstitutionIndex == -1) { - // We have the template argument pack to substitute, but we're not - // actually expanding the enclosing pack expansion yet. So, just - // keep the entire argument pack. - return getSema().Context.getSubstTemplateTemplateParmPack(TTP, Arg); - } + TemplateArgument Arg = TemplateArgs(TTP->getDepth(), TTP->getPosition()); - Arg = getPackSubstitutedTemplateArgument(getSema(), Arg); + if (TemplateArgs.isRewrite()) { + // We're rewriting the template parameter as a reference to another + // template parameter. + if (Arg.getKind() == TemplateArgument::Pack) { + assert(Arg.pack_size() == 1 && Arg.pack_begin()->isPackExpansion() && + "unexpected pack arguments in template rewrite"); + Arg = Arg.pack_begin()->getPackExpansionPattern(); } + assert(Arg.getKind() == TemplateArgument::Template && + "unexpected nontype template argument kind in template rewrite"); + return Arg.getAsTemplate(); + } - TemplateName Template = Arg.getAsTemplate().getNameToSubstitute(); - assert(!Template.isNull() && "Null template template argument"); - assert(!Template.getAsQualifiedTemplateName() && - "template decl to substitute is qualified?"); + if (TTP->isParameterPack()) { + assert(Arg.getKind() == TemplateArgument::Pack && + "Missing argument pack"); + + if (getSema().ArgumentPackSubstitutionIndex == -1) { + // We have the template argument pack to substitute, but we're not + // actually expanding the enclosing pack expansion yet. So, just + // keep the entire argument pack. + return getSema().Context.getSubstTemplateTemplateParmPack(TTP, Arg); + } - Template = getSema().Context.getSubstTemplateTemplateParm(TTP, Template); - return Template; + Arg = getPackSubstitutedTemplateArgument(getSema(), Arg); } + + TemplateName Template = Arg.getAsTemplate().getNameToSubstitute(); + assert(!Template.isNull() && "Null template template argument"); + assert(!Template.getAsQualifiedTemplateName() && + "template decl to substitute is qualified?"); + + return getSema().Context.getSubstTemplateTemplateParm(TransTTP, Template); } if (SubstTemplateTemplateParmPackStorage *SubstPack @@ -1640,9 +1642,11 @@ // Type=decltype(2))) // The call to CheckTemplateArgument here produces the ImpCast. TemplateArgument Converted; - if (SemaRef.CheckTemplateArgument(E->getParameter(), SubstType, - SubstReplacement.get(), - Converted).isInvalid()) + if (SemaRef + .CheckTemplateArgument( + E->getParameter(), SubstType, SubstReplacement.get(), Converted, + Sema::CTAK_Specified, /*DontCanonicalize=*/false) + .isInvalid()) return true; return transformNonTypeTemplateParmRef(E->getParameter(), E->getExprLoc(), Converted); @@ -1780,6 +1784,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. @@ -1789,8 +1796,9 @@ // template arguments in a function template class, but there were some // arguments left unspecified. if (!TemplateArgs.hasTemplateArgument(T->getDepth(), T->getIndex())) { - TemplateTypeParmTypeLoc NewTL - = TLB.push(TL.getType()); + QualType NewT = getSema().Context.getTemplateTypeParmType( + T->getDepth(), T->getIndex(), T->isParameterPack(), NewTTPDecl); + TemplateTypeParmTypeLoc NewTL = TLB.push(NewT); NewTL.setNameLoc(TL.getNameLoc()); return TL.getType(); } @@ -1815,6 +1823,10 @@ return NewT; } + const auto *NewT = + cast(getSema().Context.getTemplateTypeParmType( + T->getDepth(), T->getIndex(), T->isParameterPack(), NewTTPDecl)); + Optional PackIndex; if (T->isParameterPack()) { assert(Arg.getKind() == TemplateArgument::Pack && @@ -1824,8 +1836,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(NewT, Arg); SubstTemplateTypeParmPackTypeLoc NewTL = TLB.push(Result); NewTL.setNameLoc(TL.getNameLoc()); @@ -1843,7 +1855,7 @@ // TODO: only do this uniquing once, at the start of instantiation. QualType Result = getSema().Context.getSubstTemplateTypeParmType( - T, Replacement, PackIndex); + NewT, Replacement, PackIndex); SubstTemplateTypeParmTypeLoc NewTL = TLB.push(Result); NewTL.setNameLoc(TL.getNameLoc()); @@ -1854,11 +1866,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( TemplateArgs.getNewDepth(T->getDepth()), T->getIndex(), T->isParameterPack(), NewTTPDecl); @@ -2704,6 +2711,21 @@ // it now and put it back later. SavePendingParsedClassStateRAII SavedPendingParsedClassState(*this); + if (const auto *CTSD = + dyn_cast(Instantiation)) { + const ClassTemplateDecl *CTD = CTSD->getSpecializedTemplate(); + if (const ClassTemplateDecl *InstFrom = + CTD->getInstantiatedFromMemberTemplate()) { + TemplateParameterList *NewTPL = CTD->getTemplateParameters(); + const TemplateParameterList *OldTPL = InstFrom->getTemplateParameters(); + assert(NewTPL->size() == OldTPL->size()); + for (unsigned I = 0, E = NewTPL->size(); I < E; ++I) + Scope.InstantiatedLocal(OldTPL->getParam(I), NewTPL->getParam(I)); + } + } else { + assert(Instantiation->getKind() == Decl::Kind::CXXRecord); + } + // Pull attributes from the pattern onto the instantiation. InstantiateAttrs(TemplateArgs, Pattern, Instantiation); 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 @@ -6163,7 +6163,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 @@ -9133,8 +9133,17 @@ // 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(); - return isa(VD) ? T.getUnqualifiedType() : T; + QualType VT = VD->getType(), ET = DRE->getType(); + if (const auto *VTL = VT->getAs()) + ET = Context.getLValueReferenceType(ET, VTL->isSpelledAsLValue()); + if (VT->isRValueReferenceType()) + ET = Context.getRValueReferenceType(ET); + if (!Context.hasSameType(ET, VT)) { + ET.dump(); + VT.dump(); + assert(false); + } + return isa(VD) ? ET.getUnqualifiedType() : ET; } if (const auto *ME = dyn_cast(IDExpr)) { if (const auto *VD = ME->getMemberDecl()) 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); @@ -1068,9 +1069,10 @@ // Otherwise, make an elaborated type wrapping a non-dependent // specialization. - QualType T = - getDerived().RebuildTemplateSpecializationType(InstName, NameLoc, Args); - if (T.isNull()) return QualType(); + QualType T = getDerived().RebuildTemplateSpecializationType(SS, InstName, + NameLoc, Args); + if (T.isNull()) + return QualType(); if (Keyword == ETK_None && QualifierLoc.getNestedNameSpecifier() == nullptr) return T; @@ -2678,6 +2680,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 @@ -2693,15 +2698,15 @@ return ExprError(); Base = BaseResult.get(); - CXXScopeSpec EmptySS; + QualType FieldType = Member->getType(); + FieldType = getSema().resugar(SS, Member, ExplicitTemplateArgs, FieldType, + /*Escapes=*/true); return getSema().BuildFieldReferenceExpr( - Base, isArrow, OpLoc, EmptySS, cast(Member), - DeclAccessPair::make(FoundDecl, FoundDecl->getAccess()), MemberNameInfo); + Base, isArrow, OpLoc, CXXScopeSpec(), cast(Member), + FieldType, DeclAccessPair::make(FoundDecl, FoundDecl->getAccess()), + MemberNameInfo); } - CXXScopeSpec SS; - SS.Adopt(QualifierLoc); - Base = BaseResult.get(); QualType BaseType = Base->getType(); @@ -4895,7 +4900,7 @@ return TL; TypeSourceInfo *TSI = - TransformTSIInObjectScope(TL, ObjectType, UnqualLookup, SS); + getDerived().TransformTSIInObjectScope(TL, ObjectType, UnqualLookup, SS); if (TSI) return TSI->getTypeLoc(); return TypeLoc(); @@ -4910,8 +4915,8 @@ if (getDerived().AlreadyTransformed(TSInfo->getType())) return TSInfo; - return TransformTSIInObjectScope(TSInfo->getTypeLoc(), ObjectType, - UnqualLookup, SS); + return getDerived().TransformTSIInObjectScope(TSInfo->getTypeLoc(), + ObjectType, UnqualLookup, SS); } template @@ -5515,7 +5520,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(); @@ -5548,9 +5554,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; @@ -6694,10 +6699,8 @@ // FIXME: maybe don't rebuild if all the template arguments are the same. - QualType Result = - getDerived().RebuildTemplateSpecializationType(Template, - TL.getTemplateNameLoc(), - NewTemplateArgs); + QualType Result = getDerived().RebuildTemplateSpecializationType( + CXXScopeSpec(), Template, TL.getTemplateNameLoc(), NewTemplateArgs); if (!Result.isNull()) { // Specializations of template template parameters are represented as @@ -6770,10 +6773,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? @@ -14706,12 +14707,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/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/temp/temp.deduct.guide/p3.cpp b/clang/test/CXX/temp/temp.deduct.guide/p3.cpp --- a/clang/test/CXX/temp/temp.deduct.guide/p3.cpp +++ b/clang/test/CXX/temp/temp.deduct.guide/p3.cpp @@ -33,7 +33,7 @@ }; A(int) -> int; // expected-error {{deduced type 'int' of deduction guide is not a specialization of template 'A'}} -template A(T) -> B; // expected-error {{deduced type 'B' (aka 'A') of deduction guide is not written as a specialization of template 'A'}} +template A(T)->B; // expected-error {{deduced type 'B' (aka 'A') of deduction guide is not written as a specialization of template 'A'}} template A(T*) -> const A; // expected-error {{deduced type 'const A' of deduction guide is not a specialization of template 'A'}} // A deduction-guide shall be declared in the same scope as the corresponding diff --git a/clang/test/CodeGenCXX/mangle-ms-back-references-pr13207.cpp b/clang/test/CodeGenCXX/mangle-ms-back-references-pr13207.cpp --- a/clang/test/CodeGenCXX/mangle-ms-back-references-pr13207.cpp +++ b/clang/test/CodeGenCXX/mangle-ms-back-references-pr13207.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-win32 | FileCheck %s +// RUN: %clang_cc1 -fno-resugar -emit-llvm %s -o - -triple=i386-pc-win32 | FileCheck %s template class A {}; @@ -220,6 +220,7 @@ class T20> struct Food {}; +// FIXME: Should implement resugaring cache for this. using B0 = Food; using B1 = Food; using B2 = Food; diff --git a/clang/test/CodeGenCXX/pr29160.cpp b/clang/test/CodeGenCXX/pr29160.cpp --- a/clang/test/CodeGenCXX/pr29160.cpp +++ b/clang/test/CodeGenCXX/pr29160.cpp @@ -1,8 +1,9 @@ -// RUN: %clang_cc1 -std=c++11 -triple i686-linux-gnu %s -o /dev/null -S -emit-llvm +// RUN: %clang_cc1 -std=c++11 -fno-resugar -triple i686-linux-gnu %s -o /dev/null -S -emit-llvm // // This test's failure mode is running ~forever. (For some value of "forever" // that's greater than 25 minutes on my machine) +// FIXME: Should implement resugaring cache for this. template struct Foo { template diff --git a/clang/test/Misc/diag-template-diffing.cpp b/clang/test/Misc/diag-template-diffing.cpp --- a/clang/test/Misc/diag-template-diffing.cpp +++ b/clang/test/Misc/diag-template-diffing.cpp @@ -257,24 +257,21 @@ int k9 = f9(V9()); // CHECK-ELIDE-NOTREE: no matching function for call to 'f9' -// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'S9<[2 * ...], S9<[2 * ...], double>>' to 'S9<[2 * ...], S9<[2 * ...], const double>>' for 1st argument +// CHECK-ELIDE-NOTREE: candidate function not viable: no known conversion from 'S9<[2 * ...], U9>' to 'S9<[2 * ...], U9>' for 1st argument // CHECK-NOELIDE-NOTREE: no matching function for call to 'f9' -// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'S9>' to 'S9>' for 1st argument +// CHECK-NOELIDE-NOTREE: candidate function not viable: no known conversion from 'S9>' to 'S9>' for 1st argument // CHECK-ELIDE-TREE: no matching function for call to 'f9' // CHECK-ELIDE-TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument // CHECK-ELIDE-TREE: S9< -// CHECK-ELIDE-TREE: [2 * ...], -// CHECK-ELIDE-TREE: S9< -// CHECK-ELIDE-TREE: [2 * ...], +// CHECK-ELIDE-TREE: [2 * ...], +// CHECK-ELIDE-TREE: U9< // CHECK-ELIDE-TREE: [double != const double]>> // CHECK-NOELIDE-TREE: no matching function for call to 'f9' // CHECK-NOELIDE-TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument // CHECK-NOELIDE-TREE: S9< -// CHECK-NOELIDE-TREE: int, -// CHECK-NOELIDE-TREE: char, -// CHECK-NOELIDE-TREE: S9< -// CHECK-NOELIDE-TREE: int, -// CHECK-NOELIDE-TREE: char, +// CHECK-NOELIDE-TREE: int, +// CHECK-NOELIDE-TREE: char, +// CHECK-NOELIDE-TREE: U9< // CHECK-NOELIDE-TREE: [double != const double]>> template class class_types {}; diff --git a/clang/test/Sema/Resugar/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,128 @@ +// RUN: %clang_cc1 -std=c++2b -fsyntax-only -verify=yep %s +// RUN: %clang_cc1 -std=c++2b -fsyntax-only -fno-resugar -verify=nop %s + +enum class Foo; + +struct Bar {}; + +using Int = int; +using Float = float; +using Struct = Bar; + +namespace t1 { +template struct A { + static constexpr A1 a = {}; +}; + +Foo x1 = A::a; +// yep-error@-1 {{with an lvalue of type 'const Int' (aka 'const int')}} +// nop-error@-2 {{with an lvalue of type 'const int'}} +} // namespace t1 + +namespace t2 { +template struct A { + static constexpr A1 A2::*a = {}; +}; + +Foo x1 = A::a; +// yep-error@-1 {{with an lvalue of type 'Int Struct::*const'}} +// nop-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 = {}; + }; +}; + +Foo x1 = A::B::a; +// yep-error@-1 {{with an lvalue of type 'Float Struct::*const'}} +// nop-error@-2 {{with an lvalue of type 'float Bar::*const'}} +} // namespace t3 + +namespace t4 { +template struct A { A2 A1::*f(); }; + +using M = int; +using N = int; + +struct B {}; +using X = B; +using Y = B; + +auto a = &A::f; +Foo x1 = a; +// yep-error@-1 {{with an lvalue of type 't4::M t4::X::*(t4::A::*)()'}} // FIXME +// nop-error@-2 {{with an lvalue of type 'int t4::B::*(t4::A::*)()'}} + +A b; +Foo x2 = (b.*a)(); +// yep-error@-1 {{with an rvalue of type 't4::M t4::X::*'}} +// nop-error@-2 {{with an rvalue of type 'int t4::B::*'}} + +using t1 = decltype((b.*a)()); +Foo x3 = t1{}; +// yep-error@-1 {{with an rvalue of type 't4::t1' (aka 't4::M t4::X::*')}} +// nop-error@-2 {{with an rvalue of type 't4::t1' (aka 'int t4::B::*')}} +} // namespace t4 + +namespace t5 { +template struct A { A1 a; }; +auto [a] = A{}; + +Foo x1 = a; +// yep-error@-1 {{with an lvalue of type 'int'}} // FIXME +// nop-error@-2 {{with an lvalue of type 'int'}} +} // namespace t5 + +namespace t6 { +template struct A { + template static constexpr B1 (*b)(A1) = nullptr; +}; + +Foo x1 = A::b; +// yep-error@-1 {{with an lvalue of type 'Int (*const)(Float)' (aka 'int (*const)(float)')}} +// nop-error@-2 {{with an lvalue of type 'int (*const)(float)'}} +} // namespace t6 + +namespace t7 { +template struct A { + template static constexpr auto b = (B1(*)(A1)){}; +}; + +Foo x1 = A::b; +// yep-error@-1 {{with an lvalue of type 'int (*const)(float)'}} // FIXME +// nop-error@-2 {{with an lvalue of type 'int (*const)(float)'}} +} // namespace t7 + +namespace t8 { +template A1 a; +template A2 a; + +Foo x1 = a; +// yep-error@-1 {{with an lvalue of type 'Int' (aka 'int')}} +// nop-error@-2 {{with an lvalue of type 'int'}} + +Foo x2 = a; +// yep-error@-1 {{with an lvalue of type 'float'}} // FIXME +// nop-error@-2 {{with an lvalue of type 'float'}} +} // namespace t8 + +namespace t9 { +template struct A { A1 foo(); }; + +Foo x1 = A().foo(); +// yep-error@-1 {{with an rvalue of type 'int'}} // FIXME +// nop-error@-2 {{with an rvalue of type 'int'}} +} // namespace t9 + +namespace t10 { +template struct A { + auto foo() { return A1(); }; +}; + +Foo x1 = A().foo(); +// yep-error@-1 {{with an rvalue of type 'int'}} // FIXME +// nop-error@-2 {{with an rvalue of type 'int'}} +} // namespace t10 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,186 @@ +// 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