Author: Erich Keane Date: 2020-06-12T05:32:13-07:00 New Revision: 82a21229da36bc53004dc54203e3bdeea718c942
URL: https://github.com/llvm/llvm-project/commit/82a21229da36bc53004dc54203e3bdeea718c942 DIFF: https://github.com/llvm/llvm-project/commit/82a21229da36bc53004dc54203e3bdeea718c942.diff LOG: (PR46111) Properly handle elaborated types in an implicit deduction guide As reported in PR46111, implicit instantiation of a deduction guide causes us to have an elaborated type as the parameter, rather than the dependent type. After review and feedback from @rsmith, this patch solves this problem by wrapping the value in an uninstantiated typedef/type-alias that is instantiated when required later. Differential Revision: https://reviews.llvm.org/D80743 Added: clang/test/AST/deduction-guides.cpp Modified: clang/lib/Sema/SemaTemplate.cpp clang/lib/Sema/SemaTemplateInstantiate.cpp clang/lib/Sema/SemaTemplateInstantiateDecl.cpp Removed: ################################################################################ diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index c2324f976eba..073b4e818a24 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1947,16 +1947,46 @@ namespace { /// constructor to a deduction guide. class ExtractTypeForDeductionGuide : public TreeTransform<ExtractTypeForDeductionGuide> { + llvm::SmallVectorImpl<TypedefNameDecl *> &MaterializedTypedefs; + public: typedef TreeTransform<ExtractTypeForDeductionGuide> Base; - ExtractTypeForDeductionGuide(Sema &SemaRef) : Base(SemaRef) {} + ExtractTypeForDeductionGuide( + Sema &SemaRef, + llvm::SmallVectorImpl<TypedefNameDecl *> &MaterializedTypedefs) + : Base(SemaRef), MaterializedTypedefs(MaterializedTypedefs) {} TypeSourceInfo *transform(TypeSourceInfo *TSI) { return TransformType(TSI); } QualType TransformTypedefType(TypeLocBuilder &TLB, TypedefTypeLoc TL) { - return TransformType( - TLB, - TL.getTypedefNameDecl()->getTypeSourceInfo()->getTypeLoc()); + ASTContext &Context = SemaRef.getASTContext(); + TypedefNameDecl *OrigDecl = TL.getTypedefNameDecl(); + TypeLocBuilder InnerTLB; + QualType Transformed = + TransformType(InnerTLB, OrigDecl->getTypeSourceInfo()->getTypeLoc()); + TypeSourceInfo *TSI = + TransformType(InnerTLB.getTypeSourceInfo(Context, Transformed)); + + TypedefNameDecl *Decl = nullptr; + + if (isa<TypeAliasDecl>(OrigDecl)) + Decl = TypeAliasDecl::Create( + Context, Context.getTranslationUnitDecl(), OrigDecl->getBeginLoc(), + OrigDecl->getLocation(), OrigDecl->getIdentifier(), TSI); + else { + assert(isa<TypedefDecl>(OrigDecl) && "Not a Type alias or typedef"); + Decl = TypedefDecl::Create( + Context, Context.getTranslationUnitDecl(), OrigDecl->getBeginLoc(), + OrigDecl->getLocation(), OrigDecl->getIdentifier(), TSI); + } + + MaterializedTypedefs.push_back(Decl); + + QualType TDTy = Context.getTypedefType(Decl); + TypedefTypeLoc TypedefTL = TLB.push<TypedefTypeLoc>(TDTy); + TypedefTL.setNameLoc(TL.getNameLoc()); + + return TDTy; } }; @@ -2041,14 +2071,16 @@ struct ConvertConstructorToDeductionGuideTransform { // new ones. TypeLocBuilder TLB; SmallVector<ParmVarDecl*, 8> Params; - QualType NewType = transformFunctionProtoType(TLB, FPTL, Params, Args); + SmallVector<TypedefNameDecl *, 4> MaterializedTypedefs; + QualType NewType = transformFunctionProtoType(TLB, FPTL, Params, Args, + MaterializedTypedefs); if (NewType.isNull()) return nullptr; TypeSourceInfo *NewTInfo = TLB.getTypeSourceInfo(SemaRef.Context, NewType); return buildDeductionGuide(TemplateParams, CD->getExplicitSpecifier(), NewTInfo, CD->getBeginLoc(), CD->getLocation(), - CD->getEndLoc()); + CD->getEndLoc(), MaterializedTypedefs); } /// Build a deduction guide with the specified parameter types. @@ -2143,16 +2175,18 @@ struct ConvertConstructorToDeductionGuideTransform { return NewParam; } - QualType transformFunctionProtoType(TypeLocBuilder &TLB, - FunctionProtoTypeLoc TL, - SmallVectorImpl<ParmVarDecl*> &Params, - MultiLevelTemplateArgumentList &Args) { + QualType transformFunctionProtoType( + TypeLocBuilder &TLB, FunctionProtoTypeLoc TL, + SmallVectorImpl<ParmVarDecl *> &Params, + MultiLevelTemplateArgumentList &Args, + SmallVectorImpl<TypedefNameDecl *> &MaterializedTypedefs) { SmallVector<QualType, 4> ParamTypes; const FunctionProtoType *T = TL.getTypePtr(); // -- The types of the function parameters are those of the constructor. for (auto *OldParam : TL.getParams()) { - ParmVarDecl *NewParam = transformFunctionTypeParam(OldParam, Args); + ParmVarDecl *NewParam = + transformFunctionTypeParam(OldParam, Args, MaterializedTypedefs); if (!NewParam) return QualType(); ParamTypes.push_back(NewParam->getType()); @@ -2194,9 +2228,9 @@ struct ConvertConstructorToDeductionGuideTransform { return Result; } - ParmVarDecl * - transformFunctionTypeParam(ParmVarDecl *OldParam, - MultiLevelTemplateArgumentList &Args) { + ParmVarDecl *transformFunctionTypeParam( + ParmVarDecl *OldParam, MultiLevelTemplateArgumentList &Args, + llvm::SmallVectorImpl<TypedefNameDecl *> &MaterializedTypedefs) { TypeSourceInfo *OldDI = OldParam->getTypeSourceInfo(); TypeSourceInfo *NewDI; if (auto PackTL = OldDI->getTypeLoc().getAs<PackExpansionTypeLoc>()) { @@ -2219,7 +2253,8 @@ struct ConvertConstructorToDeductionGuideTransform { // members of the current instantiations with the definitions of those // typedefs, avoiding triggering instantiation of the deduced type during // deduction. - NewDI = ExtractTypeForDeductionGuide(SemaRef).transform(NewDI); + NewDI = ExtractTypeForDeductionGuide(SemaRef, MaterializedTypedefs) + .transform(NewDI); // Resolving a wording defect, we also inherit default arguments from the // constructor. @@ -2250,10 +2285,11 @@ struct ConvertConstructorToDeductionGuideTransform { return NewParam; } - NamedDecl *buildDeductionGuide(TemplateParameterList *TemplateParams, - ExplicitSpecifier ES, TypeSourceInfo *TInfo, - SourceLocation LocStart, SourceLocation Loc, - SourceLocation LocEnd) { + FunctionTemplateDecl *buildDeductionGuide( + TemplateParameterList *TemplateParams, ExplicitSpecifier ES, + TypeSourceInfo *TInfo, SourceLocation LocStart, SourceLocation Loc, + SourceLocation LocEnd, + llvm::ArrayRef<TypedefNameDecl *> MaterializedTypedefs = {}) { DeclarationNameInfo Name(DeductionGuideName, Loc); ArrayRef<ParmVarDecl *> Params = TInfo->getTypeLoc().castAs<FunctionProtoTypeLoc>().getParams(); @@ -2267,6 +2303,8 @@ struct ConvertConstructorToDeductionGuideTransform { for (auto *Param : Params) Param->setDeclContext(Guide); + for (auto *TD : MaterializedTypedefs) + TD->setDeclContext(Guide); auto *GuideTemplate = FunctionTemplateDecl::Create( SemaRef.Context, DC, Loc, DeductionGuideName, TemplateParams, Guide); diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 9cbdfcb5f2fb..bfda59d40c2a 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -3579,6 +3579,12 @@ LocalInstantiationScope::findInstantiationOf(const Decl *D) { if (isa<EnumDecl>(D)) return nullptr; + // Materialized typedefs/type alias for implicit deduction guides may require + // instantiation. + if (isa<TypedefNameDecl>(D) && + isa<CXXDeductionGuideDecl>(D->getDeclContext())) + return nullptr; + // If we didn't find the decl, then we either have a sema bug, or we have a // forward reference to a label declaration. Return null to indicate that // we have an uninstantiated label. diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index b4aa234a3934..7d0777cce6ae 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -5702,6 +5702,9 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, bool NeedInstantiate = false; if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) NeedInstantiate = RD->isLocalClass(); + else if (isa<TypedefNameDecl>(D) && + isa<CXXDeductionGuideDecl>(D->getDeclContext())) + NeedInstantiate = true; else NeedInstantiate = isa<EnumDecl>(D); if (NeedInstantiate) { diff --git a/clang/test/AST/deduction-guides.cpp b/clang/test/AST/deduction-guides.cpp new file mode 100644 index 000000000000..0e9d2754f865 --- /dev/null +++ b/clang/test/AST/deduction-guides.cpp @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -fsyntax-only %s -ast-dump -std=c++17 | FileCheck %s + +namespace PR46111 { +template <typename> +struct S; + +template <typename T> +struct HasDeductionGuide { + typedef PR46111::S<T> STy; + HasDeductionGuide(typename STy::Child); +}; + +// This causes deduction guides to be generated for all constructors. +HasDeductionGuide()->HasDeductionGuide<int>; + +template <typename T> +struct HasDeductionGuideTypeAlias { + using STy = PR46111::S<T>; + HasDeductionGuideTypeAlias(typename STy::Child); +}; + +// This causes deduction guides to be generated for all constructors. +HasDeductionGuideTypeAlias()->HasDeductionGuideTypeAlias<int>; + +// The parameter to this one shouldn't be an elaborated type. +// CHECK: CXXDeductionGuideDecl {{.*}} implicit <deduction guide for HasDeductionGuide> 'auto (typename STy::Child) -> HasDeductionGuide<T>' +// CHECK: CXXDeductionGuideDecl {{.*}} implicit <deduction guide for HasDeductionGuide> 'auto (HasDeductionGuide<T>) -> HasDeductionGuide<T>' +// CHECK: CXXDeductionGuideDecl {{.*}} <deduction guide for HasDeductionGuide> 'auto () -> HasDeductionGuide<int>' +// CHECK: CXXDeductionGuideDecl {{.*}} implicit <deduction guide for HasDeductionGuideTypeAlias> 'auto (typename STy::Child) -> HasDeductionGuideTypeAlias<T>' +// CHECK: CXXDeductionGuideDecl {{.*}} implicit <deduction guide for HasDeductionGuideTypeAlias> 'auto (HasDeductionGuideTypeAlias<T>) -> HasDeductionGuideTypeAlias<T>' +// CHECK: CXXDeductionGuideDecl {{.*}} <deduction guide for HasDeductionGuideTypeAlias> 'auto () -> HasDeductionGuideTypeAlias<int>' +} // namespace PR46111 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits