[clang] 82a2122 - (PR46111) Properly handle elaborated types in an implicit deduction guide
Erich Keane via cfe-commits
cfe-commits at lists.llvm.org
Fri Jun 12 05:32:26 PDT 2020
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
More information about the cfe-commits
mailing list