|
| 1 | +//===--- CTAD.cpp - -------------------------------------------------------===// |
| 2 | +// |
| 3 | +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | +// See https://llvm.org/LICENSE.txt for license information. |
| 5 | +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | +// |
| 7 | +//===----------------------------------------------------------------------===// |
| 8 | + |
| 9 | +#include "CTAD.h" |
| 10 | +#include "TreeTransform.h" |
| 11 | +#include "TypeLocBuilder.h" |
| 12 | +#include "clang/AST/ASTConsumer.h" |
| 13 | +#include "clang/AST/ASTContext.h" |
| 14 | +#include "clang/AST/ASTMutationListener.h" |
| 15 | +#include "clang/AST/ASTStructuralEquivalence.h" |
| 16 | +#include "clang/AST/CXXInheritance.h" |
| 17 | +#include "clang/AST/Decl.h" |
| 18 | +#include "clang/AST/DeclObjC.h" |
| 19 | +#include "clang/AST/DeclTemplate.h" |
| 20 | +#include "clang/AST/Expr.h" |
| 21 | +#include "clang/AST/Type.h" |
| 22 | +#include "clang/AST/TypeLoc.h" |
| 23 | +#include "clang/Basic/SourceLocation.h" |
| 24 | +#include "clang/Basic/Specifiers.h" |
| 25 | +#include "clang/Sema/DeclSpec.h" |
| 26 | +#include "clang/Sema/ScopeInfo.h" |
| 27 | +#include "clang/Sema/Template.h" |
| 28 | +#include "llvm/ADT/ArrayRef.h" |
| 29 | +#include <optional> |
| 30 | + |
| 31 | +namespace clang { |
| 32 | + |
| 33 | +namespace { |
| 34 | +/// Tree transform to "extract" a transformed type from a class template's |
| 35 | +/// constructor to a deduction guide. |
| 36 | +class ExtractTypeForDeductionGuide |
| 37 | + : public TreeTransform<ExtractTypeForDeductionGuide> { |
| 38 | + llvm::SmallVectorImpl<TypedefNameDecl *> &MaterializedTypedefs; |
| 39 | + |
| 40 | +public: |
| 41 | + typedef TreeTransform<ExtractTypeForDeductionGuide> Base; |
| 42 | + ExtractTypeForDeductionGuide( |
| 43 | + Sema &SemaRef, |
| 44 | + llvm::SmallVectorImpl<TypedefNameDecl *> &MaterializedTypedefs) |
| 45 | + : Base(SemaRef), MaterializedTypedefs(MaterializedTypedefs) {} |
| 46 | + |
| 47 | + TypeSourceInfo *transform(TypeSourceInfo *TSI) { return TransformType(TSI); } |
| 48 | + |
| 49 | + QualType TransformTypedefType(TypeLocBuilder &TLB, TypedefTypeLoc TL) { |
| 50 | + ASTContext &Context = SemaRef.getASTContext(); |
| 51 | + TypedefNameDecl *OrigDecl = TL.getTypedefNameDecl(); |
| 52 | + TypedefNameDecl *Decl = OrigDecl; |
| 53 | + // Transform the underlying type of the typedef and clone the Decl only if |
| 54 | + // the typedef has a dependent context. |
| 55 | + if (OrigDecl->getDeclContext()->isDependentContext()) { |
| 56 | + TypeLocBuilder InnerTLB; |
| 57 | + QualType Transformed = |
| 58 | + TransformType(InnerTLB, OrigDecl->getTypeSourceInfo()->getTypeLoc()); |
| 59 | + TypeSourceInfo *TSI = InnerTLB.getTypeSourceInfo(Context, Transformed); |
| 60 | + if (isa<TypeAliasDecl>(OrigDecl)) |
| 61 | + Decl = TypeAliasDecl::Create( |
| 62 | + Context, Context.getTranslationUnitDecl(), OrigDecl->getBeginLoc(), |
| 63 | + OrigDecl->getLocation(), OrigDecl->getIdentifier(), TSI); |
| 64 | + else { |
| 65 | + assert(isa<TypedefDecl>(OrigDecl) && "Not a Type alias or typedef"); |
| 66 | + Decl = TypedefDecl::Create( |
| 67 | + Context, Context.getTranslationUnitDecl(), OrigDecl->getBeginLoc(), |
| 68 | + OrigDecl->getLocation(), OrigDecl->getIdentifier(), TSI); |
| 69 | + } |
| 70 | + MaterializedTypedefs.push_back(Decl); |
| 71 | + } |
| 72 | + |
| 73 | + QualType TDTy = Context.getTypedefType(Decl); |
| 74 | + TypedefTypeLoc TypedefTL = TLB.push<TypedefTypeLoc>(TDTy); |
| 75 | + TypedefTL.setNameLoc(TL.getNameLoc()); |
| 76 | + |
| 77 | + return TDTy; |
| 78 | + } |
| 79 | +}; |
| 80 | +} // namespace |
| 81 | + |
| 82 | +ParmVarDecl *transformFunctionTypeParam( |
| 83 | + Sema &SemaRef, ParmVarDecl *OldParam, DeclContext *DC, |
| 84 | + MultiLevelTemplateArgumentList &Args, |
| 85 | + llvm::SmallVectorImpl<TypedefNameDecl *> &MaterializedTypedefs) { |
| 86 | + TypeSourceInfo *OldDI = OldParam->getTypeSourceInfo(); |
| 87 | + TypeSourceInfo *NewDI; |
| 88 | + if (auto PackTL = OldDI->getTypeLoc().getAs<PackExpansionTypeLoc>()) { |
| 89 | + // Expand out the one and only element in each inner pack. |
| 90 | + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, 0); |
| 91 | + NewDI = SemaRef.SubstType(PackTL.getPatternLoc(), Args, |
| 92 | + OldParam->getLocation(), OldParam->getDeclName()); |
| 93 | + if (!NewDI) |
| 94 | + return nullptr; |
| 95 | + NewDI = SemaRef.CheckPackExpansion(NewDI, PackTL.getEllipsisLoc(), |
| 96 | + PackTL.getTypePtr()->getNumExpansions()); |
| 97 | + } else |
| 98 | + NewDI = SemaRef.SubstType(OldDI, Args, OldParam->getLocation(), |
| 99 | + OldParam->getDeclName()); |
| 100 | + if (!NewDI) |
| 101 | + return nullptr; |
| 102 | + |
| 103 | + // Extract the type. This (for instance) replaces references to typedef |
| 104 | + // members of the current instantiations with the definitions of those |
| 105 | + // typedefs, avoiding triggering instantiation of the deduced type during |
| 106 | + // deduction. |
| 107 | + NewDI = ExtractTypeForDeductionGuide(SemaRef, MaterializedTypedefs) |
| 108 | + .transform(NewDI); |
| 109 | + |
| 110 | + // Resolving a wording defect, we also inherit default arguments from the |
| 111 | + // constructor. |
| 112 | + ExprResult NewDefArg; |
| 113 | + if (OldParam->hasDefaultArg()) { |
| 114 | + // We don't care what the value is (we won't use it); just create a |
| 115 | + // placeholder to indicate there is a default argument. |
| 116 | + QualType ParamTy = NewDI->getType(); |
| 117 | + NewDefArg = new (SemaRef.Context) |
| 118 | + OpaqueValueExpr(OldParam->getDefaultArgRange().getBegin(), |
| 119 | + ParamTy.getNonLValueExprType(SemaRef.Context), |
| 120 | + ParamTy->isLValueReferenceType() ? VK_LValue |
| 121 | + : ParamTy->isRValueReferenceType() ? VK_XValue |
| 122 | + : VK_PRValue); |
| 123 | + } |
| 124 | + // Handle arrays and functions decay. |
| 125 | + auto NewType = NewDI->getType(); |
| 126 | + if (NewType->isArrayType() || NewType->isFunctionType()) |
| 127 | + NewType = SemaRef.Context.getDecayedType(NewType); |
| 128 | + |
| 129 | + ParmVarDecl *NewParam = ParmVarDecl::Create( |
| 130 | + SemaRef.Context, DC, OldParam->getInnerLocStart(), |
| 131 | + OldParam->getLocation(), OldParam->getIdentifier(), NewType, NewDI, |
| 132 | + OldParam->getStorageClass(), NewDefArg.get()); |
| 133 | + NewParam->setScopeInfo(OldParam->getFunctionScopeDepth(), |
| 134 | + OldParam->getFunctionScopeIndex()); |
| 135 | + SemaRef.CurrentInstantiationScope->InstantiatedLocal(OldParam, NewParam); |
| 136 | + return NewParam; |
| 137 | +} |
| 138 | + |
| 139 | +TemplateTypeParmDecl * |
| 140 | +transformTemplateTypeParam(Sema &SemaRef, DeclContext *DC, |
| 141 | + TemplateTypeParmDecl *TTP, |
| 142 | + MultiLevelTemplateArgumentList &Args, |
| 143 | + unsigned NewDepth, unsigned NewIndex) { |
| 144 | + // TemplateTypeParmDecl's index cannot be changed after creation, so |
| 145 | + // substitute it directly. |
| 146 | + auto *NewTTP = TemplateTypeParmDecl::Create( |
| 147 | + SemaRef.Context, DC, TTP->getBeginLoc(), TTP->getLocation(), NewDepth, |
| 148 | + NewIndex, TTP->getIdentifier(), TTP->wasDeclaredWithTypename(), |
| 149 | + TTP->isParameterPack(), TTP->hasTypeConstraint(), |
| 150 | + TTP->isExpandedParameterPack() |
| 151 | + ? std::optional<unsigned>(TTP->getNumExpansionParameters()) |
| 152 | + : std::nullopt); |
| 153 | + if (const auto *TC = TTP->getTypeConstraint()) |
| 154 | + SemaRef.SubstTypeConstraint(NewTTP, TC, Args, |
| 155 | + /*EvaluateConstraint*/ true); |
| 156 | + if (TTP->hasDefaultArgument()) { |
| 157 | + TypeSourceInfo *InstantiatedDefaultArg = |
| 158 | + SemaRef.SubstType(TTP->getDefaultArgumentInfo(), Args, |
| 159 | + TTP->getDefaultArgumentLoc(), TTP->getDeclName()); |
| 160 | + if (InstantiatedDefaultArg) |
| 161 | + NewTTP->setDefaultArgument(InstantiatedDefaultArg); |
| 162 | + } |
| 163 | + SemaRef.CurrentInstantiationScope->InstantiatedLocal(TTP, NewTTP); |
| 164 | + return NewTTP; |
| 165 | +} |
| 166 | + |
| 167 | +FunctionTemplateDecl * |
| 168 | +buildDeductionGuide(Sema &SemaRef, TemplateDecl *OriginalTemplate, |
| 169 | + TemplateParameterList *TemplateParams, |
| 170 | + CXXConstructorDecl *Ctor, ExplicitSpecifier ES, |
| 171 | + TypeSourceInfo *TInfo, SourceLocation LocStart, |
| 172 | + SourceLocation Loc, SourceLocation LocEnd, bool IsImplicit, |
| 173 | + llvm::ArrayRef<TypedefNameDecl *> MaterializedTypedefs) { |
| 174 | + DeclContext *DC = OriginalTemplate->getDeclContext(); |
| 175 | + auto DeductionGuideName = |
| 176 | + SemaRef.Context.DeclarationNames.getCXXDeductionGuideName( |
| 177 | + OriginalTemplate); |
| 178 | + |
| 179 | + DeclarationNameInfo Name(DeductionGuideName, Loc); |
| 180 | + ArrayRef<ParmVarDecl *> Params = |
| 181 | + TInfo->getTypeLoc().castAs<FunctionProtoTypeLoc>().getParams(); |
| 182 | + |
| 183 | + // Build the implicit deduction guide template. |
| 184 | + auto *Guide = |
| 185 | + CXXDeductionGuideDecl::Create(SemaRef.Context, DC, LocStart, ES, Name, |
| 186 | + TInfo->getType(), TInfo, LocEnd, Ctor); |
| 187 | + Guide->setImplicit(IsImplicit); |
| 188 | + Guide->setParams(Params); |
| 189 | + |
| 190 | + for (auto *Param : Params) |
| 191 | + Param->setDeclContext(Guide); |
| 192 | + for (auto *TD : MaterializedTypedefs) |
| 193 | + TD->setDeclContext(Guide); |
| 194 | + |
| 195 | + auto *GuideTemplate = FunctionTemplateDecl::Create( |
| 196 | + SemaRef.Context, DC, Loc, DeductionGuideName, TemplateParams, Guide); |
| 197 | + GuideTemplate->setImplicit(IsImplicit); |
| 198 | + Guide->setDescribedFunctionTemplate(GuideTemplate); |
| 199 | + |
| 200 | + if (isa<CXXRecordDecl>(DC)) { |
| 201 | + Guide->setAccess(AS_public); |
| 202 | + GuideTemplate->setAccess(AS_public); |
| 203 | + } |
| 204 | + |
| 205 | + DC->addDecl(GuideTemplate); |
| 206 | + return GuideTemplate; |
| 207 | +} |
| 208 | + |
| 209 | +} // namespace clang |
0 commit comments