llvm-project/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Matheus Izvekov 761787d425
Reland: [clang] Improved canonicalization for template specialization types (#135414)
This relands https://github.com/llvm/llvm-project/pull/135119, after
fixing crashes seen in LLDB CI reported here:
https://github.com/llvm/llvm-project/pull/135119#issuecomment-2794910840

Fixes https://github.com/llvm/llvm-project/pull/135119

This changes the TemplateArgument representation to hold a flag
indicating whether a tempalte argument of expression type is supposed to
be canonical or not.

This gets one step closer to solving
https://github.com/llvm/llvm-project/issues/92292

This still doesn't try to unique as-written TSTs. While this would
increase the amount of memory savings and make code dealing with the AST
more well-behaved, profiling template argument lists is still too
expensive for this to be worthwhile, at least for now.

This also fixes the context creation of TSTs, so that they don't in some
cases get incorrectly flagged as sugar over their own canonical form.
This is captured in the test expectation change of some AST dumps.

This fixes some places which were unnecessarily canonicalizing these
TSTs.
2025-04-12 14:26:30 -03:00

7078 lines
278 KiB
C++

//===--- SemaTemplateInstantiateDecl.cpp - C++ Template Decl Instantiation ===/
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//===----------------------------------------------------------------------===/
//
// This file implements C++ template instantiation for declarations.
//
//===----------------------------------------------------------------------===/
#include "TreeTransform.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTLambda.h"
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DependentDiagnostic.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/PrettyDeclStackTrace.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/EnterExpressionEvaluationContext.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaAMDGPU.h"
#include "clang/Sema/SemaCUDA.h"
#include "clang/Sema/SemaHLSL.h"
#include "clang/Sema/SemaObjC.h"
#include "clang/Sema/SemaOpenMP.h"
#include "clang/Sema/SemaSwift.h"
#include "clang/Sema/Template.h"
#include "clang/Sema/TemplateInstCallback.h"
#include "llvm/Support/TimeProfiler.h"
#include <optional>
using namespace clang;
static bool isDeclWithinFunction(const Decl *D) {
const DeclContext *DC = D->getDeclContext();
if (DC->isFunctionOrMethod())
return true;
if (DC->isRecord())
return cast<CXXRecordDecl>(DC)->isLocalClass();
return false;
}
template<typename DeclT>
static bool SubstQualifier(Sema &SemaRef, const DeclT *OldDecl, DeclT *NewDecl,
const MultiLevelTemplateArgumentList &TemplateArgs) {
if (!OldDecl->getQualifierLoc())
return false;
assert((NewDecl->getFriendObjectKind() ||
!OldDecl->getLexicalDeclContext()->isDependentContext()) &&
"non-friend with qualified name defined in dependent context");
Sema::ContextRAII SavedContext(
SemaRef,
const_cast<DeclContext *>(NewDecl->getFriendObjectKind()
? NewDecl->getLexicalDeclContext()
: OldDecl->getLexicalDeclContext()));
NestedNameSpecifierLoc NewQualifierLoc
= SemaRef.SubstNestedNameSpecifierLoc(OldDecl->getQualifierLoc(),
TemplateArgs);
if (!NewQualifierLoc)
return true;
NewDecl->setQualifierInfo(NewQualifierLoc);
return false;
}
bool TemplateDeclInstantiator::SubstQualifier(const DeclaratorDecl *OldDecl,
DeclaratorDecl *NewDecl) {
return ::SubstQualifier(SemaRef, OldDecl, NewDecl, TemplateArgs);
}
bool TemplateDeclInstantiator::SubstQualifier(const TagDecl *OldDecl,
TagDecl *NewDecl) {
return ::SubstQualifier(SemaRef, OldDecl, NewDecl, TemplateArgs);
}
// Include attribute instantiation code.
#include "clang/Sema/AttrTemplateInstantiate.inc"
static void instantiateDependentAlignedAttr(
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
const AlignedAttr *Aligned, Decl *New, bool IsPackExpansion) {
if (Aligned->isAlignmentExpr()) {
// The alignment expression is a constant expression.
EnterExpressionEvaluationContext Unevaluated(
S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
ExprResult Result = S.SubstExpr(Aligned->getAlignmentExpr(), TemplateArgs);
if (!Result.isInvalid())
S.AddAlignedAttr(New, *Aligned, Result.getAs<Expr>(), IsPackExpansion);
} else {
if (TypeSourceInfo *Result =
S.SubstType(Aligned->getAlignmentType(), TemplateArgs,
Aligned->getLocation(), DeclarationName())) {
if (!S.CheckAlignasTypeArgument(Aligned->getSpelling(), Result,
Aligned->getLocation(),
Result->getTypeLoc().getSourceRange()))
S.AddAlignedAttr(New, *Aligned, Result, IsPackExpansion);
}
}
}
static void instantiateDependentAlignedAttr(
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
const AlignedAttr *Aligned, Decl *New) {
if (!Aligned->isPackExpansion()) {
instantiateDependentAlignedAttr(S, TemplateArgs, Aligned, New, false);
return;
}
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
if (Aligned->isAlignmentExpr())
S.collectUnexpandedParameterPacks(Aligned->getAlignmentExpr(),
Unexpanded);
else
S.collectUnexpandedParameterPacks(Aligned->getAlignmentType()->getTypeLoc(),
Unexpanded);
assert(!Unexpanded.empty() && "Pack expansion without parameter packs?");
// Determine whether we can expand this attribute pack yet.
bool Expand = true, RetainExpansion = false;
UnsignedOrNone NumExpansions = std::nullopt;
// FIXME: Use the actual location of the ellipsis.
SourceLocation EllipsisLoc = Aligned->getLocation();
if (S.CheckParameterPacksForExpansion(EllipsisLoc, Aligned->getRange(),
Unexpanded, TemplateArgs, Expand,
RetainExpansion, NumExpansions))
return;
if (!Expand) {
Sema::ArgPackSubstIndexRAII SubstIndex(S, std::nullopt);
instantiateDependentAlignedAttr(S, TemplateArgs, Aligned, New, true);
} else {
for (unsigned I = 0; I != *NumExpansions; ++I) {
Sema::ArgPackSubstIndexRAII SubstIndex(S, I);
instantiateDependentAlignedAttr(S, TemplateArgs, Aligned, New, false);
}
}
}
static void instantiateDependentAssumeAlignedAttr(
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
const AssumeAlignedAttr *Aligned, Decl *New) {
// The alignment expression is a constant expression.
EnterExpressionEvaluationContext Unevaluated(
S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
Expr *E, *OE = nullptr;
ExprResult Result = S.SubstExpr(Aligned->getAlignment(), TemplateArgs);
if (Result.isInvalid())
return;
E = Result.getAs<Expr>();
if (Aligned->getOffset()) {
Result = S.SubstExpr(Aligned->getOffset(), TemplateArgs);
if (Result.isInvalid())
return;
OE = Result.getAs<Expr>();
}
S.AddAssumeAlignedAttr(New, *Aligned, E, OE);
}
static void instantiateDependentAlignValueAttr(
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
const AlignValueAttr *Aligned, Decl *New) {
// The alignment expression is a constant expression.
EnterExpressionEvaluationContext Unevaluated(
S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
ExprResult Result = S.SubstExpr(Aligned->getAlignment(), TemplateArgs);
if (!Result.isInvalid())
S.AddAlignValueAttr(New, *Aligned, Result.getAs<Expr>());
}
static void instantiateDependentAllocAlignAttr(
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
const AllocAlignAttr *Align, Decl *New) {
Expr *Param = IntegerLiteral::Create(
S.getASTContext(),
llvm::APInt(64, Align->getParamIndex().getSourceIndex()),
S.getASTContext().UnsignedLongLongTy, Align->getLocation());
S.AddAllocAlignAttr(New, *Align, Param);
}
static void instantiateDependentAnnotationAttr(
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
const AnnotateAttr *Attr, Decl *New) {
EnterExpressionEvaluationContext Unevaluated(
S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
// If the attribute has delayed arguments it will have to instantiate those
// and handle them as new arguments for the attribute.
bool HasDelayedArgs = Attr->delayedArgs_size();
ArrayRef<Expr *> ArgsToInstantiate =
HasDelayedArgs
? ArrayRef<Expr *>{Attr->delayedArgs_begin(), Attr->delayedArgs_end()}
: ArrayRef<Expr *>{Attr->args_begin(), Attr->args_end()};
SmallVector<Expr *, 4> Args;
if (S.SubstExprs(ArgsToInstantiate,
/*IsCall=*/false, TemplateArgs, Args))
return;
StringRef Str = Attr->getAnnotation();
if (HasDelayedArgs) {
if (Args.size() < 1) {
S.Diag(Attr->getLoc(), diag::err_attribute_too_few_arguments)
<< Attr << 1;
return;
}
if (!S.checkStringLiteralArgumentAttr(*Attr, Args[0], Str))
return;
llvm::SmallVector<Expr *, 4> ActualArgs;
ActualArgs.insert(ActualArgs.begin(), Args.begin() + 1, Args.end());
std::swap(Args, ActualArgs);
}
auto *AA = S.CreateAnnotationAttr(*Attr, Str, Args);
if (AA) {
New->addAttr(AA);
}
}
static Expr *instantiateDependentFunctionAttrCondition(
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
const Attr *A, Expr *OldCond, const Decl *Tmpl, FunctionDecl *New) {
Expr *Cond = nullptr;
{
Sema::ContextRAII SwitchContext(S, New);
EnterExpressionEvaluationContext Unevaluated(
S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
ExprResult Result = S.SubstExpr(OldCond, TemplateArgs);
if (Result.isInvalid())
return nullptr;
Cond = Result.getAs<Expr>();
}
if (!Cond->isTypeDependent()) {
ExprResult Converted = S.PerformContextuallyConvertToBool(Cond);
if (Converted.isInvalid())
return nullptr;
Cond = Converted.get();
}
SmallVector<PartialDiagnosticAt, 8> Diags;
if (OldCond->isValueDependent() && !Cond->isValueDependent() &&
!Expr::isPotentialConstantExprUnevaluated(Cond, New, Diags)) {
S.Diag(A->getLocation(), diag::err_attr_cond_never_constant_expr) << A;
for (const auto &P : Diags)
S.Diag(P.first, P.second);
return nullptr;
}
return Cond;
}
static void instantiateDependentEnableIfAttr(
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
const EnableIfAttr *EIA, const Decl *Tmpl, FunctionDecl *New) {
Expr *Cond = instantiateDependentFunctionAttrCondition(
S, TemplateArgs, EIA, EIA->getCond(), Tmpl, New);
if (Cond)
New->addAttr(new (S.getASTContext()) EnableIfAttr(S.getASTContext(), *EIA,
Cond, EIA->getMessage()));
}
static void instantiateDependentDiagnoseIfAttr(
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
const DiagnoseIfAttr *DIA, const Decl *Tmpl, FunctionDecl *New) {
Expr *Cond = instantiateDependentFunctionAttrCondition(
S, TemplateArgs, DIA, DIA->getCond(), Tmpl, New);
if (Cond)
New->addAttr(new (S.getASTContext()) DiagnoseIfAttr(
S.getASTContext(), *DIA, Cond, DIA->getMessage(),
DIA->getDefaultSeverity(), DIA->getWarningGroup(),
DIA->getArgDependent(), New));
}
// Constructs and adds to New a new instance of CUDALaunchBoundsAttr using
// template A as the base and arguments from TemplateArgs.
static void instantiateDependentCUDALaunchBoundsAttr(
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
const CUDALaunchBoundsAttr &Attr, Decl *New) {
// The alignment expression is a constant expression.
EnterExpressionEvaluationContext Unevaluated(
S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
ExprResult Result = S.SubstExpr(Attr.getMaxThreads(), TemplateArgs);
if (Result.isInvalid())
return;
Expr *MaxThreads = Result.getAs<Expr>();
Expr *MinBlocks = nullptr;
if (Attr.getMinBlocks()) {
Result = S.SubstExpr(Attr.getMinBlocks(), TemplateArgs);
if (Result.isInvalid())
return;
MinBlocks = Result.getAs<Expr>();
}
Expr *MaxBlocks = nullptr;
if (Attr.getMaxBlocks()) {
Result = S.SubstExpr(Attr.getMaxBlocks(), TemplateArgs);
if (Result.isInvalid())
return;
MaxBlocks = Result.getAs<Expr>();
}
S.AddLaunchBoundsAttr(New, Attr, MaxThreads, MinBlocks, MaxBlocks);
}
static void
instantiateDependentModeAttr(Sema &S,
const MultiLevelTemplateArgumentList &TemplateArgs,
const ModeAttr &Attr, Decl *New) {
S.AddModeAttr(New, Attr, Attr.getMode(),
/*InInstantiation=*/true);
}
/// Instantiation of 'declare simd' attribute and its arguments.
static void instantiateOMPDeclareSimdDeclAttr(
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
const OMPDeclareSimdDeclAttr &Attr, Decl *New) {
// Allow 'this' in clauses with varlist.
if (auto *FTD = dyn_cast<FunctionTemplateDecl>(New))
New = FTD->getTemplatedDecl();
auto *FD = cast<FunctionDecl>(New);
auto *ThisContext = dyn_cast_or_null<CXXRecordDecl>(FD->getDeclContext());
SmallVector<Expr *, 4> Uniforms, Aligneds, Alignments, Linears, Steps;
SmallVector<unsigned, 4> LinModifiers;
auto SubstExpr = [&](Expr *E) -> ExprResult {
if (auto *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()))
if (auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) {
Sema::ContextRAII SavedContext(S, FD);
LocalInstantiationScope Local(S);
if (FD->getNumParams() > PVD->getFunctionScopeIndex())
Local.InstantiatedLocal(
PVD, FD->getParamDecl(PVD->getFunctionScopeIndex()));
return S.SubstExpr(E, TemplateArgs);
}
Sema::CXXThisScopeRAII ThisScope(S, ThisContext, Qualifiers(),
FD->isCXXInstanceMember());
return S.SubstExpr(E, TemplateArgs);
};
// Substitute a single OpenMP clause, which is a potentially-evaluated
// full-expression.
auto Subst = [&](Expr *E) -> ExprResult {
EnterExpressionEvaluationContext Evaluated(
S, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
ExprResult Res = SubstExpr(E);
if (Res.isInvalid())
return Res;
return S.ActOnFinishFullExpr(Res.get(), false);
};
ExprResult Simdlen;
if (auto *E = Attr.getSimdlen())
Simdlen = Subst(E);
if (Attr.uniforms_size() > 0) {
for(auto *E : Attr.uniforms()) {
ExprResult Inst = Subst(E);
if (Inst.isInvalid())
continue;
Uniforms.push_back(Inst.get());
}
}
auto AI = Attr.alignments_begin();
for (auto *E : Attr.aligneds()) {
ExprResult Inst = Subst(E);
if (Inst.isInvalid())
continue;
Aligneds.push_back(Inst.get());
Inst = ExprEmpty();
if (*AI)
Inst = S.SubstExpr(*AI, TemplateArgs);
Alignments.push_back(Inst.get());
++AI;
}
auto SI = Attr.steps_begin();
for (auto *E : Attr.linears()) {
ExprResult Inst = Subst(E);
if (Inst.isInvalid())
continue;
Linears.push_back(Inst.get());
Inst = ExprEmpty();
if (*SI)
Inst = S.SubstExpr(*SI, TemplateArgs);
Steps.push_back(Inst.get());
++SI;
}
LinModifiers.append(Attr.modifiers_begin(), Attr.modifiers_end());
(void)S.OpenMP().ActOnOpenMPDeclareSimdDirective(
S.ConvertDeclToDeclGroup(New), Attr.getBranchState(), Simdlen.get(),
Uniforms, Aligneds, Alignments, Linears, LinModifiers, Steps,
Attr.getRange());
}
/// Instantiation of 'declare variant' attribute and its arguments.
static void instantiateOMPDeclareVariantAttr(
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
const OMPDeclareVariantAttr &Attr, Decl *New) {
// Allow 'this' in clauses with varlist.
if (auto *FTD = dyn_cast<FunctionTemplateDecl>(New))
New = FTD->getTemplatedDecl();
auto *FD = cast<FunctionDecl>(New);
auto *ThisContext = dyn_cast_or_null<CXXRecordDecl>(FD->getDeclContext());
auto &&SubstExpr = [FD, ThisContext, &S, &TemplateArgs](Expr *E) {
if (auto *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()))
if (auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) {
Sema::ContextRAII SavedContext(S, FD);
LocalInstantiationScope Local(S);
if (FD->getNumParams() > PVD->getFunctionScopeIndex())
Local.InstantiatedLocal(
PVD, FD->getParamDecl(PVD->getFunctionScopeIndex()));
return S.SubstExpr(E, TemplateArgs);
}
Sema::CXXThisScopeRAII ThisScope(S, ThisContext, Qualifiers(),
FD->isCXXInstanceMember());
return S.SubstExpr(E, TemplateArgs);
};
// Substitute a single OpenMP clause, which is a potentially-evaluated
// full-expression.
auto &&Subst = [&SubstExpr, &S](Expr *E) {
EnterExpressionEvaluationContext Evaluated(
S, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
ExprResult Res = SubstExpr(E);
if (Res.isInvalid())
return Res;
return S.ActOnFinishFullExpr(Res.get(), false);
};
ExprResult VariantFuncRef;
if (Expr *E = Attr.getVariantFuncRef()) {
// Do not mark function as is used to prevent its emission if this is the
// only place where it is used.
EnterExpressionEvaluationContext Unevaluated(
S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
VariantFuncRef = Subst(E);
}
// Copy the template version of the OMPTraitInfo and run substitute on all
// score and condition expressiosn.
OMPTraitInfo &TI = S.getASTContext().getNewOMPTraitInfo();
TI = *Attr.getTraitInfos();
// Try to substitute template parameters in score and condition expressions.
auto SubstScoreOrConditionExpr = [&S, Subst](Expr *&E, bool) {
if (E) {
EnterExpressionEvaluationContext Unevaluated(
S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
ExprResult ER = Subst(E);
if (ER.isUsable())
E = ER.get();
else
return true;
}
return false;
};
if (TI.anyScoreOrCondition(SubstScoreOrConditionExpr))
return;
Expr *E = VariantFuncRef.get();
// Check function/variant ref for `omp declare variant` but not for `omp
// begin declare variant` (which use implicit attributes).
std::optional<std::pair<FunctionDecl *, Expr *>> DeclVarData =
S.OpenMP().checkOpenMPDeclareVariantFunction(
S.ConvertDeclToDeclGroup(New), E, TI, Attr.appendArgs_size(),
Attr.getRange());
if (!DeclVarData)
return;
E = DeclVarData->second;
FD = DeclVarData->first;
if (auto *VariantDRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts())) {
if (auto *VariantFD = dyn_cast<FunctionDecl>(VariantDRE->getDecl())) {
if (auto *VariantFTD = VariantFD->getDescribedFunctionTemplate()) {
if (!VariantFTD->isThisDeclarationADefinition())
return;
Sema::TentativeAnalysisScope Trap(S);
const TemplateArgumentList *TAL = TemplateArgumentList::CreateCopy(
S.Context, TemplateArgs.getInnermost());
auto *SubstFD = S.InstantiateFunctionDeclaration(VariantFTD, TAL,
New->getLocation());
if (!SubstFD)
return;
QualType NewType = S.Context.mergeFunctionTypes(
SubstFD->getType(), FD->getType(),
/* OfBlockPointer */ false,
/* Unqualified */ false, /* AllowCXX */ true);
if (NewType.isNull())
return;
S.InstantiateFunctionDefinition(
New->getLocation(), SubstFD, /* Recursive */ true,
/* DefinitionRequired */ false, /* AtEndOfTU */ false);
SubstFD->setInstantiationIsPending(!SubstFD->isDefined());
E = DeclRefExpr::Create(S.Context, NestedNameSpecifierLoc(),
SourceLocation(), SubstFD,
/* RefersToEnclosingVariableOrCapture */ false,
/* NameLoc */ SubstFD->getLocation(),
SubstFD->getType(), ExprValueKind::VK_PRValue);
}
}
}
SmallVector<Expr *, 8> NothingExprs;
SmallVector<Expr *, 8> NeedDevicePtrExprs;
SmallVector<OMPInteropInfo, 4> AppendArgs;
for (Expr *E : Attr.adjustArgsNothing()) {
ExprResult ER = Subst(E);
if (ER.isInvalid())
continue;
NothingExprs.push_back(ER.get());
}
for (Expr *E : Attr.adjustArgsNeedDevicePtr()) {
ExprResult ER = Subst(E);
if (ER.isInvalid())
continue;
NeedDevicePtrExprs.push_back(ER.get());
}
for (OMPInteropInfo &II : Attr.appendArgs()) {
// When prefer_type is implemented for append_args handle them here too.
AppendArgs.emplace_back(II.IsTarget, II.IsTargetSync);
}
S.OpenMP().ActOnOpenMPDeclareVariantDirective(
FD, E, TI, NothingExprs, NeedDevicePtrExprs, AppendArgs, SourceLocation(),
SourceLocation(), Attr.getRange());
}
static void instantiateDependentAMDGPUFlatWorkGroupSizeAttr(
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
const AMDGPUFlatWorkGroupSizeAttr &Attr, Decl *New) {
// Both min and max expression are constant expressions.
EnterExpressionEvaluationContext Unevaluated(
S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
ExprResult Result = S.SubstExpr(Attr.getMin(), TemplateArgs);
if (Result.isInvalid())
return;
Expr *MinExpr = Result.getAs<Expr>();
Result = S.SubstExpr(Attr.getMax(), TemplateArgs);
if (Result.isInvalid())
return;
Expr *MaxExpr = Result.getAs<Expr>();
S.AMDGPU().addAMDGPUFlatWorkGroupSizeAttr(New, Attr, MinExpr, MaxExpr);
}
static void instantiateDependentReqdWorkGroupSizeAttr(
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
const ReqdWorkGroupSizeAttr &Attr, Decl *New) {
// Both min and max expression are constant expressions.
EnterExpressionEvaluationContext Unevaluated(
S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
ExprResult Result = S.SubstExpr(Attr.getXDim(), TemplateArgs);
if (Result.isInvalid())
return;
Expr *X = Result.getAs<Expr>();
Result = S.SubstExpr(Attr.getYDim(), TemplateArgs);
if (Result.isInvalid())
return;
Expr *Y = Result.getAs<Expr>();
Result = S.SubstExpr(Attr.getZDim(), TemplateArgs);
if (Result.isInvalid())
return;
Expr *Z = Result.getAs<Expr>();
ASTContext &Context = S.getASTContext();
New->addAttr(::new (Context) ReqdWorkGroupSizeAttr(Context, Attr, X, Y, Z));
}
ExplicitSpecifier Sema::instantiateExplicitSpecifier(
const MultiLevelTemplateArgumentList &TemplateArgs, ExplicitSpecifier ES) {
if (!ES.getExpr())
return ES;
Expr *OldCond = ES.getExpr();
Expr *Cond = nullptr;
{
EnterExpressionEvaluationContext Unevaluated(
*this, Sema::ExpressionEvaluationContext::ConstantEvaluated);
ExprResult SubstResult = SubstExpr(OldCond, TemplateArgs);
if (SubstResult.isInvalid()) {
return ExplicitSpecifier::Invalid();
}
Cond = SubstResult.get();
}
ExplicitSpecifier Result(Cond, ES.getKind());
if (!Cond->isTypeDependent())
tryResolveExplicitSpecifier(Result);
return Result;
}
static void instantiateDependentAMDGPUWavesPerEUAttr(
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
const AMDGPUWavesPerEUAttr &Attr, Decl *New) {
// Both min and max expression are constant expressions.
EnterExpressionEvaluationContext Unevaluated(
S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
ExprResult Result = S.SubstExpr(Attr.getMin(), TemplateArgs);
if (Result.isInvalid())
return;
Expr *MinExpr = Result.getAs<Expr>();
Expr *MaxExpr = nullptr;
if (auto Max = Attr.getMax()) {
Result = S.SubstExpr(Max, TemplateArgs);
if (Result.isInvalid())
return;
MaxExpr = Result.getAs<Expr>();
}
S.AMDGPU().addAMDGPUWavesPerEUAttr(New, Attr, MinExpr, MaxExpr);
}
static void instantiateDependentAMDGPUMaxNumWorkGroupsAttr(
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
const AMDGPUMaxNumWorkGroupsAttr &Attr, Decl *New) {
EnterExpressionEvaluationContext Unevaluated(
S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
ExprResult ResultX = S.SubstExpr(Attr.getMaxNumWorkGroupsX(), TemplateArgs);
if (!ResultX.isUsable())
return;
ExprResult ResultY = S.SubstExpr(Attr.getMaxNumWorkGroupsY(), TemplateArgs);
if (!ResultY.isUsable())
return;
ExprResult ResultZ = S.SubstExpr(Attr.getMaxNumWorkGroupsZ(), TemplateArgs);
if (!ResultZ.isUsable())
return;
Expr *XExpr = ResultX.getAs<Expr>();
Expr *YExpr = ResultY.getAs<Expr>();
Expr *ZExpr = ResultZ.getAs<Expr>();
S.AMDGPU().addAMDGPUMaxNumWorkGroupsAttr(New, Attr, XExpr, YExpr, ZExpr);
}
// This doesn't take any template parameters, but we have a custom action that
// needs to happen when the kernel itself is instantiated. We need to run the
// ItaniumMangler to mark the names required to name this kernel.
static void instantiateDependentSYCLKernelAttr(
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
const SYCLKernelAttr &Attr, Decl *New) {
New->addAttr(Attr.clone(S.getASTContext()));
}
/// Determine whether the attribute A might be relevant to the declaration D.
/// If not, we can skip instantiating it. The attribute may or may not have
/// been instantiated yet.
static bool isRelevantAttr(Sema &S, const Decl *D, const Attr *A) {
// 'preferred_name' is only relevant to the matching specialization of the
// template.
if (const auto *PNA = dyn_cast<PreferredNameAttr>(A)) {
QualType T = PNA->getTypedefType();
const auto *RD = cast<CXXRecordDecl>(D);
if (!T->isDependentType() && !RD->isDependentContext() &&
!declaresSameEntity(T->getAsCXXRecordDecl(), RD))
return false;
for (const auto *ExistingPNA : D->specific_attrs<PreferredNameAttr>())
if (S.Context.hasSameType(ExistingPNA->getTypedefType(),
PNA->getTypedefType()))
return false;
return true;
}
if (const auto *BA = dyn_cast<BuiltinAttr>(A)) {
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
switch (BA->getID()) {
case Builtin::BIforward:
// Do not treat 'std::forward' as a builtin if it takes an rvalue reference
// type and returns an lvalue reference type. The library implementation
// will produce an error in this case; don't get in its way.
if (FD && FD->getNumParams() >= 1 &&
FD->getParamDecl(0)->getType()->isRValueReferenceType() &&
FD->getReturnType()->isLValueReferenceType()) {
return false;
}
[[fallthrough]];
case Builtin::BImove:
case Builtin::BImove_if_noexcept:
// HACK: Super-old versions of libc++ (3.1 and earlier) provide
// std::forward and std::move overloads that sometimes return by value
// instead of by reference when building in C++98 mode. Don't treat such
// cases as builtins.
if (FD && !FD->getReturnType()->isReferenceType())
return false;
break;
}
}
return true;
}
static void instantiateDependentHLSLParamModifierAttr(
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
const HLSLParamModifierAttr *Attr, Decl *New) {
ParmVarDecl *P = cast<ParmVarDecl>(New);
P->addAttr(Attr->clone(S.getASTContext()));
P->setType(S.HLSL().getInoutParameterType(P->getType()));
}
void Sema::InstantiateAttrsForDecl(
const MultiLevelTemplateArgumentList &TemplateArgs, const Decl *Tmpl,
Decl *New, LateInstantiatedAttrVec *LateAttrs,
LocalInstantiationScope *OuterMostScope) {
if (NamedDecl *ND = dyn_cast<NamedDecl>(New)) {
// FIXME: This function is called multiple times for the same template
// specialization. We should only instantiate attributes that were added
// since the previous instantiation.
for (const auto *TmplAttr : Tmpl->attrs()) {
if (!isRelevantAttr(*this, New, TmplAttr))
continue;
// FIXME: If any of the special case versions from InstantiateAttrs become
// applicable to template declaration, we'll need to add them here.
CXXThisScopeRAII ThisScope(
*this, dyn_cast_or_null<CXXRecordDecl>(ND->getDeclContext()),
Qualifiers(), ND->isCXXInstanceMember());
Attr *NewAttr = sema::instantiateTemplateAttributeForDecl(
TmplAttr, Context, *this, TemplateArgs);
if (NewAttr && isRelevantAttr(*this, New, NewAttr))
New->addAttr(NewAttr);
}
}
}
static Sema::RetainOwnershipKind
attrToRetainOwnershipKind(const Attr *A) {
switch (A->getKind()) {
case clang::attr::CFConsumed:
return Sema::RetainOwnershipKind::CF;
case clang::attr::OSConsumed:
return Sema::RetainOwnershipKind::OS;
case clang::attr::NSConsumed:
return Sema::RetainOwnershipKind::NS;
default:
llvm_unreachable("Wrong argument supplied");
}
}
// Implementation is down with the rest of the OpenACC Decl instantiations.
static void instantiateDependentOpenACCRoutineDeclAttr(
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
const OpenACCRoutineDeclAttr *OldAttr, const Decl *Old, Decl *New);
void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
const Decl *Tmpl, Decl *New,
LateInstantiatedAttrVec *LateAttrs,
LocalInstantiationScope *OuterMostScope) {
for (const auto *TmplAttr : Tmpl->attrs()) {
if (!isRelevantAttr(*this, New, TmplAttr))
continue;
// FIXME: This should be generalized to more than just the AlignedAttr.
const AlignedAttr *Aligned = dyn_cast<AlignedAttr>(TmplAttr);
if (Aligned && Aligned->isAlignmentDependent()) {
instantiateDependentAlignedAttr(*this, TemplateArgs, Aligned, New);
continue;
}
if (const auto *AssumeAligned = dyn_cast<AssumeAlignedAttr>(TmplAttr)) {
instantiateDependentAssumeAlignedAttr(*this, TemplateArgs, AssumeAligned, New);
continue;
}
if (const auto *AlignValue = dyn_cast<AlignValueAttr>(TmplAttr)) {
instantiateDependentAlignValueAttr(*this, TemplateArgs, AlignValue, New);
continue;
}
if (const auto *AllocAlign = dyn_cast<AllocAlignAttr>(TmplAttr)) {
instantiateDependentAllocAlignAttr(*this, TemplateArgs, AllocAlign, New);
continue;
}
if (const auto *Annotate = dyn_cast<AnnotateAttr>(TmplAttr)) {
instantiateDependentAnnotationAttr(*this, TemplateArgs, Annotate, New);
continue;
}
if (const auto *EnableIf = dyn_cast<EnableIfAttr>(TmplAttr)) {
instantiateDependentEnableIfAttr(*this, TemplateArgs, EnableIf, Tmpl,
cast<FunctionDecl>(New));
continue;
}
if (const auto *DiagnoseIf = dyn_cast<DiagnoseIfAttr>(TmplAttr)) {
instantiateDependentDiagnoseIfAttr(*this, TemplateArgs, DiagnoseIf, Tmpl,
cast<FunctionDecl>(New));
continue;
}
if (const auto *CUDALaunchBounds =
dyn_cast<CUDALaunchBoundsAttr>(TmplAttr)) {
instantiateDependentCUDALaunchBoundsAttr(*this, TemplateArgs,
*CUDALaunchBounds, New);
continue;
}
if (const auto *Mode = dyn_cast<ModeAttr>(TmplAttr)) {
instantiateDependentModeAttr(*this, TemplateArgs, *Mode, New);
continue;
}
if (const auto *OMPAttr = dyn_cast<OMPDeclareSimdDeclAttr>(TmplAttr)) {
instantiateOMPDeclareSimdDeclAttr(*this, TemplateArgs, *OMPAttr, New);
continue;
}
if (const auto *OMPAttr = dyn_cast<OMPDeclareVariantAttr>(TmplAttr)) {
instantiateOMPDeclareVariantAttr(*this, TemplateArgs, *OMPAttr, New);
continue;
}
if (const auto *ReqdWorkGroupSize =
dyn_cast<ReqdWorkGroupSizeAttr>(TmplAttr)) {
instantiateDependentReqdWorkGroupSizeAttr(*this, TemplateArgs,
*ReqdWorkGroupSize, New);
}
if (const auto *AMDGPUFlatWorkGroupSize =
dyn_cast<AMDGPUFlatWorkGroupSizeAttr>(TmplAttr)) {
instantiateDependentAMDGPUFlatWorkGroupSizeAttr(
*this, TemplateArgs, *AMDGPUFlatWorkGroupSize, New);
}
if (const auto *AMDGPUFlatWorkGroupSize =
dyn_cast<AMDGPUWavesPerEUAttr>(TmplAttr)) {
instantiateDependentAMDGPUWavesPerEUAttr(*this, TemplateArgs,
*AMDGPUFlatWorkGroupSize, New);
}
if (const auto *AMDGPUMaxNumWorkGroups =
dyn_cast<AMDGPUMaxNumWorkGroupsAttr>(TmplAttr)) {
instantiateDependentAMDGPUMaxNumWorkGroupsAttr(
*this, TemplateArgs, *AMDGPUMaxNumWorkGroups, New);
}
if (const auto *ParamAttr = dyn_cast<HLSLParamModifierAttr>(TmplAttr)) {
instantiateDependentHLSLParamModifierAttr(*this, TemplateArgs, ParamAttr,
New);
continue;
}
if (const auto *RoutineAttr = dyn_cast<OpenACCRoutineDeclAttr>(TmplAttr)) {
instantiateDependentOpenACCRoutineDeclAttr(*this, TemplateArgs,
RoutineAttr, Tmpl, New);
continue;
}
// Existing DLL attribute on the instantiation takes precedence.
if (TmplAttr->getKind() == attr::DLLExport ||
TmplAttr->getKind() == attr::DLLImport) {
if (New->hasAttr<DLLExportAttr>() || New->hasAttr<DLLImportAttr>()) {
continue;
}
}
if (const auto *ABIAttr = dyn_cast<ParameterABIAttr>(TmplAttr)) {
Swift().AddParameterABIAttr(New, *ABIAttr, ABIAttr->getABI());
continue;
}
if (isa<NSConsumedAttr>(TmplAttr) || isa<OSConsumedAttr>(TmplAttr) ||
isa<CFConsumedAttr>(TmplAttr)) {
ObjC().AddXConsumedAttr(New, *TmplAttr,
attrToRetainOwnershipKind(TmplAttr),
/*template instantiation=*/true);
continue;
}
if (auto *A = dyn_cast<PointerAttr>(TmplAttr)) {
if (!New->hasAttr<PointerAttr>())
New->addAttr(A->clone(Context));
continue;
}
if (auto *A = dyn_cast<OwnerAttr>(TmplAttr)) {
if (!New->hasAttr<OwnerAttr>())
New->addAttr(A->clone(Context));
continue;
}
if (auto *A = dyn_cast<SYCLKernelAttr>(TmplAttr)) {
instantiateDependentSYCLKernelAttr(*this, TemplateArgs, *A, New);
continue;
}
if (auto *A = dyn_cast<CUDAGridConstantAttr>(TmplAttr)) {
if (!New->hasAttr<CUDAGridConstantAttr>())
New->addAttr(A->clone(Context));
continue;
}
assert(!TmplAttr->isPackExpansion());
if (TmplAttr->isLateParsed() && LateAttrs) {
// Late parsed attributes must be instantiated and attached after the
// enclosing class has been instantiated. See Sema::InstantiateClass.
LocalInstantiationScope *Saved = nullptr;
if (CurrentInstantiationScope)
Saved = CurrentInstantiationScope->cloneScopes(OuterMostScope);
LateAttrs->push_back(LateInstantiatedAttribute(TmplAttr, Saved, New));
} else {
// Allow 'this' within late-parsed attributes.
auto *ND = cast<NamedDecl>(New);
auto *ThisContext = dyn_cast_or_null<CXXRecordDecl>(ND->getDeclContext());
CXXThisScopeRAII ThisScope(*this, ThisContext, Qualifiers(),
ND->isCXXInstanceMember());
Attr *NewAttr = sema::instantiateTemplateAttribute(TmplAttr, Context,
*this, TemplateArgs);
if (NewAttr && isRelevantAttr(*this, New, TmplAttr))
New->addAttr(NewAttr);
}
}
}
void Sema::updateAttrsForLateParsedTemplate(const Decl *Pattern, Decl *Inst) {
for (const auto *Attr : Pattern->attrs()) {
if (auto *A = dyn_cast<StrictFPAttr>(Attr)) {
if (!Inst->hasAttr<StrictFPAttr>())
Inst->addAttr(A->clone(getASTContext()));
continue;
}
}
}
void Sema::InstantiateDefaultCtorDefaultArgs(CXXConstructorDecl *Ctor) {
assert(Context.getTargetInfo().getCXXABI().isMicrosoft() &&
Ctor->isDefaultConstructor());
unsigned NumParams = Ctor->getNumParams();
if (NumParams == 0)
return;
DLLExportAttr *Attr = Ctor->getAttr<DLLExportAttr>();
if (!Attr)
return;
for (unsigned I = 0; I != NumParams; ++I) {
(void)CheckCXXDefaultArgExpr(Attr->getLocation(), Ctor,
Ctor->getParamDecl(I));
CleanupVarDeclMarking();
}
}
/// Get the previous declaration of a declaration for the purposes of template
/// instantiation. If this finds a previous declaration, then the previous
/// declaration of the instantiation of D should be an instantiation of the
/// result of this function.
template<typename DeclT>
static DeclT *getPreviousDeclForInstantiation(DeclT *D) {
DeclT *Result = D->getPreviousDecl();
// If the declaration is within a class, and the previous declaration was
// merged from a different definition of that class, then we don't have a
// previous declaration for the purpose of template instantiation.
if (Result && isa<CXXRecordDecl>(D->getDeclContext()) &&
D->getLexicalDeclContext() != Result->getLexicalDeclContext())
return nullptr;
return Result;
}
Decl *
TemplateDeclInstantiator::VisitTranslationUnitDecl(TranslationUnitDecl *D) {
llvm_unreachable("Translation units cannot be instantiated");
}
Decl *TemplateDeclInstantiator::VisitHLSLBufferDecl(HLSLBufferDecl *Decl) {
llvm_unreachable("HLSL buffer declarations cannot be instantiated");
}
Decl *
TemplateDeclInstantiator::VisitPragmaCommentDecl(PragmaCommentDecl *D) {
llvm_unreachable("pragma comment cannot be instantiated");
}
Decl *TemplateDeclInstantiator::VisitPragmaDetectMismatchDecl(
PragmaDetectMismatchDecl *D) {
llvm_unreachable("pragma comment cannot be instantiated");
}
Decl *
TemplateDeclInstantiator::VisitExternCContextDecl(ExternCContextDecl *D) {
llvm_unreachable("extern \"C\" context cannot be instantiated");
}
Decl *TemplateDeclInstantiator::VisitMSGuidDecl(MSGuidDecl *D) {
llvm_unreachable("GUID declaration cannot be instantiated");
}
Decl *TemplateDeclInstantiator::VisitUnnamedGlobalConstantDecl(
UnnamedGlobalConstantDecl *D) {
llvm_unreachable("UnnamedGlobalConstantDecl cannot be instantiated");
}
Decl *TemplateDeclInstantiator::VisitTemplateParamObjectDecl(
TemplateParamObjectDecl *D) {
llvm_unreachable("template parameter objects cannot be instantiated");
}
Decl *
TemplateDeclInstantiator::VisitLabelDecl(LabelDecl *D) {
LabelDecl *Inst = LabelDecl::Create(SemaRef.Context, Owner, D->getLocation(),
D->getIdentifier());
SemaRef.InstantiateAttrs(TemplateArgs, D, Inst, LateAttrs, StartingScope);
Owner->addDecl(Inst);
return Inst;
}
Decl *
TemplateDeclInstantiator::VisitNamespaceDecl(NamespaceDecl *D) {
llvm_unreachable("Namespaces cannot be instantiated");
}
namespace {
class OpenACCDeclClauseInstantiator final
: public OpenACCClauseVisitor<OpenACCDeclClauseInstantiator> {
Sema &SemaRef;
const MultiLevelTemplateArgumentList &MLTAL;
ArrayRef<OpenACCClause *> ExistingClauses;
SemaOpenACC::OpenACCParsedClause &ParsedClause;
OpenACCClause *NewClause = nullptr;
public:
OpenACCDeclClauseInstantiator(Sema &S,
const MultiLevelTemplateArgumentList &MLTAL,
ArrayRef<OpenACCClause *> ExistingClauses,
SemaOpenACC::OpenACCParsedClause &ParsedClause)
: SemaRef(S), MLTAL(MLTAL), ExistingClauses(ExistingClauses),
ParsedClause(ParsedClause) {}
OpenACCClause *CreatedClause() { return NewClause; }
#define VISIT_CLAUSE(CLAUSE_NAME) \
void Visit##CLAUSE_NAME##Clause(const OpenACC##CLAUSE_NAME##Clause &Clause);
#include "clang/Basic/OpenACCClauses.def"
llvm::SmallVector<Expr *> VisitVarList(ArrayRef<Expr *> VarList) {
llvm::SmallVector<Expr *> InstantiatedVarList;
for (Expr *CurVar : VarList) {
ExprResult Res = SemaRef.SubstExpr(CurVar, MLTAL);
if (!Res.isUsable())
continue;
Res = SemaRef.OpenACC().ActOnVar(ParsedClause.getDirectiveKind(),
ParsedClause.getClauseKind(), Res.get());
if (Res.isUsable())
InstantiatedVarList.push_back(Res.get());
}
return InstantiatedVarList;
}
};
#define CLAUSE_NOT_ON_DECLS(CLAUSE_NAME) \
void OpenACCDeclClauseInstantiator::Visit##CLAUSE_NAME##Clause( \
const OpenACC##CLAUSE_NAME##Clause &) { \
llvm_unreachable("Clause type invalid on declaration construct, or " \
"instantiation not implemented"); \
}
CLAUSE_NOT_ON_DECLS(Auto)
CLAUSE_NOT_ON_DECLS(Async)
CLAUSE_NOT_ON_DECLS(Attach)
CLAUSE_NOT_ON_DECLS(Collapse)
CLAUSE_NOT_ON_DECLS(Default)
CLAUSE_NOT_ON_DECLS(DefaultAsync)
CLAUSE_NOT_ON_DECLS(Delete)
CLAUSE_NOT_ON_DECLS(Detach)
CLAUSE_NOT_ON_DECLS(Device)
CLAUSE_NOT_ON_DECLS(DeviceNum)
CLAUSE_NOT_ON_DECLS(Finalize)
CLAUSE_NOT_ON_DECLS(FirstPrivate)
CLAUSE_NOT_ON_DECLS(Host)
CLAUSE_NOT_ON_DECLS(If)
CLAUSE_NOT_ON_DECLS(IfPresent)
CLAUSE_NOT_ON_DECLS(Independent)
CLAUSE_NOT_ON_DECLS(NoCreate)
CLAUSE_NOT_ON_DECLS(NumGangs)
CLAUSE_NOT_ON_DECLS(NumWorkers)
CLAUSE_NOT_ON_DECLS(Private)
CLAUSE_NOT_ON_DECLS(Reduction)
CLAUSE_NOT_ON_DECLS(Self)
CLAUSE_NOT_ON_DECLS(Tile)
CLAUSE_NOT_ON_DECLS(UseDevice)
CLAUSE_NOT_ON_DECLS(VectorLength)
CLAUSE_NOT_ON_DECLS(Wait)
#undef CLAUSE_NOT_ON_DECLS
void OpenACCDeclClauseInstantiator::VisitGangClause(
const OpenACCGangClause &C) {
llvm::SmallVector<OpenACCGangKind> TransformedGangKinds;
llvm::SmallVector<Expr *> TransformedIntExprs;
assert(C.getNumExprs() <= 1 &&
"Only 1 expression allowed on gang clause in routine");
if (C.getNumExprs() > 0) {
assert(C.getExpr(0).first == OpenACCGangKind::Dim &&
"Only dim allowed on routine");
ExprResult ER =
SemaRef.SubstExpr(const_cast<Expr *>(C.getExpr(0).second), MLTAL);
if (ER.isUsable()) {
ER = SemaRef.OpenACC().CheckGangExpr(ExistingClauses,
ParsedClause.getDirectiveKind(),
C.getExpr(0).first, ER.get());
if (ER.isUsable()) {
TransformedGangKinds.push_back(OpenACCGangKind::Dim);
TransformedIntExprs.push_back(ER.get());
}
}
}
NewClause = SemaRef.OpenACC().CheckGangClause(
ParsedClause.getDirectiveKind(), ExistingClauses,
ParsedClause.getBeginLoc(), ParsedClause.getLParenLoc(),
TransformedGangKinds, TransformedIntExprs, ParsedClause.getEndLoc());
}
void OpenACCDeclClauseInstantiator::VisitSeqClause(const OpenACCSeqClause &C) {
NewClause = OpenACCSeqClause::Create(SemaRef.getASTContext(),
ParsedClause.getBeginLoc(),
ParsedClause.getEndLoc());
}
void OpenACCDeclClauseInstantiator::VisitNoHostClause(
const OpenACCNoHostClause &C) {
NewClause = OpenACCNoHostClause::Create(SemaRef.getASTContext(),
ParsedClause.getBeginLoc(),
ParsedClause.getEndLoc());
}
void OpenACCDeclClauseInstantiator::VisitDeviceTypeClause(
const OpenACCDeviceTypeClause &C) {
// Nothing to transform here, just create a new version of 'C'.
NewClause = OpenACCDeviceTypeClause::Create(
SemaRef.getASTContext(), C.getClauseKind(), ParsedClause.getBeginLoc(),
ParsedClause.getLParenLoc(), C.getArchitectures(),
ParsedClause.getEndLoc());
}
void OpenACCDeclClauseInstantiator::VisitWorkerClause(
const OpenACCWorkerClause &C) {
assert(!C.hasIntExpr() && "Int Expr not allowed on routine 'worker' clause");
NewClause = OpenACCWorkerClause::Create(SemaRef.getASTContext(),
ParsedClause.getBeginLoc(), {},
nullptr, ParsedClause.getEndLoc());
}
void OpenACCDeclClauseInstantiator::VisitVectorClause(
const OpenACCVectorClause &C) {
assert(!C.hasIntExpr() && "Int Expr not allowed on routine 'vector' clause");
NewClause = OpenACCVectorClause::Create(SemaRef.getASTContext(),
ParsedClause.getBeginLoc(), {},
nullptr, ParsedClause.getEndLoc());
}
void OpenACCDeclClauseInstantiator::VisitCopyClause(
const OpenACCCopyClause &C) {
ParsedClause.setVarListDetails(VisitVarList(C.getVarList()),
C.getModifierList());
if (SemaRef.OpenACC().CheckDeclareClause(ParsedClause, C.getModifierList()))
return;
NewClause = OpenACCCopyClause::Create(
SemaRef.getASTContext(), ParsedClause.getClauseKind(),
ParsedClause.getBeginLoc(), ParsedClause.getLParenLoc(),
ParsedClause.getModifierList(), ParsedClause.getVarList(),
ParsedClause.getEndLoc());
}
void OpenACCDeclClauseInstantiator::VisitLinkClause(
const OpenACCLinkClause &C) {
ParsedClause.setVarListDetails(
SemaRef.OpenACC().CheckLinkClauseVarList(VisitVarList(C.getVarList())),
OpenACCModifierKind::Invalid);
if (SemaRef.OpenACC().CheckDeclareClause(ParsedClause,
OpenACCModifierKind::Invalid))
return;
NewClause = OpenACCLinkClause::Create(
SemaRef.getASTContext(), ParsedClause.getBeginLoc(),
ParsedClause.getLParenLoc(), ParsedClause.getVarList(),
ParsedClause.getEndLoc());
}
void OpenACCDeclClauseInstantiator::VisitDeviceResidentClause(
const OpenACCDeviceResidentClause &C) {
ParsedClause.setVarListDetails(VisitVarList(C.getVarList()),
OpenACCModifierKind::Invalid);
if (SemaRef.OpenACC().CheckDeclareClause(ParsedClause,
OpenACCModifierKind::Invalid))
return;
NewClause = OpenACCDeviceResidentClause::Create(
SemaRef.getASTContext(), ParsedClause.getBeginLoc(),
ParsedClause.getLParenLoc(), ParsedClause.getVarList(),
ParsedClause.getEndLoc());
}
void OpenACCDeclClauseInstantiator::VisitCopyInClause(
const OpenACCCopyInClause &C) {
ParsedClause.setVarListDetails(VisitVarList(C.getVarList()),
C.getModifierList());
if (SemaRef.OpenACC().CheckDeclareClause(ParsedClause, C.getModifierList()))
return;
NewClause = OpenACCCopyInClause::Create(
SemaRef.getASTContext(), ParsedClause.getClauseKind(),
ParsedClause.getBeginLoc(), ParsedClause.getLParenLoc(),
ParsedClause.getModifierList(), ParsedClause.getVarList(),
ParsedClause.getEndLoc());
}
void OpenACCDeclClauseInstantiator::VisitCopyOutClause(
const OpenACCCopyOutClause &C) {
ParsedClause.setVarListDetails(VisitVarList(C.getVarList()),
C.getModifierList());
if (SemaRef.OpenACC().CheckDeclareClause(ParsedClause, C.getModifierList()))
return;
NewClause = OpenACCCopyOutClause::Create(
SemaRef.getASTContext(), ParsedClause.getClauseKind(),
ParsedClause.getBeginLoc(), ParsedClause.getLParenLoc(),
ParsedClause.getModifierList(), ParsedClause.getVarList(),
ParsedClause.getEndLoc());
}
void OpenACCDeclClauseInstantiator::VisitCreateClause(
const OpenACCCreateClause &C) {
ParsedClause.setVarListDetails(VisitVarList(C.getVarList()),
C.getModifierList());
if (SemaRef.OpenACC().CheckDeclareClause(ParsedClause, C.getModifierList()))
return;
NewClause = OpenACCCreateClause::Create(
SemaRef.getASTContext(), ParsedClause.getClauseKind(),
ParsedClause.getBeginLoc(), ParsedClause.getLParenLoc(),
ParsedClause.getModifierList(), ParsedClause.getVarList(),
ParsedClause.getEndLoc());
}
void OpenACCDeclClauseInstantiator::VisitPresentClause(
const OpenACCPresentClause &C) {
ParsedClause.setVarListDetails(VisitVarList(C.getVarList()),
OpenACCModifierKind::Invalid);
if (SemaRef.OpenACC().CheckDeclareClause(ParsedClause,
OpenACCModifierKind::Invalid))
return;
NewClause = OpenACCPresentClause::Create(
SemaRef.getASTContext(), ParsedClause.getBeginLoc(),
ParsedClause.getLParenLoc(), ParsedClause.getVarList(),
ParsedClause.getEndLoc());
}
void OpenACCDeclClauseInstantiator::VisitDevicePtrClause(
const OpenACCDevicePtrClause &C) {
llvm::SmallVector<Expr *> VarList = VisitVarList(C.getVarList());
// Ensure each var is a pointer type.
VarList.erase(std::remove_if(VarList.begin(), VarList.end(),
[&](Expr *E) {
return SemaRef.OpenACC().CheckVarIsPointerType(
OpenACCClauseKind::DevicePtr, E);
}),
VarList.end());
ParsedClause.setVarListDetails(VarList, OpenACCModifierKind::Invalid);
if (SemaRef.OpenACC().CheckDeclareClause(ParsedClause,
OpenACCModifierKind::Invalid))
return;
NewClause = OpenACCDevicePtrClause::Create(
SemaRef.getASTContext(), ParsedClause.getBeginLoc(),
ParsedClause.getLParenLoc(), ParsedClause.getVarList(),
ParsedClause.getEndLoc());
}
void OpenACCDeclClauseInstantiator::VisitBindClause(
const OpenACCBindClause &C) {
// Nothing to instantiate, we support only string literal or identifier.
if (C.isStringArgument())
NewClause = OpenACCBindClause::Create(
SemaRef.getASTContext(), ParsedClause.getBeginLoc(),
ParsedClause.getLParenLoc(), C.getStringArgument(),
ParsedClause.getEndLoc());
else
NewClause = OpenACCBindClause::Create(
SemaRef.getASTContext(), ParsedClause.getBeginLoc(),
ParsedClause.getLParenLoc(), C.getIdentifierArgument(),
ParsedClause.getEndLoc());
}
llvm::SmallVector<OpenACCClause *> InstantiateOpenACCClauseList(
Sema &S, const MultiLevelTemplateArgumentList &MLTAL,
OpenACCDirectiveKind DK, ArrayRef<const OpenACCClause *> ClauseList) {
llvm::SmallVector<OpenACCClause *> TransformedClauses;
for (const auto *Clause : ClauseList) {
SemaOpenACC::OpenACCParsedClause ParsedClause(DK, Clause->getClauseKind(),
Clause->getBeginLoc());
ParsedClause.setEndLoc(Clause->getEndLoc());
if (const auto *WithParms = dyn_cast<OpenACCClauseWithParams>(Clause))
ParsedClause.setLParenLoc(WithParms->getLParenLoc());
OpenACCDeclClauseInstantiator Instantiator{S, MLTAL, TransformedClauses,
ParsedClause};
Instantiator.Visit(Clause);
if (Instantiator.CreatedClause())
TransformedClauses.push_back(Instantiator.CreatedClause());
}
return TransformedClauses;
}
} // namespace
static void instantiateDependentOpenACCRoutineDeclAttr(
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
const OpenACCRoutineDeclAttr *OldAttr, const Decl *OldDecl, Decl *NewDecl) {
OpenACCRoutineDeclAttr *A =
OpenACCRoutineDeclAttr::Create(S.getASTContext(), OldAttr->getLocation());
if (!OldAttr->Clauses.empty()) {
llvm::SmallVector<OpenACCClause *> TransformedClauses =
InstantiateOpenACCClauseList(
S, TemplateArgs, OpenACCDirectiveKind::Routine, OldAttr->Clauses);
A->Clauses.assign(TransformedClauses.begin(), TransformedClauses.end());
}
// We don't end up having to do any magic-static or bind checking here, since
// the first phase should have caught this, since we always apply to the
// functiondecl.
NewDecl->addAttr(A);
}
Decl *TemplateDeclInstantiator::VisitOpenACCDeclareDecl(OpenACCDeclareDecl *D) {
SemaRef.OpenACC().ActOnConstruct(D->getDirectiveKind(), D->getBeginLoc());
llvm::SmallVector<OpenACCClause *> TransformedClauses =
InstantiateOpenACCClauseList(SemaRef, TemplateArgs, D->getDirectiveKind(),
D->clauses());
if (SemaRef.OpenACC().ActOnStartDeclDirective(
D->getDirectiveKind(), D->getBeginLoc(), TransformedClauses))
return nullptr;
DeclGroupRef Res = SemaRef.OpenACC().ActOnEndDeclDirective(
D->getDirectiveKind(), D->getBeginLoc(), D->getDirectiveLoc(), {}, {},
D->getEndLoc(), TransformedClauses);
if (Res.isNull())
return nullptr;
return Res.getSingleDecl();
}
Decl *TemplateDeclInstantiator::VisitOpenACCRoutineDecl(OpenACCRoutineDecl *D) {
SemaRef.OpenACC().ActOnConstruct(D->getDirectiveKind(), D->getBeginLoc());
llvm::SmallVector<OpenACCClause *> TransformedClauses =
InstantiateOpenACCClauseList(SemaRef, TemplateArgs, D->getDirectiveKind(),
D->clauses());
ExprResult FuncRef;
if (D->getFunctionReference()) {
FuncRef = SemaRef.SubstCXXIdExpr(D->getFunctionReference(), TemplateArgs);
if (FuncRef.isUsable())
FuncRef = SemaRef.OpenACC().ActOnRoutineName(FuncRef.get());
// We don't return early here, we leave the construct in the AST, even if
// the function decl is empty.
}
if (SemaRef.OpenACC().ActOnStartDeclDirective(
D->getDirectiveKind(), D->getBeginLoc(), TransformedClauses))
return nullptr;
DeclGroupRef Res = SemaRef.OpenACC().ActOnEndRoutineDeclDirective(
D->getBeginLoc(), D->getDirectiveLoc(), D->getLParenLoc(), FuncRef.get(),
D->getRParenLoc(), TransformedClauses, D->getEndLoc(), nullptr);
if (Res.isNull())
return nullptr;
return Res.getSingleDecl();
}
Decl *
TemplateDeclInstantiator::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
NamespaceAliasDecl *Inst
= NamespaceAliasDecl::Create(SemaRef.Context, Owner,
D->getNamespaceLoc(),
D->getAliasLoc(),
D->getIdentifier(),
D->getQualifierLoc(),
D->getTargetNameLoc(),
D->getNamespace());
Owner->addDecl(Inst);
return Inst;
}
Decl *TemplateDeclInstantiator::InstantiateTypedefNameDecl(TypedefNameDecl *D,
bool IsTypeAlias) {
bool Invalid = false;
TypeSourceInfo *DI = D->getTypeSourceInfo();
if (DI->getType()->isInstantiationDependentType() ||
DI->getType()->isVariablyModifiedType()) {
DI = SemaRef.SubstType(DI, TemplateArgs,
D->getLocation(), D->getDeclName());
if (!DI) {
Invalid = true;
DI = SemaRef.Context.getTrivialTypeSourceInfo(SemaRef.Context.IntTy);
}
} else {
SemaRef.MarkDeclarationsReferencedInType(D->getLocation(), DI->getType());
}
// HACK: 2012-10-23 g++ has a bug where it gets the value kind of ?: wrong.
// libstdc++ relies upon this bug in its implementation of common_type. If we
// happen to be processing that implementation, fake up the g++ ?:
// semantics. See LWG issue 2141 for more information on the bug. The bugs
// are fixed in g++ and libstdc++ 4.9.0 (2014-04-22).
const DecltypeType *DT = DI->getType()->getAs<DecltypeType>();
CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D->getDeclContext());
if (DT && RD && isa<ConditionalOperator>(DT->getUnderlyingExpr()) &&
DT->isReferenceType() &&
RD->getEnclosingNamespaceContext() == SemaRef.getStdNamespace() &&
RD->getIdentifier() && RD->getIdentifier()->isStr("common_type") &&
D->getIdentifier() && D->getIdentifier()->isStr("type") &&
SemaRef.getSourceManager().isInSystemHeader(D->getBeginLoc()))
// Fold it to the (non-reference) type which g++ would have produced.
DI = SemaRef.Context.getTrivialTypeSourceInfo(
DI->getType().getNonReferenceType());
// Create the new typedef
TypedefNameDecl *Typedef;
if (IsTypeAlias)
Typedef = TypeAliasDecl::Create(SemaRef.Context, Owner, D->getBeginLoc(),
D->getLocation(), D->getIdentifier(), DI);
else
Typedef = TypedefDecl::Create(SemaRef.Context, Owner, D->getBeginLoc(),
D->getLocation(), D->getIdentifier(), DI);
if (Invalid)
Typedef->setInvalidDecl();
// If the old typedef was the name for linkage purposes of an anonymous
// tag decl, re-establish that relationship for the new typedef.
if (const TagType *oldTagType = D->getUnderlyingType()->getAs<TagType>()) {
TagDecl *oldTag = oldTagType->getDecl();
if (oldTag->getTypedefNameForAnonDecl() == D && !Invalid) {
TagDecl *newTag = DI->getType()->castAs<TagType>()->getDecl();
assert(!newTag->hasNameForLinkage());
newTag->setTypedefNameForAnonDecl(Typedef);
}
}
if (TypedefNameDecl *Prev = getPreviousDeclForInstantiation(D)) {
NamedDecl *InstPrev = SemaRef.FindInstantiatedDecl(D->getLocation(), Prev,
TemplateArgs);
if (!InstPrev)
return nullptr;
TypedefNameDecl *InstPrevTypedef = cast<TypedefNameDecl>(InstPrev);
// If the typedef types are not identical, reject them.
SemaRef.isIncompatibleTypedef(InstPrevTypedef, Typedef);
Typedef->setPreviousDecl(InstPrevTypedef);
}
SemaRef.InstantiateAttrs(TemplateArgs, D, Typedef);
if (D->getUnderlyingType()->getAs<DependentNameType>())
SemaRef.inferGslPointerAttribute(Typedef);
Typedef->setAccess(D->getAccess());
Typedef->setReferenced(D->isReferenced());
return Typedef;
}
Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) {
Decl *Typedef = InstantiateTypedefNameDecl(D, /*IsTypeAlias=*/false);
if (Typedef)
Owner->addDecl(Typedef);
return Typedef;
}
Decl *TemplateDeclInstantiator::VisitTypeAliasDecl(TypeAliasDecl *D) {
Decl *Typedef = InstantiateTypedefNameDecl(D, /*IsTypeAlias=*/true);
if (Typedef)
Owner->addDecl(Typedef);
return Typedef;
}
Decl *TemplateDeclInstantiator::InstantiateTypeAliasTemplateDecl(
TypeAliasTemplateDecl *D) {
// Create a local instantiation scope for this type alias template, which
// will contain the instantiations of the template parameters.
LocalInstantiationScope Scope(SemaRef);
TemplateParameterList *TempParams = D->getTemplateParameters();
TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
if (!InstParams)
return nullptr;
TypeAliasDecl *Pattern = D->getTemplatedDecl();
Sema::InstantiatingTemplate InstTemplate(
SemaRef, D->getBeginLoc(), D,
D->getTemplateDepth() >= TemplateArgs.getNumLevels()
? ArrayRef<TemplateArgument>()
: (TemplateArgs.begin() + TemplateArgs.getNumLevels() - 1 -
D->getTemplateDepth())
->Args);
if (InstTemplate.isInvalid())
return nullptr;
TypeAliasTemplateDecl *PrevAliasTemplate = nullptr;
if (getPreviousDeclForInstantiation<TypedefNameDecl>(Pattern)) {
DeclContext::lookup_result Found = Owner->lookup(Pattern->getDeclName());
if (!Found.empty()) {
PrevAliasTemplate = dyn_cast<TypeAliasTemplateDecl>(Found.front());
}
}
TypeAliasDecl *AliasInst = cast_or_null<TypeAliasDecl>(
InstantiateTypedefNameDecl(Pattern, /*IsTypeAlias=*/true));
if (!AliasInst)
return nullptr;
TypeAliasTemplateDecl *Inst
= TypeAliasTemplateDecl::Create(SemaRef.Context, Owner, D->getLocation(),
D->getDeclName(), InstParams, AliasInst);
AliasInst->setDescribedAliasTemplate(Inst);
if (PrevAliasTemplate)
Inst->setPreviousDecl(PrevAliasTemplate);
Inst->setAccess(D->getAccess());
if (!PrevAliasTemplate)
Inst->setInstantiatedFromMemberTemplate(D);
return Inst;
}
Decl *
TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
Decl *Inst = InstantiateTypeAliasTemplateDecl(D);
if (Inst)
Owner->addDecl(Inst);
return Inst;
}
Decl *TemplateDeclInstantiator::VisitBindingDecl(BindingDecl *D) {
auto *NewBD = BindingDecl::Create(SemaRef.Context, Owner, D->getLocation(),
D->getIdentifier(), D->getType());
NewBD->setReferenced(D->isReferenced());
SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, NewBD);
return NewBD;
}
Decl *TemplateDeclInstantiator::VisitDecompositionDecl(DecompositionDecl *D) {
// Transform the bindings first.
// The transformed DD will have all of the concrete BindingDecls.
SmallVector<BindingDecl*, 16> NewBindings;
BindingDecl *OldBindingPack = nullptr;
for (auto *OldBD : D->bindings()) {
Expr *BindingExpr = OldBD->getBinding();
if (isa_and_present<FunctionParmPackExpr>(BindingExpr)) {
// We have a resolved pack.
assert(!OldBindingPack && "no more than one pack is allowed");
OldBindingPack = OldBD;
}
NewBindings.push_back(cast<BindingDecl>(VisitBindingDecl(OldBD)));
}
ArrayRef<BindingDecl*> NewBindingArray = NewBindings;
auto *NewDD = cast_if_present<DecompositionDecl>(
VisitVarDecl(D, /*InstantiatingVarTemplate=*/false, &NewBindingArray));
if (!NewDD || NewDD->isInvalidDecl()) {
for (auto *NewBD : NewBindings)
NewBD->setInvalidDecl();
} else if (OldBindingPack) {
// Mark the bindings in the pack as instantiated.
auto Bindings = NewDD->bindings();
BindingDecl *NewBindingPack = *llvm::find_if(
Bindings, [](BindingDecl *D) -> bool { return D->isParameterPack(); });
assert(NewBindingPack != nullptr && "new bindings should also have a pack");
llvm::ArrayRef<BindingDecl *> OldDecls =
OldBindingPack->getBindingPackDecls();
llvm::ArrayRef<BindingDecl *> NewDecls =
NewBindingPack->getBindingPackDecls();
assert(OldDecls.size() == NewDecls.size());
for (unsigned I = 0; I < OldDecls.size(); I++)
SemaRef.CurrentInstantiationScope->InstantiatedLocal(OldDecls[I],
NewDecls[I]);
}
return NewDD;
}
Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
return VisitVarDecl(D, /*InstantiatingVarTemplate=*/false);
}
Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D,
bool InstantiatingVarTemplate,
ArrayRef<BindingDecl*> *Bindings) {
// Do substitution on the type of the declaration
TypeSourceInfo *DI = SemaRef.SubstType(
D->getTypeSourceInfo(), TemplateArgs, D->getTypeSpecStartLoc(),
D->getDeclName(), /*AllowDeducedTST*/true);
if (!DI)
return nullptr;
if (DI->getType()->isFunctionType()) {
SemaRef.Diag(D->getLocation(), diag::err_variable_instantiates_to_function)
<< D->isStaticDataMember() << DI->getType();
return nullptr;
}
DeclContext *DC = Owner;
if (D->isLocalExternDecl())
SemaRef.adjustContextForLocalExternDecl(DC);
// Build the instantiated declaration.
VarDecl *Var;
if (Bindings)
Var = DecompositionDecl::Create(SemaRef.Context, DC, D->getInnerLocStart(),
D->getLocation(), DI->getType(), DI,
D->getStorageClass(), *Bindings);
else
Var = VarDecl::Create(SemaRef.Context, DC, D->getInnerLocStart(),
D->getLocation(), D->getIdentifier(), DI->getType(),
DI, D->getStorageClass());
// In ARC, infer 'retaining' for variables of retainable type.
if (SemaRef.getLangOpts().ObjCAutoRefCount &&
SemaRef.ObjC().inferObjCARCLifetime(Var))
Var->setInvalidDecl();
if (SemaRef.getLangOpts().OpenCL)
SemaRef.deduceOpenCLAddressSpace(Var);
// Substitute the nested name specifier, if any.
if (SubstQualifier(D, Var))
return nullptr;
SemaRef.BuildVariableInstantiation(Var, D, TemplateArgs, LateAttrs, Owner,
StartingScope, InstantiatingVarTemplate);
if (D->isNRVOVariable() && !Var->isInvalidDecl()) {
QualType RT;
if (auto *F = dyn_cast<FunctionDecl>(DC))
RT = F->getReturnType();
else if (isa<BlockDecl>(DC))
RT = cast<FunctionType>(SemaRef.getCurBlock()->FunctionType)
->getReturnType();
else
llvm_unreachable("Unknown context type");
// This is the last chance we have of checking copy elision eligibility
// for functions in dependent contexts. The sema actions for building
// the return statement during template instantiation will have no effect
// regarding copy elision, since NRVO propagation runs on the scope exit
// actions, and these are not run on instantiation.
// This might run through some VarDecls which were returned from non-taken
// 'if constexpr' branches, and these will end up being constructed on the
// return slot even if they will never be returned, as a sort of accidental
// 'optimization'. Notably, functions with 'auto' return types won't have it
// deduced by this point. Coupled with the limitation described
// previously, this makes it very hard to support copy elision for these.
Sema::NamedReturnInfo Info = SemaRef.getNamedReturnInfo(Var);
bool NRVO = SemaRef.getCopyElisionCandidate(Info, RT) != nullptr;
Var->setNRVOVariable(NRVO);
}
Var->setImplicit(D->isImplicit());
if (Var->isStaticLocal())
SemaRef.CheckStaticLocalForDllExport(Var);
if (Var->getTLSKind())
SemaRef.CheckThreadLocalForLargeAlignment(Var);
if (SemaRef.getLangOpts().OpenACC)
SemaRef.OpenACC().ActOnVariableDeclarator(Var);
return Var;
}
Decl *TemplateDeclInstantiator::VisitAccessSpecDecl(AccessSpecDecl *D) {
AccessSpecDecl* AD
= AccessSpecDecl::Create(SemaRef.Context, D->getAccess(), Owner,
D->getAccessSpecifierLoc(), D->getColonLoc());
Owner->addHiddenDecl(AD);
return AD;
}
Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
bool Invalid = false;
TypeSourceInfo *DI = D->getTypeSourceInfo();
if (DI->getType()->isInstantiationDependentType() ||
DI->getType()->isVariablyModifiedType()) {
DI = SemaRef.SubstType(DI, TemplateArgs,
D->getLocation(), D->getDeclName());
if (!DI) {
DI = D->getTypeSourceInfo();
Invalid = true;
} else if (DI->getType()->isFunctionType()) {
// C++ [temp.arg.type]p3:
// If a declaration acquires a function type through a type
// dependent on a template-parameter and this causes a
// declaration that does not use the syntactic form of a
// function declarator to have function type, the program is
// ill-formed.
SemaRef.Diag(D->getLocation(), diag::err_field_instantiates_to_function)
<< DI->getType();
Invalid = true;
}
} else {
SemaRef.MarkDeclarationsReferencedInType(D->getLocation(), DI->getType());
}
Expr *BitWidth = D->getBitWidth();
if (Invalid)
BitWidth = nullptr;
else if (BitWidth) {
// The bit-width expression is a constant expression.
EnterExpressionEvaluationContext Unevaluated(
SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated);
ExprResult InstantiatedBitWidth
= SemaRef.SubstExpr(BitWidth, TemplateArgs);
if (InstantiatedBitWidth.isInvalid()) {
Invalid = true;
BitWidth = nullptr;
} else
BitWidth = InstantiatedBitWidth.getAs<Expr>();
}
FieldDecl *Field = SemaRef.CheckFieldDecl(D->getDeclName(),
DI->getType(), DI,
cast<RecordDecl>(Owner),
D->getLocation(),
D->isMutable(),
BitWidth,
D->getInClassInitStyle(),
D->getInnerLocStart(),
D->getAccess(),
nullptr);
if (!Field) {
cast<Decl>(Owner)->setInvalidDecl();
return nullptr;
}
SemaRef.InstantiateAttrs(TemplateArgs, D, Field, LateAttrs, StartingScope);
if (Field->hasAttrs())
SemaRef.CheckAlignasUnderalignment(Field);
if (Invalid)
Field->setInvalidDecl();
if (!Field->getDeclName() || Field->isPlaceholderVar(SemaRef.getLangOpts())) {
// Keep track of where this decl came from.
SemaRef.Context.setInstantiatedFromUnnamedFieldDecl(Field, D);
}
if (CXXRecordDecl *Parent= dyn_cast<CXXRecordDecl>(Field->getDeclContext())) {
if (Parent->isAnonymousStructOrUnion() &&
Parent->getRedeclContext()->isFunctionOrMethod())
SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Field);
}
Field->setImplicit(D->isImplicit());
Field->setAccess(D->getAccess());
Owner->addDecl(Field);
return Field;
}
Decl *TemplateDeclInstantiator::VisitMSPropertyDecl(MSPropertyDecl *D) {
bool Invalid = false;
TypeSourceInfo *DI = D->getTypeSourceInfo();
if (DI->getType()->isVariablyModifiedType()) {
SemaRef.Diag(D->getLocation(), diag::err_property_is_variably_modified)
<< D;
Invalid = true;
} else if (DI->getType()->isInstantiationDependentType()) {
DI = SemaRef.SubstType(DI, TemplateArgs,
D->getLocation(), D->getDeclName());
if (!DI) {
DI = D->getTypeSourceInfo();
Invalid = true;
} else if (DI->getType()->isFunctionType()) {
// C++ [temp.arg.type]p3:
// If a declaration acquires a function type through a type
// dependent on a template-parameter and this causes a
// declaration that does not use the syntactic form of a
// function declarator to have function type, the program is
// ill-formed.
SemaRef.Diag(D->getLocation(), diag::err_field_instantiates_to_function)
<< DI->getType();
Invalid = true;
}
} else {
SemaRef.MarkDeclarationsReferencedInType(D->getLocation(), DI->getType());
}
MSPropertyDecl *Property = MSPropertyDecl::Create(
SemaRef.Context, Owner, D->getLocation(), D->getDeclName(), DI->getType(),
DI, D->getBeginLoc(), D->getGetterId(), D->getSetterId());
SemaRef.InstantiateAttrs(TemplateArgs, D, Property, LateAttrs,
StartingScope);
if (Invalid)
Property->setInvalidDecl();
Property->setAccess(D->getAccess());
Owner->addDecl(Property);
return Property;
}
Decl *TemplateDeclInstantiator::VisitIndirectFieldDecl(IndirectFieldDecl *D) {
NamedDecl **NamedChain =
new (SemaRef.Context)NamedDecl*[D->getChainingSize()];
int i = 0;
for (auto *PI : D->chain()) {
NamedDecl *Next = SemaRef.FindInstantiatedDecl(D->getLocation(), PI,
TemplateArgs);
if (!Next)
return nullptr;
NamedChain[i++] = Next;
}
QualType T = cast<FieldDecl>(NamedChain[i-1])->getType();
IndirectFieldDecl *IndirectField = IndirectFieldDecl::Create(
SemaRef.Context, Owner, D->getLocation(), D->getIdentifier(), T,
{NamedChain, D->getChainingSize()});
for (const auto *Attr : D->attrs())
IndirectField->addAttr(Attr->clone(SemaRef.Context));
IndirectField->setImplicit(D->isImplicit());
IndirectField->setAccess(D->getAccess());
Owner->addDecl(IndirectField);
return IndirectField;
}
Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) {
// Handle friend type expressions by simply substituting template
// parameters into the pattern type and checking the result.
if (TypeSourceInfo *Ty = D->getFriendType()) {
TypeSourceInfo *InstTy;
// If this is an unsupported friend, don't bother substituting template
// arguments into it. The actual type referred to won't be used by any
// parts of Clang, and may not be valid for instantiating. Just use the
// same info for the instantiated friend.
if (D->isUnsupportedFriend()) {
InstTy = Ty;
} else {
if (D->isPackExpansion()) {
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
SemaRef.collectUnexpandedParameterPacks(Ty->getTypeLoc(), Unexpanded);
assert(!Unexpanded.empty() && "Pack expansion without packs");
bool ShouldExpand = true;
bool RetainExpansion = false;
UnsignedOrNone NumExpansions = std::nullopt;
if (SemaRef.CheckParameterPacksForExpansion(
D->getEllipsisLoc(), D->getSourceRange(), Unexpanded,
TemplateArgs, ShouldExpand, RetainExpansion, NumExpansions))
return nullptr;
assert(!RetainExpansion &&
"should never retain an expansion for a variadic friend decl");
if (ShouldExpand) {
SmallVector<FriendDecl *> Decls;
for (unsigned I = 0; I != *NumExpansions; I++) {
Sema::ArgPackSubstIndexRAII SubstIndex(SemaRef, I);
TypeSourceInfo *TSI = SemaRef.SubstType(
Ty, TemplateArgs, D->getEllipsisLoc(), DeclarationName());
if (!TSI)
return nullptr;
auto FD =
FriendDecl::Create(SemaRef.Context, Owner, D->getLocation(),
TSI, D->getFriendLoc());
FD->setAccess(AS_public);
Owner->addDecl(FD);
Decls.push_back(FD);
}
// Just drop this node; we have no use for it anymore.
return nullptr;
}
}
InstTy = SemaRef.SubstType(Ty, TemplateArgs, D->getLocation(),
DeclarationName());
}
if (!InstTy)
return nullptr;
FriendDecl *FD = FriendDecl::Create(
SemaRef.Context, Owner, D->getLocation(), InstTy, D->getFriendLoc());
FD->setAccess(AS_public);
FD->setUnsupportedFriend(D->isUnsupportedFriend());
Owner->addDecl(FD);
return FD;
}
NamedDecl *ND = D->getFriendDecl();
assert(ND && "friend decl must be a decl or a type!");
// All of the Visit implementations for the various potential friend
// declarations have to be carefully written to work for friend
// objects, with the most important detail being that the target
// decl should almost certainly not be placed in Owner.
Decl *NewND = Visit(ND);
if (!NewND) return nullptr;
FriendDecl *FD =
FriendDecl::Create(SemaRef.Context, Owner, D->getLocation(),
cast<NamedDecl>(NewND), D->getFriendLoc());
FD->setAccess(AS_public);
FD->setUnsupportedFriend(D->isUnsupportedFriend());
Owner->addDecl(FD);
return FD;
}
Decl *TemplateDeclInstantiator::VisitStaticAssertDecl(StaticAssertDecl *D) {
Expr *AssertExpr = D->getAssertExpr();
// The expression in a static assertion is a constant expression.
EnterExpressionEvaluationContext Unevaluated(
SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated);
ExprResult InstantiatedAssertExpr
= SemaRef.SubstExpr(AssertExpr, TemplateArgs);
if (InstantiatedAssertExpr.isInvalid())
return nullptr;
ExprResult InstantiatedMessageExpr =
SemaRef.SubstExpr(D->getMessage(), TemplateArgs);
if (InstantiatedMessageExpr.isInvalid())
return nullptr;
return SemaRef.BuildStaticAssertDeclaration(
D->getLocation(), InstantiatedAssertExpr.get(),
InstantiatedMessageExpr.get(), D->getRParenLoc(), D->isFailed());
}
Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
EnumDecl *PrevDecl = nullptr;
if (EnumDecl *PatternPrev = getPreviousDeclForInstantiation(D)) {
NamedDecl *Prev = SemaRef.FindInstantiatedDecl(D->getLocation(),
PatternPrev,
TemplateArgs);
if (!Prev) return nullptr;
PrevDecl = cast<EnumDecl>(Prev);
}
EnumDecl *Enum =
EnumDecl::Create(SemaRef.Context, Owner, D->getBeginLoc(),
D->getLocation(), D->getIdentifier(), PrevDecl,
D->isScoped(), D->isScopedUsingClassTag(), D->isFixed());
if (D->isFixed()) {
if (TypeSourceInfo *TI = D->getIntegerTypeSourceInfo()) {
// If we have type source information for the underlying type, it means it
// has been explicitly set by the user. Perform substitution on it before
// moving on.
SourceLocation UnderlyingLoc = TI->getTypeLoc().getBeginLoc();
TypeSourceInfo *NewTI = SemaRef.SubstType(TI, TemplateArgs, UnderlyingLoc,
DeclarationName());
if (!NewTI || SemaRef.CheckEnumUnderlyingType(NewTI))
Enum->setIntegerType(SemaRef.Context.IntTy);
else
Enum->setIntegerTypeSourceInfo(NewTI);
// C++23 [conv.prom]p4
// if integral promotion can be applied to its underlying type, a prvalue
// of an unscoped enumeration type whose underlying type is fixed can also
// be converted to a prvalue of the promoted underlying type.
//
// FIXME: that logic is already implemented in ActOnEnumBody, factor out
// into (Re)BuildEnumBody.
QualType UnderlyingType = Enum->getIntegerType();
Enum->setPromotionType(
SemaRef.Context.isPromotableIntegerType(UnderlyingType)
? SemaRef.Context.getPromotedIntegerType(UnderlyingType)
: UnderlyingType);
} else {
assert(!D->getIntegerType()->isDependentType()
&& "Dependent type without type source info");
Enum->setIntegerType(D->getIntegerType());
}
}
SemaRef.InstantiateAttrs(TemplateArgs, D, Enum);
Enum->setInstantiationOfMemberEnum(D, TSK_ImplicitInstantiation);
Enum->setAccess(D->getAccess());
// Forward the mangling number from the template to the instantiated decl.
SemaRef.Context.setManglingNumber(Enum, SemaRef.Context.getManglingNumber(D));
// See if the old tag was defined along with a declarator.
// If it did, mark the new tag as being associated with that declarator.
if (DeclaratorDecl *DD = SemaRef.Context.getDeclaratorForUnnamedTagDecl(D))
SemaRef.Context.addDeclaratorForUnnamedTagDecl(Enum, DD);
// See if the old tag was defined along with a typedef.
// If it did, mark the new tag as being associated with that typedef.
if (TypedefNameDecl *TND = SemaRef.Context.getTypedefNameForUnnamedTagDecl(D))
SemaRef.Context.addTypedefNameForUnnamedTagDecl(Enum, TND);
if (SubstQualifier(D, Enum)) return nullptr;
Owner->addDecl(Enum);
EnumDecl *Def = D->getDefinition();
if (Def && Def != D) {
// If this is an out-of-line definition of an enum member template, check
// that the underlying types match in the instantiation of both
// declarations.
if (TypeSourceInfo *TI = Def->getIntegerTypeSourceInfo()) {
SourceLocation UnderlyingLoc = TI->getTypeLoc().getBeginLoc();
QualType DefnUnderlying =
SemaRef.SubstType(TI->getType(), TemplateArgs,
UnderlyingLoc, DeclarationName());
SemaRef.CheckEnumRedeclaration(Def->getLocation(), Def->isScoped(),
DefnUnderlying, /*IsFixed=*/true, Enum);
}
}
// C++11 [temp.inst]p1: The implicit instantiation of a class template
// specialization causes the implicit instantiation of the declarations, but
// not the definitions of scoped member enumerations.
//
// DR1484 clarifies that enumeration definitions inside a template
// declaration aren't considered entities that can be separately instantiated
// from the rest of the entity they are declared inside.
if (isDeclWithinFunction(D) ? D == Def : Def && !Enum->isScoped()) {
// Prevent redundant instantiation of the enumerator-definition if the
// definition has already been instantiated due to a prior
// opaque-enum-declaration.
if (PrevDecl == nullptr) {
SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Enum);
InstantiateEnumDefinition(Enum, Def);
}
}
return Enum;
}
void TemplateDeclInstantiator::InstantiateEnumDefinition(
EnumDecl *Enum, EnumDecl *Pattern) {
Enum->startDefinition();
// Update the location to refer to the definition.
Enum->setLocation(Pattern->getLocation());
SmallVector<Decl*, 4> Enumerators;
EnumConstantDecl *LastEnumConst = nullptr;
for (auto *EC : Pattern->enumerators()) {
// The specified value for the enumerator.
ExprResult Value((Expr *)nullptr);
if (Expr *UninstValue = EC->getInitExpr()) {
// The enumerator's value expression is a constant expression.
EnterExpressionEvaluationContext Unevaluated(
SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated);
Value = SemaRef.SubstExpr(UninstValue, TemplateArgs);
}
// Drop the initial value and continue.
bool isInvalid = false;
if (Value.isInvalid()) {
Value = nullptr;
isInvalid = true;
}
EnumConstantDecl *EnumConst
= SemaRef.CheckEnumConstant(Enum, LastEnumConst,
EC->getLocation(), EC->getIdentifier(),
Value.get());
if (isInvalid) {
if (EnumConst)
EnumConst->setInvalidDecl();
Enum->setInvalidDecl();
}
if (EnumConst) {
SemaRef.InstantiateAttrs(TemplateArgs, EC, EnumConst);
EnumConst->setAccess(Enum->getAccess());
Enum->addDecl(EnumConst);
Enumerators.push_back(EnumConst);
LastEnumConst = EnumConst;
if (Pattern->getDeclContext()->isFunctionOrMethod() &&
!Enum->isScoped()) {
// If the enumeration is within a function or method, record the enum
// constant as a local.
SemaRef.CurrentInstantiationScope->InstantiatedLocal(EC, EnumConst);
}
}
}
SemaRef.ActOnEnumBody(Enum->getLocation(), Enum->getBraceRange(), Enum,
Enumerators, nullptr, ParsedAttributesView());
}
Decl *TemplateDeclInstantiator::VisitEnumConstantDecl(EnumConstantDecl *D) {
llvm_unreachable("EnumConstantDecls can only occur within EnumDecls.");
}
Decl *
TemplateDeclInstantiator::VisitBuiltinTemplateDecl(BuiltinTemplateDecl *D) {
llvm_unreachable("BuiltinTemplateDecls cannot be instantiated.");
}
Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
bool isFriend = (D->getFriendObjectKind() != Decl::FOK_None);
// Create a local instantiation scope for this class template, which
// will contain the instantiations of the template parameters.
LocalInstantiationScope Scope(SemaRef);
TemplateParameterList *TempParams = D->getTemplateParameters();
TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
if (!InstParams)
return nullptr;
CXXRecordDecl *Pattern = D->getTemplatedDecl();
// Instantiate the qualifier. We have to do this first in case
// we're a friend declaration, because if we are then we need to put
// the new declaration in the appropriate context.
NestedNameSpecifierLoc QualifierLoc = Pattern->getQualifierLoc();
if (QualifierLoc) {
QualifierLoc = SemaRef.SubstNestedNameSpecifierLoc(QualifierLoc,
TemplateArgs);
if (!QualifierLoc)
return nullptr;
}
CXXRecordDecl *PrevDecl = nullptr;
ClassTemplateDecl *PrevClassTemplate = nullptr;
if (!isFriend && getPreviousDeclForInstantiation(Pattern)) {
DeclContext::lookup_result Found = Owner->lookup(Pattern->getDeclName());
if (!Found.empty()) {
PrevClassTemplate = dyn_cast<ClassTemplateDecl>(Found.front());
if (PrevClassTemplate)
PrevDecl = PrevClassTemplate->getTemplatedDecl();
}
}
// If this isn't a friend, then it's a member template, in which
// case we just want to build the instantiation in the
// specialization. If it is a friend, we want to build it in
// the appropriate context.
DeclContext *DC = Owner;
if (isFriend) {
if (QualifierLoc) {
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
DC = SemaRef.computeDeclContext(SS);
if (!DC) return nullptr;
} else {
DC = SemaRef.FindInstantiatedContext(Pattern->getLocation(),
Pattern->getDeclContext(),
TemplateArgs);
}
// Look for a previous declaration of the template in the owning
// context.
LookupResult R(SemaRef, Pattern->getDeclName(), Pattern->getLocation(),
Sema::LookupOrdinaryName,
SemaRef.forRedeclarationInCurContext());
SemaRef.LookupQualifiedName(R, DC);
if (R.isSingleResult()) {
PrevClassTemplate = R.getAsSingle<ClassTemplateDecl>();
if (PrevClassTemplate)
PrevDecl = PrevClassTemplate->getTemplatedDecl();
}
if (!PrevClassTemplate && QualifierLoc) {
SemaRef.Diag(Pattern->getLocation(), diag::err_not_tag_in_scope)
<< llvm::to_underlying(D->getTemplatedDecl()->getTagKind())
<< Pattern->getDeclName() << DC << QualifierLoc.getSourceRange();
return nullptr;
}
}
CXXRecordDecl *RecordInst = CXXRecordDecl::Create(
SemaRef.Context, Pattern->getTagKind(), DC, Pattern->getBeginLoc(),
Pattern->getLocation(), Pattern->getIdentifier(), PrevDecl,
/*DelayTypeCreation=*/true);
if (QualifierLoc)
RecordInst->setQualifierInfo(QualifierLoc);
SemaRef.InstantiateAttrsForDecl(TemplateArgs, Pattern, RecordInst, LateAttrs,
StartingScope);
ClassTemplateDecl *Inst
= ClassTemplateDecl::Create(SemaRef.Context, DC, D->getLocation(),
D->getIdentifier(), InstParams, RecordInst);
RecordInst->setDescribedClassTemplate(Inst);
if (isFriend) {
assert(!Owner->isDependentContext());
Inst->setLexicalDeclContext(Owner);
RecordInst->setLexicalDeclContext(Owner);
Inst->setObjectOfFriendDecl();
if (PrevClassTemplate) {
Inst->setCommonPtr(PrevClassTemplate->getCommonPtr());
RecordInst->setTypeForDecl(
PrevClassTemplate->getTemplatedDecl()->getTypeForDecl());
const ClassTemplateDecl *MostRecentPrevCT =
PrevClassTemplate->getMostRecentDecl();
TemplateParameterList *PrevParams =
MostRecentPrevCT->getTemplateParameters();
// Make sure the parameter lists match.
if (!SemaRef.TemplateParameterListsAreEqual(
RecordInst, InstParams, MostRecentPrevCT->getTemplatedDecl(),
PrevParams, true, Sema::TPL_TemplateMatch))
return nullptr;
// Do some additional validation, then merge default arguments
// from the existing declarations.
if (SemaRef.CheckTemplateParameterList(InstParams, PrevParams,
Sema::TPC_Other))
return nullptr;
Inst->setAccess(PrevClassTemplate->getAccess());
} else {
Inst->setAccess(D->getAccess());
}
Inst->setObjectOfFriendDecl();
// TODO: do we want to track the instantiation progeny of this
// friend target decl?
} else {
Inst->setAccess(D->getAccess());
if (!PrevClassTemplate)
Inst->setInstantiatedFromMemberTemplate(D);
}
Inst->setPreviousDecl(PrevClassTemplate);
// Trigger creation of the type for the instantiation.
SemaRef.Context.getInjectedClassNameType(
RecordInst, Inst->getInjectedClassNameSpecialization());
// Finish handling of friends.
if (isFriend) {
DC->makeDeclVisibleInContext(Inst);
return Inst;
}
if (D->isOutOfLine()) {
Inst->setLexicalDeclContext(D->getLexicalDeclContext());
RecordInst->setLexicalDeclContext(D->getLexicalDeclContext());
}
Owner->addDecl(Inst);
if (!PrevClassTemplate) {
// Queue up any out-of-line partial specializations of this member
// class template; the client will force their instantiation once
// the enclosing class has been instantiated.
SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs;
D->getPartialSpecializations(PartialSpecs);
for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I)
if (PartialSpecs[I]->getFirstDecl()->isOutOfLine())
OutOfLinePartialSpecs.push_back(std::make_pair(Inst, PartialSpecs[I]));
}
return Inst;
}
Decl *
TemplateDeclInstantiator::VisitClassTemplatePartialSpecializationDecl(
ClassTemplatePartialSpecializationDecl *D) {
ClassTemplateDecl *ClassTemplate = D->getSpecializedTemplate();
// Lookup the already-instantiated declaration in the instantiation
// of the class template and return that.
DeclContext::lookup_result Found
= Owner->lookup(ClassTemplate->getDeclName());
if (Found.empty())
return nullptr;
ClassTemplateDecl *InstClassTemplate
= dyn_cast<ClassTemplateDecl>(Found.front());
if (!InstClassTemplate)
return nullptr;
if (ClassTemplatePartialSpecializationDecl *Result
= InstClassTemplate->findPartialSpecInstantiatedFromMember(D))
return Result;
return InstantiateClassTemplatePartialSpecialization(InstClassTemplate, D);
}
Decl *TemplateDeclInstantiator::VisitVarTemplateDecl(VarTemplateDecl *D) {
assert(D->getTemplatedDecl()->isStaticDataMember() &&
"Only static data member templates are allowed.");
// Create a local instantiation scope for this variable template, which
// will contain the instantiations of the template parameters.
LocalInstantiationScope Scope(SemaRef);
TemplateParameterList *TempParams = D->getTemplateParameters();
TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
if (!InstParams)
return nullptr;
VarDecl *Pattern = D->getTemplatedDecl();
VarTemplateDecl *PrevVarTemplate = nullptr;
if (getPreviousDeclForInstantiation(Pattern)) {
DeclContext::lookup_result Found = Owner->lookup(Pattern->getDeclName());
if (!Found.empty())
PrevVarTemplate = dyn_cast<VarTemplateDecl>(Found.front());
}
VarDecl *VarInst =
cast_or_null<VarDecl>(VisitVarDecl(Pattern,
/*InstantiatingVarTemplate=*/true));
if (!VarInst) return nullptr;
DeclContext *DC = Owner;
VarTemplateDecl *Inst = VarTemplateDecl::Create(
SemaRef.Context, DC, D->getLocation(), D->getIdentifier(), InstParams,
VarInst);
VarInst->setDescribedVarTemplate(Inst);
Inst->setPreviousDecl(PrevVarTemplate);
Inst->setAccess(D->getAccess());
if (!PrevVarTemplate)
Inst->setInstantiatedFromMemberTemplate(D);
if (D->isOutOfLine()) {
Inst->setLexicalDeclContext(D->getLexicalDeclContext());
VarInst->setLexicalDeclContext(D->getLexicalDeclContext());
}
Owner->addDecl(Inst);
if (!PrevVarTemplate) {
// Queue up any out-of-line partial specializations of this member
// variable template; the client will force their instantiation once
// the enclosing class has been instantiated.
SmallVector<VarTemplatePartialSpecializationDecl *, 4> PartialSpecs;
D->getPartialSpecializations(PartialSpecs);
for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I)
if (PartialSpecs[I]->getFirstDecl()->isOutOfLine())
OutOfLineVarPartialSpecs.push_back(
std::make_pair(Inst, PartialSpecs[I]));
}
return Inst;
}
Decl *TemplateDeclInstantiator::VisitVarTemplatePartialSpecializationDecl(
VarTemplatePartialSpecializationDecl *D) {
assert(D->isStaticDataMember() &&
"Only static data member templates are allowed.");
VarTemplateDecl *VarTemplate = D->getSpecializedTemplate();
// Lookup the already-instantiated declaration and return that.
DeclContext::lookup_result Found = Owner->lookup(VarTemplate->getDeclName());
assert(!Found.empty() && "Instantiation found nothing?");
VarTemplateDecl *InstVarTemplate = dyn_cast<VarTemplateDecl>(Found.front());
assert(InstVarTemplate && "Instantiation did not find a variable template?");
if (VarTemplatePartialSpecializationDecl *Result =
InstVarTemplate->findPartialSpecInstantiatedFromMember(D))
return Result;
return InstantiateVarTemplatePartialSpecialization(InstVarTemplate, D);
}
Decl *
TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
// Create a local instantiation scope for this function template, which
// will contain the instantiations of the template parameters and then get
// merged with the local instantiation scope for the function template
// itself.
LocalInstantiationScope Scope(SemaRef);
Sema::ConstraintEvalRAII<TemplateDeclInstantiator> RAII(*this);
TemplateParameterList *TempParams = D->getTemplateParameters();
TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
if (!InstParams)
return nullptr;
FunctionDecl *Instantiated = nullptr;
if (CXXMethodDecl *DMethod = dyn_cast<CXXMethodDecl>(D->getTemplatedDecl()))
Instantiated = cast_or_null<FunctionDecl>(VisitCXXMethodDecl(DMethod,
InstParams));
else
Instantiated = cast_or_null<FunctionDecl>(VisitFunctionDecl(
D->getTemplatedDecl(),
InstParams));
if (!Instantiated)
return nullptr;
// Link the instantiated function template declaration to the function
// template from which it was instantiated.
FunctionTemplateDecl *InstTemplate
= Instantiated->getDescribedFunctionTemplate();
InstTemplate->setAccess(D->getAccess());
assert(InstTemplate &&
"VisitFunctionDecl/CXXMethodDecl didn't create a template!");
bool isFriend = (InstTemplate->getFriendObjectKind() != Decl::FOK_None);
// Link the instantiation back to the pattern *unless* this is a
// non-definition friend declaration.
if (!InstTemplate->getInstantiatedFromMemberTemplate() &&
!(isFriend && !D->getTemplatedDecl()->isThisDeclarationADefinition()))
InstTemplate->setInstantiatedFromMemberTemplate(D);
// Make declarations visible in the appropriate context.
if (!isFriend) {
Owner->addDecl(InstTemplate);
} else if (InstTemplate->getDeclContext()->isRecord() &&
!getPreviousDeclForInstantiation(D)) {
SemaRef.CheckFriendAccess(InstTemplate);
}
return InstTemplate;
}
Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
CXXRecordDecl *PrevDecl = nullptr;
if (CXXRecordDecl *PatternPrev = getPreviousDeclForInstantiation(D)) {
NamedDecl *Prev = SemaRef.FindInstantiatedDecl(D->getLocation(),
PatternPrev,
TemplateArgs);
if (!Prev) return nullptr;
PrevDecl = cast<CXXRecordDecl>(Prev);
}
CXXRecordDecl *Record = nullptr;
bool IsInjectedClassName = D->isInjectedClassName();
if (D->isLambda())
Record = CXXRecordDecl::CreateLambda(
SemaRef.Context, Owner, D->getLambdaTypeInfo(), D->getLocation(),
D->getLambdaDependencyKind(), D->isGenericLambda(),
D->getLambdaCaptureDefault());
else
Record = CXXRecordDecl::Create(SemaRef.Context, D->getTagKind(), Owner,
D->getBeginLoc(), D->getLocation(),
D->getIdentifier(), PrevDecl,
/*DelayTypeCreation=*/IsInjectedClassName);
// Link the type of the injected-class-name to that of the outer class.
if (IsInjectedClassName)
(void)SemaRef.Context.getTypeDeclType(Record, cast<CXXRecordDecl>(Owner));
// Substitute the nested name specifier, if any.
if (SubstQualifier(D, Record))
return nullptr;
SemaRef.InstantiateAttrsForDecl(TemplateArgs, D, Record, LateAttrs,
StartingScope);
Record->setImplicit(D->isImplicit());
// FIXME: Check against AS_none is an ugly hack to work around the issue that
// the tag decls introduced by friend class declarations don't have an access
// specifier. Remove once this area of the code gets sorted out.
if (D->getAccess() != AS_none)
Record->setAccess(D->getAccess());
if (!IsInjectedClassName)
Record->setInstantiationOfMemberClass(D, TSK_ImplicitInstantiation);
// If the original function was part of a friend declaration,
// inherit its namespace state.
if (D->getFriendObjectKind())
Record->setObjectOfFriendDecl();
// Make sure that anonymous structs and unions are recorded.
if (D->isAnonymousStructOrUnion())
Record->setAnonymousStructOrUnion(true);
if (D->isLocalClass())
SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Record);
// Forward the mangling number from the template to the instantiated decl.
SemaRef.Context.setManglingNumber(Record,
SemaRef.Context.getManglingNumber(D));
// See if the old tag was defined along with a declarator.
// If it did, mark the new tag as being associated with that declarator.
if (DeclaratorDecl *DD = SemaRef.Context.getDeclaratorForUnnamedTagDecl(D))
SemaRef.Context.addDeclaratorForUnnamedTagDecl(Record, DD);
// See if the old tag was defined along with a typedef.
// If it did, mark the new tag as being associated with that typedef.
if (TypedefNameDecl *TND = SemaRef.Context.getTypedefNameForUnnamedTagDecl(D))
SemaRef.Context.addTypedefNameForUnnamedTagDecl(Record, TND);
Owner->addDecl(Record);
// DR1484 clarifies that the members of a local class are instantiated as part
// of the instantiation of their enclosing entity.
if (D->isCompleteDefinition() && D->isLocalClass()) {
Sema::LocalEagerInstantiationScope LocalInstantiations(SemaRef,
/*AtEndOfTU=*/false);
SemaRef.InstantiateClass(D->getLocation(), Record, D, TemplateArgs,
TSK_ImplicitInstantiation,
/*Complain=*/true);
// For nested local classes, we will instantiate the members when we
// reach the end of the outermost (non-nested) local class.
if (!D->isCXXClassMember())
SemaRef.InstantiateClassMembers(D->getLocation(), Record, TemplateArgs,
TSK_ImplicitInstantiation);
// This class may have local implicit instantiations that need to be
// performed within this scope.
LocalInstantiations.perform();
}
SemaRef.DiagnoseUnusedNestedTypedefs(Record);
if (IsInjectedClassName)
assert(Record->isInjectedClassName() && "Broken injected-class-name");
return Record;
}
/// Adjust the given function type for an instantiation of the
/// given declaration, to cope with modifications to the function's type that
/// aren't reflected in the type-source information.
///
/// \param D The declaration we're instantiating.
/// \param TInfo The already-instantiated type.
static QualType adjustFunctionTypeForInstantiation(ASTContext &Context,
FunctionDecl *D,
TypeSourceInfo *TInfo) {
const FunctionProtoType *OrigFunc
= D->getType()->castAs<FunctionProtoType>();
const FunctionProtoType *NewFunc
= TInfo->getType()->castAs<FunctionProtoType>();
if (OrigFunc->getExtInfo() == NewFunc->getExtInfo())
return TInfo->getType();
FunctionProtoType::ExtProtoInfo NewEPI = NewFunc->getExtProtoInfo();
NewEPI.ExtInfo = OrigFunc->getExtInfo();
return Context.getFunctionType(NewFunc->getReturnType(),
NewFunc->getParamTypes(), NewEPI);
}
/// Normal class members are of more specific types and therefore
/// don't make it here. This function serves three purposes:
/// 1) instantiating function templates
/// 2) substituting friend and local function declarations
/// 3) substituting deduction guide declarations for nested class templates
Decl *TemplateDeclInstantiator::VisitFunctionDecl(
FunctionDecl *D, TemplateParameterList *TemplateParams,
RewriteKind FunctionRewriteKind) {
// Check whether there is already a function template specialization for
// this declaration.
FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate();
bool isFriend;
if (FunctionTemplate)
isFriend = (FunctionTemplate->getFriendObjectKind() != Decl::FOK_None);
else
isFriend = (D->getFriendObjectKind() != Decl::FOK_None);
// Friend function defined withing class template may stop being function
// definition during AST merges from different modules, in this case decl
// with function body should be used for instantiation.
if (ExternalASTSource *Source = SemaRef.Context.getExternalSource()) {
if (isFriend && Source->wasThisDeclarationADefinition(D)) {
const FunctionDecl *Defn = nullptr;
if (D->hasBody(Defn)) {
D = const_cast<FunctionDecl *>(Defn);
FunctionTemplate = Defn->getDescribedFunctionTemplate();
}
}
}
if (FunctionTemplate && !TemplateParams) {
ArrayRef<TemplateArgument> Innermost = TemplateArgs.getInnermost();
void *InsertPos = nullptr;
FunctionDecl *SpecFunc
= FunctionTemplate->findSpecialization(Innermost, InsertPos);
// If we already have a function template specialization, return it.
if (SpecFunc)
return SpecFunc;
}
bool MergeWithParentScope = (TemplateParams != nullptr) ||
Owner->isFunctionOrMethod() ||
!(isa<Decl>(Owner) &&
cast<Decl>(Owner)->isDefinedOutsideFunctionOrMethod());
LocalInstantiationScope Scope(SemaRef, MergeWithParentScope);
ExplicitSpecifier InstantiatedExplicitSpecifier;
if (auto *DGuide = dyn_cast<CXXDeductionGuideDecl>(D)) {
InstantiatedExplicitSpecifier = SemaRef.instantiateExplicitSpecifier(
TemplateArgs, DGuide->getExplicitSpecifier());
if (InstantiatedExplicitSpecifier.isInvalid())
return nullptr;
}
SmallVector<ParmVarDecl *, 4> Params;
TypeSourceInfo *TInfo = SubstFunctionType(D, Params);
if (!TInfo)
return nullptr;
QualType T = adjustFunctionTypeForInstantiation(SemaRef.Context, D, TInfo);
if (TemplateParams && TemplateParams->size()) {
auto *LastParam =
dyn_cast<TemplateTypeParmDecl>(TemplateParams->asArray().back());
if (LastParam && LastParam->isImplicit() &&
LastParam->hasTypeConstraint()) {
// In abbreviated templates, the type-constraints of invented template
// type parameters are instantiated with the function type, invalidating
// the TemplateParameterList which relied on the template type parameter
// not having a type constraint. Recreate the TemplateParameterList with
// the updated parameter list.
TemplateParams = TemplateParameterList::Create(
SemaRef.Context, TemplateParams->getTemplateLoc(),
TemplateParams->getLAngleLoc(), TemplateParams->asArray(),
TemplateParams->getRAngleLoc(), TemplateParams->getRequiresClause());
}
}
NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc();
if (QualifierLoc) {
QualifierLoc = SemaRef.SubstNestedNameSpecifierLoc(QualifierLoc,
TemplateArgs);
if (!QualifierLoc)
return nullptr;
}
AssociatedConstraint TrailingRequiresClause = D->getTrailingRequiresClause();
// If we're instantiating a local function declaration, put the result
// in the enclosing namespace; otherwise we need to find the instantiated
// context.
DeclContext *DC;
if (D->isLocalExternDecl()) {
DC = Owner;
SemaRef.adjustContextForLocalExternDecl(DC);
} else if (isFriend && QualifierLoc) {
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
DC = SemaRef.computeDeclContext(SS);
if (!DC) return nullptr;
} else {
DC = SemaRef.FindInstantiatedContext(D->getLocation(), D->getDeclContext(),
TemplateArgs);
}
DeclarationNameInfo NameInfo
= SemaRef.SubstDeclarationNameInfo(D->getNameInfo(), TemplateArgs);
if (FunctionRewriteKind != RewriteKind::None)
adjustForRewrite(FunctionRewriteKind, D, T, TInfo, NameInfo);
FunctionDecl *Function;
if (auto *DGuide = dyn_cast<CXXDeductionGuideDecl>(D)) {
Function = CXXDeductionGuideDecl::Create(
SemaRef.Context, DC, D->getInnerLocStart(),
InstantiatedExplicitSpecifier, NameInfo, T, TInfo,
D->getSourceRange().getEnd(), DGuide->getCorrespondingConstructor(),
DGuide->getDeductionCandidateKind(), TrailingRequiresClause,
DGuide->getSourceDeductionGuide(),
DGuide->getSourceDeductionGuideKind());
Function->setAccess(D->getAccess());
} else {
Function = FunctionDecl::Create(
SemaRef.Context, DC, D->getInnerLocStart(), NameInfo, T, TInfo,
D->getCanonicalDecl()->getStorageClass(), D->UsesFPIntrin(),
D->isInlineSpecified(), D->hasWrittenPrototype(), D->getConstexprKind(),
TrailingRequiresClause);
Function->setFriendConstraintRefersToEnclosingTemplate(
D->FriendConstraintRefersToEnclosingTemplate());
Function->setRangeEnd(D->getSourceRange().getEnd());
}
if (D->isInlined())
Function->setImplicitlyInline();
if (QualifierLoc)
Function->setQualifierInfo(QualifierLoc);
if (D->isLocalExternDecl())
Function->setLocalExternDecl();
DeclContext *LexicalDC = Owner;
if (!isFriend && D->isOutOfLine() && !D->isLocalExternDecl()) {
assert(D->getDeclContext()->isFileContext());
LexicalDC = D->getDeclContext();
}
else if (D->isLocalExternDecl()) {
LexicalDC = SemaRef.CurContext;
}
Function->setIsDestroyingOperatorDelete(D->isDestroyingOperatorDelete());
Function->setIsTypeAwareOperatorNewOrDelete(
D->isTypeAwareOperatorNewOrDelete());
Function->setLexicalDeclContext(LexicalDC);
// Attach the parameters
for (unsigned P = 0; P < Params.size(); ++P)
if (Params[P])
Params[P]->setOwningFunction(Function);
Function->setParams(Params);
if (TrailingRequiresClause)
Function->setTrailingRequiresClause(TrailingRequiresClause);
if (TemplateParams) {
// Our resulting instantiation is actually a function template, since we
// are substituting only the outer template parameters. For example, given
//
// template<typename T>
// struct X {
// template<typename U> friend void f(T, U);
// };
//
// X<int> x;
//
// We are instantiating the friend function template "f" within X<int>,
// which means substituting int for T, but leaving "f" as a friend function
// template.
// Build the function template itself.
FunctionTemplate = FunctionTemplateDecl::Create(SemaRef.Context, DC,
Function->getLocation(),
Function->getDeclName(),
TemplateParams, Function);
Function->setDescribedFunctionTemplate(FunctionTemplate);
FunctionTemplate->setLexicalDeclContext(LexicalDC);
if (isFriend && D->isThisDeclarationADefinition()) {
FunctionTemplate->setInstantiatedFromMemberTemplate(
D->getDescribedFunctionTemplate());
}
} else if (FunctionTemplate &&
SemaRef.CodeSynthesisContexts.back().Kind !=
Sema::CodeSynthesisContext::BuildingDeductionGuides) {
// Record this function template specialization.
ArrayRef<TemplateArgument> Innermost = TemplateArgs.getInnermost();
Function->setFunctionTemplateSpecialization(FunctionTemplate,
TemplateArgumentList::CreateCopy(SemaRef.Context,
Innermost),
/*InsertPos=*/nullptr);
} else if (FunctionRewriteKind == RewriteKind::None) {
if (isFriend && D->isThisDeclarationADefinition()) {
// Do not connect the friend to the template unless it's actually a
// definition. We don't want non-template functions to be marked as being
// template instantiations.
Function->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
} else if (!isFriend) {
// If this is not a function template, and this is not a friend (that is,
// this is a locally declared function), save the instantiation
// relationship for the purposes of constraint instantiation.
Function->setInstantiatedFromDecl(D);
}
}
if (isFriend) {
Function->setObjectOfFriendDecl();
if (FunctionTemplateDecl *FT = Function->getDescribedFunctionTemplate())
FT->setObjectOfFriendDecl();
}
if (InitFunctionInstantiation(Function, D))
Function->setInvalidDecl();
bool IsExplicitSpecialization = false;
LookupResult Previous(
SemaRef, Function->getDeclName(), SourceLocation(),
D->isLocalExternDecl() ? Sema::LookupRedeclarationWithLinkage
: Sema::LookupOrdinaryName,
D->isLocalExternDecl() ? RedeclarationKind::ForExternalRedeclaration
: SemaRef.forRedeclarationInCurContext());
if (DependentFunctionTemplateSpecializationInfo *DFTSI =
D->getDependentSpecializationInfo()) {
assert(isFriend && "dependent specialization info on "
"non-member non-friend function?");
// Instantiate the explicit template arguments.
TemplateArgumentListInfo ExplicitArgs;
if (const auto *ArgsWritten = DFTSI->TemplateArgumentsAsWritten) {
ExplicitArgs.setLAngleLoc(ArgsWritten->getLAngleLoc());
ExplicitArgs.setRAngleLoc(ArgsWritten->getRAngleLoc());
if (SemaRef.SubstTemplateArguments(ArgsWritten->arguments(), TemplateArgs,
ExplicitArgs))
return nullptr;
}
// Map the candidates for the primary template to their instantiations.
for (FunctionTemplateDecl *FTD : DFTSI->getCandidates()) {
if (NamedDecl *ND =
SemaRef.FindInstantiatedDecl(D->getLocation(), FTD, TemplateArgs))
Previous.addDecl(ND);
else
return nullptr;
}
if (SemaRef.CheckFunctionTemplateSpecialization(
Function,
DFTSI->TemplateArgumentsAsWritten ? &ExplicitArgs : nullptr,
Previous))
Function->setInvalidDecl();
IsExplicitSpecialization = true;
} else if (const ASTTemplateArgumentListInfo *ArgsWritten =
D->getTemplateSpecializationArgsAsWritten()) {
// The name of this function was written as a template-id.
SemaRef.LookupQualifiedName(Previous, DC);
// Instantiate the explicit template arguments.
TemplateArgumentListInfo ExplicitArgs(ArgsWritten->getLAngleLoc(),
ArgsWritten->getRAngleLoc());
if (SemaRef.SubstTemplateArguments(ArgsWritten->arguments(), TemplateArgs,
ExplicitArgs))
return nullptr;
if (SemaRef.CheckFunctionTemplateSpecialization(Function,
&ExplicitArgs,
Previous))
Function->setInvalidDecl();
IsExplicitSpecialization = true;
} else if (TemplateParams || !FunctionTemplate) {
// Look only into the namespace where the friend would be declared to
// find a previous declaration. This is the innermost enclosing namespace,
// as described in ActOnFriendFunctionDecl.
SemaRef.LookupQualifiedName(Previous, DC->getRedeclContext());
// In C++, the previous declaration we find might be a tag type
// (class or enum). In this case, the new declaration will hide the
// tag type. Note that this does not apply if we're declaring a
// typedef (C++ [dcl.typedef]p4).
if (Previous.isSingleTagDecl())
Previous.clear();
// Filter out previous declarations that don't match the scope. The only
// effect this has is to remove declarations found in inline namespaces
// for friend declarations with unqualified names.
if (isFriend && !QualifierLoc) {
SemaRef.FilterLookupForScope(Previous, DC, /*Scope=*/ nullptr,
/*ConsiderLinkage=*/ true,
QualifierLoc.hasQualifier());
}
}
// Per [temp.inst], default arguments in function declarations at local scope
// are instantiated along with the enclosing declaration. For example:
//
// template<typename T>
// void ft() {
// void f(int = []{ return T::value; }());
// }
// template void ft<int>(); // error: type 'int' cannot be used prior
// to '::' because it has no members
//
// The error is issued during instantiation of ft<int>() because substitution
// into the default argument fails; the default argument is instantiated even
// though it is never used.
if (Function->isLocalExternDecl()) {
for (ParmVarDecl *PVD : Function->parameters()) {
if (!PVD->hasDefaultArg())
continue;
if (SemaRef.SubstDefaultArgument(D->getInnerLocStart(), PVD, TemplateArgs)) {
// If substitution fails, the default argument is set to a
// RecoveryExpr that wraps the uninstantiated default argument so
// that downstream diagnostics are omitted.
Expr *UninstExpr = PVD->getUninstantiatedDefaultArg();
ExprResult ErrorResult = SemaRef.CreateRecoveryExpr(
UninstExpr->getBeginLoc(), UninstExpr->getEndLoc(),
{ UninstExpr }, UninstExpr->getType());
if (ErrorResult.isUsable())
PVD->setDefaultArg(ErrorResult.get());
}
}
}
SemaRef.CheckFunctionDeclaration(/*Scope*/ nullptr, Function, Previous,
IsExplicitSpecialization,
Function->isThisDeclarationADefinition());
// Check the template parameter list against the previous declaration. The
// goal here is to pick up default arguments added since the friend was
// declared; we know the template parameter lists match, since otherwise
// we would not have picked this template as the previous declaration.
if (isFriend && TemplateParams && FunctionTemplate->getPreviousDecl()) {
SemaRef.CheckTemplateParameterList(
TemplateParams,
FunctionTemplate->getPreviousDecl()->getTemplateParameters(),
Function->isThisDeclarationADefinition()
? Sema::TPC_FriendFunctionTemplateDefinition
: Sema::TPC_FriendFunctionTemplate);
}
// If we're introducing a friend definition after the first use, trigger
// instantiation.
// FIXME: If this is a friend function template definition, we should check
// to see if any specializations have been used.
if (isFriend && D->isThisDeclarationADefinition() && Function->isUsed(false)) {
if (MemberSpecializationInfo *MSInfo =
Function->getMemberSpecializationInfo()) {
if (MSInfo->getPointOfInstantiation().isInvalid()) {
SourceLocation Loc = D->getLocation(); // FIXME
MSInfo->setPointOfInstantiation(Loc);
SemaRef.PendingLocalImplicitInstantiations.push_back(
std::make_pair(Function, Loc));
}
}
}
if (D->isExplicitlyDefaulted()) {
if (SubstDefaultedFunction(Function, D))
return nullptr;
}
if (D->isDeleted())
SemaRef.SetDeclDeleted(Function, D->getLocation(), D->getDeletedMessage());
NamedDecl *PrincipalDecl =
(TemplateParams ? cast<NamedDecl>(FunctionTemplate) : Function);
// If this declaration lives in a different context from its lexical context,
// add it to the corresponding lookup table.
if (isFriend ||
(Function->isLocalExternDecl() && !Function->getPreviousDecl()))
DC->makeDeclVisibleInContext(PrincipalDecl);
if (Function->isOverloadedOperator() && !DC->isRecord() &&
PrincipalDecl->isInIdentifierNamespace(Decl::IDNS_Ordinary))
PrincipalDecl->setNonMemberOperator();
return Function;
}
Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
CXXMethodDecl *D, TemplateParameterList *TemplateParams,
RewriteKind FunctionRewriteKind) {
FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate();
if (FunctionTemplate && !TemplateParams) {
// We are creating a function template specialization from a function
// template. Check whether there is already a function template
// specialization for this particular set of template arguments.
ArrayRef<TemplateArgument> Innermost = TemplateArgs.getInnermost();
void *InsertPos = nullptr;
FunctionDecl *SpecFunc
= FunctionTemplate->findSpecialization(Innermost, InsertPos);
// If we already have a function template specialization, return it.
if (SpecFunc)
return SpecFunc;
}
bool isFriend;
if (FunctionTemplate)
isFriend = (FunctionTemplate->getFriendObjectKind() != Decl::FOK_None);
else
isFriend = (D->getFriendObjectKind() != Decl::FOK_None);
bool MergeWithParentScope = (TemplateParams != nullptr) ||
!(isa<Decl>(Owner) &&
cast<Decl>(Owner)->isDefinedOutsideFunctionOrMethod());
LocalInstantiationScope Scope(SemaRef, MergeWithParentScope);
Sema::LambdaScopeForCallOperatorInstantiationRAII LambdaScope(
SemaRef, const_cast<CXXMethodDecl *>(D), TemplateArgs, Scope);
// Instantiate enclosing template arguments for friends.
SmallVector<TemplateParameterList *, 4> TempParamLists;
unsigned NumTempParamLists = 0;
if (isFriend && (NumTempParamLists = D->getNumTemplateParameterLists())) {
TempParamLists.resize(NumTempParamLists);
for (unsigned I = 0; I != NumTempParamLists; ++I) {
TemplateParameterList *TempParams = D->getTemplateParameterList(I);
TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
if (!InstParams)
return nullptr;
TempParamLists[I] = InstParams;
}
}
auto InstantiatedExplicitSpecifier = ExplicitSpecifier::getFromDecl(D);
// deduction guides need this
const bool CouldInstantiate =
InstantiatedExplicitSpecifier.getExpr() == nullptr ||
!InstantiatedExplicitSpecifier.getExpr()->isValueDependent();
// Delay the instantiation of the explicit-specifier until after the
// constraints are checked during template argument deduction.
if (CouldInstantiate ||
SemaRef.CodeSynthesisContexts.back().Kind !=
Sema::CodeSynthesisContext::DeducedTemplateArgumentSubstitution) {
InstantiatedExplicitSpecifier = SemaRef.instantiateExplicitSpecifier(
TemplateArgs, InstantiatedExplicitSpecifier);
if (InstantiatedExplicitSpecifier.isInvalid())
return nullptr;
} else {
InstantiatedExplicitSpecifier.setKind(ExplicitSpecKind::Unresolved);
}
// Implicit destructors/constructors created for local classes in
// DeclareImplicit* (see SemaDeclCXX.cpp) might not have an associated TSI.
// Unfortunately there isn't enough context in those functions to
// conditionally populate the TSI without breaking non-template related use
// cases. Populate TSIs prior to calling SubstFunctionType to make sure we get
// a proper transformation.
if (isLambdaMethod(D) && !D->getTypeSourceInfo() &&
isa<CXXConstructorDecl, CXXDestructorDecl>(D)) {
TypeSourceInfo *TSI =
SemaRef.Context.getTrivialTypeSourceInfo(D->getType());
D->setTypeSourceInfo(TSI);
}
SmallVector<ParmVarDecl *, 4> Params;
TypeSourceInfo *TInfo = SubstFunctionType(D, Params);
if (!TInfo)
return nullptr;
QualType T = adjustFunctionTypeForInstantiation(SemaRef.Context, D, TInfo);
if (TemplateParams && TemplateParams->size()) {
auto *LastParam =
dyn_cast<TemplateTypeParmDecl>(TemplateParams->asArray().back());
if (LastParam && LastParam->isImplicit() &&
LastParam->hasTypeConstraint()) {
// In abbreviated templates, the type-constraints of invented template
// type parameters are instantiated with the function type, invalidating
// the TemplateParameterList which relied on the template type parameter
// not having a type constraint. Recreate the TemplateParameterList with
// the updated parameter list.
TemplateParams = TemplateParameterList::Create(
SemaRef.Context, TemplateParams->getTemplateLoc(),
TemplateParams->getLAngleLoc(), TemplateParams->asArray(),
TemplateParams->getRAngleLoc(), TemplateParams->getRequiresClause());
}
}
NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc();
if (QualifierLoc) {
QualifierLoc = SemaRef.SubstNestedNameSpecifierLoc(QualifierLoc,
TemplateArgs);
if (!QualifierLoc)
return nullptr;
}
DeclContext *DC = Owner;
if (isFriend) {
if (QualifierLoc) {
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
DC = SemaRef.computeDeclContext(SS);
if (DC && SemaRef.RequireCompleteDeclContext(SS, DC))
return nullptr;
} else {
DC = SemaRef.FindInstantiatedContext(D->getLocation(),
D->getDeclContext(),
TemplateArgs);
}
if (!DC) return nullptr;
}
CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
AssociatedConstraint TrailingRequiresClause = D->getTrailingRequiresClause();
DeclarationNameInfo NameInfo
= SemaRef.SubstDeclarationNameInfo(D->getNameInfo(), TemplateArgs);
if (FunctionRewriteKind != RewriteKind::None)
adjustForRewrite(FunctionRewriteKind, D, T, TInfo, NameInfo);
// Build the instantiated method declaration.
CXXMethodDecl *Method = nullptr;
SourceLocation StartLoc = D->getInnerLocStart();
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
Method = CXXConstructorDecl::Create(
SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo,
InstantiatedExplicitSpecifier, Constructor->UsesFPIntrin(),
Constructor->isInlineSpecified(), false,
Constructor->getConstexprKind(), InheritedConstructor(),
TrailingRequiresClause);
Method->setRangeEnd(Constructor->getEndLoc());
} else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
Method = CXXDestructorDecl::Create(
SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo,
Destructor->UsesFPIntrin(), Destructor->isInlineSpecified(), false,
Destructor->getConstexprKind(), TrailingRequiresClause);
Method->setIneligibleOrNotSelected(true);
Method->setRangeEnd(Destructor->getEndLoc());
Method->setDeclName(SemaRef.Context.DeclarationNames.getCXXDestructorName(
SemaRef.Context.getCanonicalType(
SemaRef.Context.getTypeDeclType(Record))));
} else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) {
Method = CXXConversionDecl::Create(
SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo,
Conversion->UsesFPIntrin(), Conversion->isInlineSpecified(),
InstantiatedExplicitSpecifier, Conversion->getConstexprKind(),
Conversion->getEndLoc(), TrailingRequiresClause);
} else {
StorageClass SC = D->isStatic() ? SC_Static : SC_None;
Method = CXXMethodDecl::Create(
SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo, SC,
D->UsesFPIntrin(), D->isInlineSpecified(), D->getConstexprKind(),
D->getEndLoc(), TrailingRequiresClause);
}
if (D->isInlined())
Method->setImplicitlyInline();
if (QualifierLoc)
Method->setQualifierInfo(QualifierLoc);
if (TemplateParams) {
// Our resulting instantiation is actually a function template, since we
// are substituting only the outer template parameters. For example, given
//
// template<typename T>
// struct X {
// template<typename U> void f(T, U);
// };
//
// X<int> x;
//
// We are instantiating the member template "f" within X<int>, which means
// substituting int for T, but leaving "f" as a member function template.
// Build the function template itself.
FunctionTemplate = FunctionTemplateDecl::Create(SemaRef.Context, Record,
Method->getLocation(),
Method->getDeclName(),
TemplateParams, Method);
if (isFriend) {
FunctionTemplate->setLexicalDeclContext(Owner);
FunctionTemplate->setObjectOfFriendDecl();
} else if (D->isOutOfLine())
FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext());
Method->setDescribedFunctionTemplate(FunctionTemplate);
} else if (FunctionTemplate) {
// Record this function template specialization.
ArrayRef<TemplateArgument> Innermost = TemplateArgs.getInnermost();
Method->setFunctionTemplateSpecialization(FunctionTemplate,
TemplateArgumentList::CreateCopy(SemaRef.Context,
Innermost),
/*InsertPos=*/nullptr);
} else if (!isFriend && FunctionRewriteKind == RewriteKind::None) {
// Record that this is an instantiation of a member function.
Method->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
}
// If we are instantiating a member function defined
// out-of-line, the instantiation will have the same lexical
// context (which will be a namespace scope) as the template.
if (isFriend) {
if (NumTempParamLists)
Method->setTemplateParameterListsInfo(
SemaRef.Context,
llvm::ArrayRef(TempParamLists.data(), NumTempParamLists));
Method->setLexicalDeclContext(Owner);
Method->setObjectOfFriendDecl();
} else if (D->isOutOfLine())
Method->setLexicalDeclContext(D->getLexicalDeclContext());
// Attach the parameters
for (unsigned P = 0; P < Params.size(); ++P)
Params[P]->setOwningFunction(Method);
Method->setParams(Params);
if (InitMethodInstantiation(Method, D))
Method->setInvalidDecl();
LookupResult Previous(SemaRef, NameInfo, Sema::LookupOrdinaryName,
RedeclarationKind::ForExternalRedeclaration);
bool IsExplicitSpecialization = false;
// If the name of this function was written as a template-id, instantiate
// the explicit template arguments.
if (DependentFunctionTemplateSpecializationInfo *DFTSI =
D->getDependentSpecializationInfo()) {
// Instantiate the explicit template arguments.
TemplateArgumentListInfo ExplicitArgs;
if (const auto *ArgsWritten = DFTSI->TemplateArgumentsAsWritten) {
ExplicitArgs.setLAngleLoc(ArgsWritten->getLAngleLoc());
ExplicitArgs.setRAngleLoc(ArgsWritten->getRAngleLoc());
if (SemaRef.SubstTemplateArguments(ArgsWritten->arguments(), TemplateArgs,
ExplicitArgs))
return nullptr;
}
// Map the candidates for the primary template to their instantiations.
for (FunctionTemplateDecl *FTD : DFTSI->getCandidates()) {
if (NamedDecl *ND =
SemaRef.FindInstantiatedDecl(D->getLocation(), FTD, TemplateArgs))
Previous.addDecl(ND);
else
return nullptr;
}
if (SemaRef.CheckFunctionTemplateSpecialization(
Method, DFTSI->TemplateArgumentsAsWritten ? &ExplicitArgs : nullptr,
Previous))
Method->setInvalidDecl();
IsExplicitSpecialization = true;
} else if (const ASTTemplateArgumentListInfo *ArgsWritten =
D->getTemplateSpecializationArgsAsWritten()) {
SemaRef.LookupQualifiedName(Previous, DC);
TemplateArgumentListInfo ExplicitArgs(ArgsWritten->getLAngleLoc(),
ArgsWritten->getRAngleLoc());
if (SemaRef.SubstTemplateArguments(ArgsWritten->arguments(), TemplateArgs,
ExplicitArgs))
return nullptr;
if (SemaRef.CheckFunctionTemplateSpecialization(Method,
&ExplicitArgs,
Previous))
Method->setInvalidDecl();
IsExplicitSpecialization = true;
} else if (!FunctionTemplate || TemplateParams || isFriend) {
SemaRef.LookupQualifiedName(Previous, Record);
// In C++, the previous declaration we find might be a tag type
// (class or enum). In this case, the new declaration will hide the
// tag type. Note that this does not apply if we're declaring a
// typedef (C++ [dcl.typedef]p4).
if (Previous.isSingleTagDecl())
Previous.clear();
}
// Per [temp.inst], default arguments in member functions of local classes
// are instantiated along with the member function declaration. For example:
//
// template<typename T>
// void ft() {
// struct lc {
// int operator()(int p = []{ return T::value; }());
// };
// }
// template void ft<int>(); // error: type 'int' cannot be used prior
// to '::'because it has no members
//
// The error is issued during instantiation of ft<int>()::lc::operator()
// because substitution into the default argument fails; the default argument
// is instantiated even though it is never used.
if (D->isInLocalScopeForInstantiation()) {
for (unsigned P = 0; P < Params.size(); ++P) {
if (!Params[P]->hasDefaultArg())
continue;
if (SemaRef.SubstDefaultArgument(StartLoc, Params[P], TemplateArgs)) {
// If substitution fails, the default argument is set to a
// RecoveryExpr that wraps the uninstantiated default argument so
// that downstream diagnostics are omitted.
Expr *UninstExpr = Params[P]->getUninstantiatedDefaultArg();
ExprResult ErrorResult = SemaRef.CreateRecoveryExpr(
UninstExpr->getBeginLoc(), UninstExpr->getEndLoc(),
{ UninstExpr }, UninstExpr->getType());
if (ErrorResult.isUsable())
Params[P]->setDefaultArg(ErrorResult.get());
}
}
}
SemaRef.CheckFunctionDeclaration(nullptr, Method, Previous,
IsExplicitSpecialization,
Method->isThisDeclarationADefinition());
if (D->isPureVirtual())
SemaRef.CheckPureMethod(Method, SourceRange());
// Propagate access. For a non-friend declaration, the access is
// whatever we're propagating from. For a friend, it should be the
// previous declaration we just found.
if (isFriend && Method->getPreviousDecl())
Method->setAccess(Method->getPreviousDecl()->getAccess());
else
Method->setAccess(D->getAccess());
if (FunctionTemplate)
FunctionTemplate->setAccess(Method->getAccess());
SemaRef.CheckOverrideControl(Method);
// If a function is defined as defaulted or deleted, mark it as such now.
if (D->isExplicitlyDefaulted()) {
if (SubstDefaultedFunction(Method, D))
return nullptr;
}
if (D->isDeletedAsWritten())
SemaRef.SetDeclDeleted(Method, Method->getLocation(),
D->getDeletedMessage());
// If this is an explicit specialization, mark the implicitly-instantiated
// template specialization as being an explicit specialization too.
// FIXME: Is this necessary?
if (IsExplicitSpecialization && !isFriend)
SemaRef.CompleteMemberSpecialization(Method, Previous);
// If the method is a special member function, we need to mark it as
// ineligible so that Owner->addDecl() won't mark the class as non trivial.
// At the end of the class instantiation, we calculate eligibility again and
// then we adjust trivility if needed.
// We need this check to happen only after the method parameters are set,
// because being e.g. a copy constructor depends on the instantiated
// arguments.
if (auto *Constructor = dyn_cast<CXXConstructorDecl>(Method)) {
if (Constructor->isDefaultConstructor() ||
Constructor->isCopyOrMoveConstructor())
Method->setIneligibleOrNotSelected(true);
} else if (Method->isCopyAssignmentOperator() ||
Method->isMoveAssignmentOperator()) {
Method->setIneligibleOrNotSelected(true);
}
// If there's a function template, let our caller handle it.
if (FunctionTemplate) {
// do nothing
// Don't hide a (potentially) valid declaration with an invalid one.
} else if (Method->isInvalidDecl() && !Previous.empty()) {
// do nothing
// Otherwise, check access to friends and make them visible.
} else if (isFriend) {
// We only need to re-check access for methods which we didn't
// manage to match during parsing.
if (!D->getPreviousDecl())
SemaRef.CheckFriendAccess(Method);
Record->makeDeclVisibleInContext(Method);
// Otherwise, add the declaration. We don't need to do this for
// class-scope specializations because we'll have matched them with
// the appropriate template.
} else {
Owner->addDecl(Method);
}
// PR17480: Honor the used attribute to instantiate member function
// definitions
if (Method->hasAttr<UsedAttr>()) {
if (const auto *A = dyn_cast<CXXRecordDecl>(Owner)) {
SourceLocation Loc;
if (const MemberSpecializationInfo *MSInfo =
A->getMemberSpecializationInfo())
Loc = MSInfo->getPointOfInstantiation();
else if (const auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(A))
Loc = Spec->getPointOfInstantiation();
SemaRef.MarkFunctionReferenced(Loc, Method);
}
}
return Method;
}
Decl *TemplateDeclInstantiator::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
return VisitCXXMethodDecl(D);
}
Decl *TemplateDeclInstantiator::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
return VisitCXXMethodDecl(D);
}
Decl *TemplateDeclInstantiator::VisitCXXConversionDecl(CXXConversionDecl *D) {
return VisitCXXMethodDecl(D);
}
Decl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) {
return SemaRef.SubstParmVarDecl(D, TemplateArgs, /*indexAdjustment*/ 0,
std::nullopt,
/*ExpectParameterPack=*/false);
}
Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl(
TemplateTypeParmDecl *D) {
assert(D->getTypeForDecl()->isTemplateTypeParmType());
UnsignedOrNone NumExpanded = std::nullopt;
if (const TypeConstraint *TC = D->getTypeConstraint()) {
if (D->isPackExpansion() && !D->getNumExpansionParameters()) {
assert(TC->getTemplateArgsAsWritten() &&
"type parameter can only be an expansion when explicit arguments "
"are specified");
// The template type parameter pack's type is a pack expansion of types.
// Determine whether we need to expand this parameter pack into separate
// types.
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
for (auto &ArgLoc : TC->getTemplateArgsAsWritten()->arguments())
SemaRef.collectUnexpandedParameterPacks(ArgLoc, Unexpanded);
// Determine whether the set of unexpanded parameter packs can and should
// be expanded.
bool Expand = true;
bool RetainExpansion = false;
if (SemaRef.CheckParameterPacksForExpansion(
cast<CXXFoldExpr>(TC->getImmediatelyDeclaredConstraint())
->getEllipsisLoc(),
SourceRange(TC->getConceptNameLoc(),
TC->hasExplicitTemplateArgs() ?
TC->getTemplateArgsAsWritten()->getRAngleLoc() :
TC->getConceptNameInfo().getEndLoc()),
Unexpanded, TemplateArgs, Expand, RetainExpansion, NumExpanded))
return nullptr;
}
}
TemplateTypeParmDecl *Inst = TemplateTypeParmDecl::Create(
SemaRef.Context, Owner, D->getBeginLoc(), D->getLocation(),
D->getDepth() - TemplateArgs.getNumSubstitutedLevels(), D->getIndex(),
D->getIdentifier(), D->wasDeclaredWithTypename(), D->isParameterPack(),
D->hasTypeConstraint(), NumExpanded);
Inst->setAccess(AS_public);
Inst->setImplicit(D->isImplicit());
if (auto *TC = D->getTypeConstraint()) {
if (!D->isImplicit()) {
// Invented template parameter type constraints will be instantiated
// with the corresponding auto-typed parameter as it might reference
// other parameters.
if (SemaRef.SubstTypeConstraint(Inst, TC, TemplateArgs,
EvaluateConstraints))
return nullptr;
}
}
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) {
TemplateArgumentLoc Output;
if (!SemaRef.SubstTemplateArgument(D->getDefaultArgument(), TemplateArgs,
Output))
Inst->setDefaultArgument(SemaRef.getASTContext(), Output);
}
// Introduce this template parameter's instantiation into the instantiation
// scope.
SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Inst);
return Inst;
}
Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
NonTypeTemplateParmDecl *D) {
// Substitute into the type of the non-type template parameter.
TypeLoc TL = D->getTypeSourceInfo()->getTypeLoc();
SmallVector<TypeSourceInfo *, 4> ExpandedParameterPackTypesAsWritten;
SmallVector<QualType, 4> ExpandedParameterPackTypes;
bool IsExpandedParameterPack = false;
TypeSourceInfo *DI;
QualType T;
bool Invalid = false;
if (D->isExpandedParameterPack()) {
// The non-type template parameter pack is an already-expanded pack
// expansion of types. Substitute into each of the expanded types.
ExpandedParameterPackTypes.reserve(D->getNumExpansionTypes());
ExpandedParameterPackTypesAsWritten.reserve(D->getNumExpansionTypes());
for (unsigned I = 0, N = D->getNumExpansionTypes(); I != N; ++I) {
TypeSourceInfo *NewDI =
SemaRef.SubstType(D->getExpansionTypeSourceInfo(I), TemplateArgs,
D->getLocation(), D->getDeclName());
if (!NewDI)
return nullptr;
QualType NewT =
SemaRef.CheckNonTypeTemplateParameterType(NewDI, D->getLocation());
if (NewT.isNull())
return nullptr;
ExpandedParameterPackTypesAsWritten.push_back(NewDI);
ExpandedParameterPackTypes.push_back(NewT);
}
IsExpandedParameterPack = true;
DI = D->getTypeSourceInfo();
T = DI->getType();
} else if (D->isPackExpansion()) {
// The non-type template parameter pack's type is a pack expansion of types.
// Determine whether we need to expand this parameter pack into separate
// types.
PackExpansionTypeLoc Expansion = TL.castAs<PackExpansionTypeLoc>();
TypeLoc Pattern = Expansion.getPatternLoc();
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
SemaRef.collectUnexpandedParameterPacks(Pattern, Unexpanded);
// Determine whether the set of unexpanded parameter packs can and should
// be expanded.
bool Expand = true;
bool RetainExpansion = false;
UnsignedOrNone OrigNumExpansions =
Expansion.getTypePtr()->getNumExpansions();
UnsignedOrNone NumExpansions = OrigNumExpansions;
if (SemaRef.CheckParameterPacksForExpansion(Expansion.getEllipsisLoc(),
Pattern.getSourceRange(),
Unexpanded,
TemplateArgs,
Expand, RetainExpansion,
NumExpansions))
return nullptr;
if (Expand) {
for (unsigned I = 0; I != *NumExpansions; ++I) {
Sema::ArgPackSubstIndexRAII SubstIndex(SemaRef, I);
TypeSourceInfo *NewDI = SemaRef.SubstType(Pattern, TemplateArgs,
D->getLocation(),
D->getDeclName());
if (!NewDI)
return nullptr;
QualType NewT =
SemaRef.CheckNonTypeTemplateParameterType(NewDI, D->getLocation());
if (NewT.isNull())
return nullptr;
ExpandedParameterPackTypesAsWritten.push_back(NewDI);
ExpandedParameterPackTypes.push_back(NewT);
}
// Note that we have an expanded parameter pack. The "type" of this
// expanded parameter pack is the original expansion type, but callers
// will end up using the expanded parameter pack types for type-checking.
IsExpandedParameterPack = true;
DI = D->getTypeSourceInfo();
T = DI->getType();
} else {
// We cannot fully expand the pack expansion now, so substitute into the
// pattern and create a new pack expansion type.
Sema::ArgPackSubstIndexRAII SubstIndex(SemaRef, std::nullopt);
TypeSourceInfo *NewPattern = SemaRef.SubstType(Pattern, TemplateArgs,
D->getLocation(),
D->getDeclName());
if (!NewPattern)
return nullptr;
SemaRef.CheckNonTypeTemplateParameterType(NewPattern, D->getLocation());
DI = SemaRef.CheckPackExpansion(NewPattern, Expansion.getEllipsisLoc(),
NumExpansions);
if (!DI)
return nullptr;
T = DI->getType();
}
} else {
// Simple case: substitution into a parameter that is not a parameter pack.
DI = SemaRef.SubstType(D->getTypeSourceInfo(), TemplateArgs,
D->getLocation(), D->getDeclName());
if (!DI)
return nullptr;
// Check that this type is acceptable for a non-type template parameter.
T = SemaRef.CheckNonTypeTemplateParameterType(DI, D->getLocation());
if (T.isNull()) {
T = SemaRef.Context.IntTy;
Invalid = true;
}
}
NonTypeTemplateParmDecl *Param;
if (IsExpandedParameterPack)
Param = NonTypeTemplateParmDecl::Create(
SemaRef.Context, Owner, D->getInnerLocStart(), D->getLocation(),
D->getDepth() - TemplateArgs.getNumSubstitutedLevels(),
D->getPosition(), D->getIdentifier(), T, DI, ExpandedParameterPackTypes,
ExpandedParameterPackTypesAsWritten);
else
Param = NonTypeTemplateParmDecl::Create(
SemaRef.Context, Owner, D->getInnerLocStart(), D->getLocation(),
D->getDepth() - TemplateArgs.getNumSubstitutedLevels(),
D->getPosition(), D->getIdentifier(), T, D->isParameterPack(), DI);
if (AutoTypeLoc AutoLoc = DI->getTypeLoc().getContainedAutoTypeLoc())
if (AutoLoc.isConstrained()) {
SourceLocation EllipsisLoc;
if (IsExpandedParameterPack)
EllipsisLoc =
DI->getTypeLoc().getAs<PackExpansionTypeLoc>().getEllipsisLoc();
else if (auto *Constraint = dyn_cast_if_present<CXXFoldExpr>(
D->getPlaceholderTypeConstraint()))
EllipsisLoc = Constraint->getEllipsisLoc();
// Note: We attach the uninstantiated constriant here, so that it can be
// instantiated relative to the top level, like all our other
// constraints.
if (SemaRef.AttachTypeConstraint(AutoLoc, /*NewConstrainedParm=*/Param,
/*OrigConstrainedParm=*/D, EllipsisLoc))
Invalid = true;
}
Param->setAccess(AS_public);
Param->setImplicit(D->isImplicit());
if (Invalid)
Param->setInvalidDecl();
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) {
EnterExpressionEvaluationContext ConstantEvaluated(
SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated);
TemplateArgumentLoc Result;
if (!SemaRef.SubstTemplateArgument(D->getDefaultArgument(), TemplateArgs,
Result))
Param->setDefaultArgument(SemaRef.Context, Result);
}
// Introduce this template parameter's instantiation into the instantiation
// scope.
SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Param);
return Param;
}
static void collectUnexpandedParameterPacks(
Sema &S,
TemplateParameterList *Params,
SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) {
for (const auto &P : *Params) {
if (P->isTemplateParameterPack())
continue;
if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P))
S.collectUnexpandedParameterPacks(NTTP->getTypeSourceInfo()->getTypeLoc(),
Unexpanded);
if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(P))
collectUnexpandedParameterPacks(S, TTP->getTemplateParameters(),
Unexpanded);
}
}
Decl *
TemplateDeclInstantiator::VisitTemplateTemplateParmDecl(
TemplateTemplateParmDecl *D) {
// Instantiate the template parameter list of the template template parameter.
TemplateParameterList *TempParams = D->getTemplateParameters();
TemplateParameterList *InstParams;
SmallVector<TemplateParameterList*, 8> ExpandedParams;
bool IsExpandedParameterPack = false;
if (D->isExpandedParameterPack()) {
// The template template parameter pack is an already-expanded pack
// expansion of template parameters. Substitute into each of the expanded
// parameters.
ExpandedParams.reserve(D->getNumExpansionTemplateParameters());
for (unsigned I = 0, N = D->getNumExpansionTemplateParameters();
I != N; ++I) {
LocalInstantiationScope Scope(SemaRef);
TemplateParameterList *Expansion =
SubstTemplateParams(D->getExpansionTemplateParameters(I));
if (!Expansion)
return nullptr;
ExpandedParams.push_back(Expansion);
}
IsExpandedParameterPack = true;
InstParams = TempParams;
} else if (D->isPackExpansion()) {
// The template template parameter pack expands to a pack of template
// template parameters. Determine whether we need to expand this parameter
// pack into separate parameters.
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
collectUnexpandedParameterPacks(SemaRef, D->getTemplateParameters(),
Unexpanded);
// Determine whether the set of unexpanded parameter packs can and should
// be expanded.
bool Expand = true;
bool RetainExpansion = false;
UnsignedOrNone NumExpansions = std::nullopt;
if (SemaRef.CheckParameterPacksForExpansion(D->getLocation(),
TempParams->getSourceRange(),
Unexpanded,
TemplateArgs,
Expand, RetainExpansion,
NumExpansions))
return nullptr;
if (Expand) {
for (unsigned I = 0; I != *NumExpansions; ++I) {
Sema::ArgPackSubstIndexRAII SubstIndex(SemaRef, I);
LocalInstantiationScope Scope(SemaRef);
TemplateParameterList *Expansion = SubstTemplateParams(TempParams);
if (!Expansion)
return nullptr;
ExpandedParams.push_back(Expansion);
}
// Note that we have an expanded parameter pack. The "type" of this
// expanded parameter pack is the original expansion type, but callers
// will end up using the expanded parameter pack types for type-checking.
IsExpandedParameterPack = true;
InstParams = TempParams;
} else {
// We cannot fully expand the pack expansion now, so just substitute
// into the pattern.
Sema::ArgPackSubstIndexRAII SubstIndex(SemaRef, std::nullopt);
LocalInstantiationScope Scope(SemaRef);
InstParams = SubstTemplateParams(TempParams);
if (!InstParams)
return nullptr;
}
} else {
// Perform the actual substitution of template parameters within a new,
// local instantiation scope.
LocalInstantiationScope Scope(SemaRef);
InstParams = SubstTemplateParams(TempParams);
if (!InstParams)
return nullptr;
}
// Build the template template parameter.
TemplateTemplateParmDecl *Param;
if (IsExpandedParameterPack)
Param = TemplateTemplateParmDecl::Create(
SemaRef.Context, Owner, D->getLocation(),
D->getDepth() - TemplateArgs.getNumSubstitutedLevels(),
D->getPosition(), D->getIdentifier(), D->wasDeclaredWithTypename(),
InstParams, ExpandedParams);
else
Param = TemplateTemplateParmDecl::Create(
SemaRef.Context, Owner, D->getLocation(),
D->getDepth() - TemplateArgs.getNumSubstitutedLevels(),
D->getPosition(), D->isParameterPack(), D->getIdentifier(),
D->wasDeclaredWithTypename(), InstParams);
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) {
NestedNameSpecifierLoc QualifierLoc =
D->getDefaultArgument().getTemplateQualifierLoc();
QualifierLoc =
SemaRef.SubstNestedNameSpecifierLoc(QualifierLoc, TemplateArgs);
TemplateName TName = SemaRef.SubstTemplateName(
QualifierLoc, D->getDefaultArgument().getArgument().getAsTemplate(),
D->getDefaultArgument().getTemplateNameLoc(), TemplateArgs);
if (!TName.isNull())
Param->setDefaultArgument(
SemaRef.Context,
TemplateArgumentLoc(SemaRef.Context, TemplateArgument(TName),
D->getDefaultArgument().getTemplateQualifierLoc(),
D->getDefaultArgument().getTemplateNameLoc()));
}
Param->setAccess(AS_public);
Param->setImplicit(D->isImplicit());
// Introduce this template parameter's instantiation into the instantiation
// scope.
SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Param);
return Param;
}
Decl *TemplateDeclInstantiator::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
// Using directives are never dependent (and never contain any types or
// expressions), so they require no explicit instantiation work.
UsingDirectiveDecl *Inst
= UsingDirectiveDecl::Create(SemaRef.Context, Owner, D->getLocation(),
D->getNamespaceKeyLocation(),
D->getQualifierLoc(),
D->getIdentLocation(),
D->getNominatedNamespace(),
D->getCommonAncestor());
// Add the using directive to its declaration context
// only if this is not a function or method.
if (!Owner->isFunctionOrMethod())
Owner->addDecl(Inst);
return Inst;
}
Decl *TemplateDeclInstantiator::VisitBaseUsingDecls(BaseUsingDecl *D,
BaseUsingDecl *Inst,
LookupResult *Lookup) {
bool isFunctionScope = Owner->isFunctionOrMethod();
for (auto *Shadow : D->shadows()) {
// FIXME: UsingShadowDecl doesn't preserve its immediate target, so
// reconstruct it in the case where it matters. Hm, can we extract it from
// the DeclSpec when parsing and save it in the UsingDecl itself?
NamedDecl *OldTarget = Shadow->getTargetDecl();
if (auto *CUSD = dyn_cast<ConstructorUsingShadowDecl>(Shadow))
if (auto *BaseShadow = CUSD->getNominatedBaseClassShadowDecl())
OldTarget = BaseShadow;
NamedDecl *InstTarget = nullptr;
if (auto *EmptyD =
dyn_cast<UnresolvedUsingIfExistsDecl>(Shadow->getTargetDecl())) {
InstTarget = UnresolvedUsingIfExistsDecl::Create(
SemaRef.Context, Owner, EmptyD->getLocation(), EmptyD->getDeclName());
} else {
InstTarget = cast_or_null<NamedDecl>(SemaRef.FindInstantiatedDecl(
Shadow->getLocation(), OldTarget, TemplateArgs));
}
if (!InstTarget)
return nullptr;
UsingShadowDecl *PrevDecl = nullptr;
if (Lookup &&
SemaRef.CheckUsingShadowDecl(Inst, InstTarget, *Lookup, PrevDecl))
continue;
if (UsingShadowDecl *OldPrev = getPreviousDeclForInstantiation(Shadow))
PrevDecl = cast_or_null<UsingShadowDecl>(SemaRef.FindInstantiatedDecl(
Shadow->getLocation(), OldPrev, TemplateArgs));
UsingShadowDecl *InstShadow = SemaRef.BuildUsingShadowDecl(
/*Scope*/ nullptr, Inst, InstTarget, PrevDecl);
SemaRef.Context.setInstantiatedFromUsingShadowDecl(InstShadow, Shadow);
if (isFunctionScope)
SemaRef.CurrentInstantiationScope->InstantiatedLocal(Shadow, InstShadow);
}
return Inst;
}
Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) {
// The nested name specifier may be dependent, for example
// template <typename T> struct t {
// struct s1 { T f1(); };
// struct s2 : s1 { using s1::f1; };
// };
// template struct t<int>;
// Here, in using s1::f1, s1 refers to t<T>::s1;
// we need to substitute for t<int>::s1.
NestedNameSpecifierLoc QualifierLoc
= SemaRef.SubstNestedNameSpecifierLoc(D->getQualifierLoc(),
TemplateArgs);
if (!QualifierLoc)
return nullptr;
// For an inheriting constructor declaration, the name of the using
// declaration is the name of a constructor in this class, not in the
// base class.
DeclarationNameInfo NameInfo = D->getNameInfo();
if (NameInfo.getName().getNameKind() == DeclarationName::CXXConstructorName)
if (auto *RD = dyn_cast<CXXRecordDecl>(SemaRef.CurContext))
NameInfo.setName(SemaRef.Context.DeclarationNames.getCXXConstructorName(
SemaRef.Context.getCanonicalType(SemaRef.Context.getRecordType(RD))));
// We only need to do redeclaration lookups if we're in a class scope (in
// fact, it's not really even possible in non-class scopes).
bool CheckRedeclaration = Owner->isRecord();
LookupResult Prev(SemaRef, NameInfo, Sema::LookupUsingDeclName,
RedeclarationKind::ForVisibleRedeclaration);
UsingDecl *NewUD = UsingDecl::Create(SemaRef.Context, Owner,
D->getUsingLoc(),
QualifierLoc,
NameInfo,
D->hasTypename());
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
if (CheckRedeclaration) {
Prev.setHideTags(false);
SemaRef.LookupQualifiedName(Prev, Owner);
// Check for invalid redeclarations.
if (SemaRef.CheckUsingDeclRedeclaration(D->getUsingLoc(),
D->hasTypename(), SS,
D->getLocation(), Prev))
NewUD->setInvalidDecl();
}
if (!NewUD->isInvalidDecl() &&
SemaRef.CheckUsingDeclQualifier(D->getUsingLoc(), D->hasTypename(), SS,
NameInfo, D->getLocation(), nullptr, D))
NewUD->setInvalidDecl();
SemaRef.Context.setInstantiatedFromUsingDecl(NewUD, D);
NewUD->setAccess(D->getAccess());
Owner->addDecl(NewUD);
// Don't process the shadow decls for an invalid decl.
if (NewUD->isInvalidDecl())
return NewUD;
// If the using scope was dependent, or we had dependent bases, we need to
// recheck the inheritance
if (NameInfo.getName().getNameKind() == DeclarationName::CXXConstructorName)
SemaRef.CheckInheritingConstructorUsingDecl(NewUD);
return VisitBaseUsingDecls(D, NewUD, CheckRedeclaration ? &Prev : nullptr);
}
Decl *TemplateDeclInstantiator::VisitUsingEnumDecl(UsingEnumDecl *D) {
// Cannot be a dependent type, but still could be an instantiation
EnumDecl *EnumD = cast_or_null<EnumDecl>(SemaRef.FindInstantiatedDecl(
D->getLocation(), D->getEnumDecl(), TemplateArgs));
if (SemaRef.RequireCompleteEnumDecl(EnumD, EnumD->getLocation()))
return nullptr;
TypeSourceInfo *TSI = SemaRef.SubstType(D->getEnumType(), TemplateArgs,
D->getLocation(), D->getDeclName());
if (!TSI)
return nullptr;
UsingEnumDecl *NewUD =
UsingEnumDecl::Create(SemaRef.Context, Owner, D->getUsingLoc(),
D->getEnumLoc(), D->getLocation(), TSI);
SemaRef.Context.setInstantiatedFromUsingEnumDecl(NewUD, D);
NewUD->setAccess(D->getAccess());
Owner->addDecl(NewUD);
// Don't process the shadow decls for an invalid decl.
if (NewUD->isInvalidDecl())
return NewUD;
// We don't have to recheck for duplication of the UsingEnumDecl itself, as it
// cannot be dependent, and will therefore have been checked during template
// definition.
return VisitBaseUsingDecls(D, NewUD, nullptr);
}
Decl *TemplateDeclInstantiator::VisitUsingShadowDecl(UsingShadowDecl *D) {
// Ignore these; we handle them in bulk when processing the UsingDecl.
return nullptr;
}
Decl *TemplateDeclInstantiator::VisitConstructorUsingShadowDecl(
ConstructorUsingShadowDecl *D) {
// Ignore these; we handle them in bulk when processing the UsingDecl.
return nullptr;
}
template <typename T>
Decl *TemplateDeclInstantiator::instantiateUnresolvedUsingDecl(
T *D, bool InstantiatingPackElement) {
// If this is a pack expansion, expand it now.
if (D->isPackExpansion() && !InstantiatingPackElement) {
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
SemaRef.collectUnexpandedParameterPacks(D->getQualifierLoc(), Unexpanded);
SemaRef.collectUnexpandedParameterPacks(D->getNameInfo(), Unexpanded);
// Determine whether the set of unexpanded parameter packs can and should
// be expanded.
bool Expand = true;
bool RetainExpansion = false;
UnsignedOrNone NumExpansions = std::nullopt;
if (SemaRef.CheckParameterPacksForExpansion(
D->getEllipsisLoc(), D->getSourceRange(), Unexpanded, TemplateArgs,
Expand, RetainExpansion, NumExpansions))
return nullptr;
// This declaration cannot appear within a function template signature,
// so we can't have a partial argument list for a parameter pack.
assert(!RetainExpansion &&
"should never need to retain an expansion for UsingPackDecl");
if (!Expand) {
// We cannot fully expand the pack expansion now, so substitute into the
// pattern and create a new pack expansion.
Sema::ArgPackSubstIndexRAII SubstIndex(SemaRef, std::nullopt);
return instantiateUnresolvedUsingDecl(D, true);
}
// Within a function, we don't have any normal way to check for conflicts
// between shadow declarations from different using declarations in the
// same pack expansion, but this is always ill-formed because all expansions
// must produce (conflicting) enumerators.
//
// Sadly we can't just reject this in the template definition because it
// could be valid if the pack is empty or has exactly one expansion.
if (D->getDeclContext()->isFunctionOrMethod() && *NumExpansions > 1) {
SemaRef.Diag(D->getEllipsisLoc(),
diag::err_using_decl_redeclaration_expansion);
return nullptr;
}
// Instantiate the slices of this pack and build a UsingPackDecl.
SmallVector<NamedDecl*, 8> Expansions;
for (unsigned I = 0; I != *NumExpansions; ++I) {
Sema::ArgPackSubstIndexRAII SubstIndex(SemaRef, I);
Decl *Slice = instantiateUnresolvedUsingDecl(D, true);
if (!Slice)
return nullptr;
// Note that we can still get unresolved using declarations here, if we
// had arguments for all packs but the pattern also contained other
// template arguments (this only happens during partial substitution, eg
// into the body of a generic lambda in a function template).
Expansions.push_back(cast<NamedDecl>(Slice));
}
auto *NewD = SemaRef.BuildUsingPackDecl(D, Expansions);
if (isDeclWithinFunction(D))
SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, NewD);
return NewD;
}
UnresolvedUsingTypenameDecl *TD = dyn_cast<UnresolvedUsingTypenameDecl>(D);
SourceLocation TypenameLoc = TD ? TD->getTypenameLoc() : SourceLocation();
NestedNameSpecifierLoc QualifierLoc
= SemaRef.SubstNestedNameSpecifierLoc(D->getQualifierLoc(),
TemplateArgs);
if (!QualifierLoc)
return nullptr;
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
DeclarationNameInfo NameInfo
= SemaRef.SubstDeclarationNameInfo(D->getNameInfo(), TemplateArgs);
// Produce a pack expansion only if we're not instantiating a particular
// slice of a pack expansion.
bool InstantiatingSlice =
D->getEllipsisLoc().isValid() && SemaRef.ArgPackSubstIndex;
SourceLocation EllipsisLoc =
InstantiatingSlice ? SourceLocation() : D->getEllipsisLoc();
bool IsUsingIfExists = D->template hasAttr<UsingIfExistsAttr>();
NamedDecl *UD = SemaRef.BuildUsingDeclaration(
/*Scope*/ nullptr, D->getAccess(), D->getUsingLoc(),
/*HasTypename*/ TD, TypenameLoc, SS, NameInfo, EllipsisLoc,
ParsedAttributesView(),
/*IsInstantiation*/ true, IsUsingIfExists);
if (UD) {
SemaRef.InstantiateAttrs(TemplateArgs, D, UD);
SemaRef.Context.setInstantiatedFromUsingDecl(UD, D);
}
return UD;
}
Decl *TemplateDeclInstantiator::VisitUnresolvedUsingTypenameDecl(
UnresolvedUsingTypenameDecl *D) {
return instantiateUnresolvedUsingDecl(D);
}
Decl *TemplateDeclInstantiator::VisitUnresolvedUsingValueDecl(
UnresolvedUsingValueDecl *D) {
return instantiateUnresolvedUsingDecl(D);
}
Decl *TemplateDeclInstantiator::VisitUnresolvedUsingIfExistsDecl(
UnresolvedUsingIfExistsDecl *D) {
llvm_unreachable("referring to unresolved decl out of UsingShadowDecl");
}
Decl *TemplateDeclInstantiator::VisitUsingPackDecl(UsingPackDecl *D) {
SmallVector<NamedDecl*, 8> Expansions;
for (auto *UD : D->expansions()) {
if (NamedDecl *NewUD =
SemaRef.FindInstantiatedDecl(D->getLocation(), UD, TemplateArgs))
Expansions.push_back(NewUD);
else
return nullptr;
}
auto *NewD = SemaRef.BuildUsingPackDecl(D, Expansions);
if (isDeclWithinFunction(D))
SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, NewD);
return NewD;
}
Decl *TemplateDeclInstantiator::VisitOMPThreadPrivateDecl(
OMPThreadPrivateDecl *D) {
SmallVector<Expr *, 5> Vars;
for (auto *I : D->varlist()) {
Expr *Var = SemaRef.SubstExpr(I, TemplateArgs).get();
assert(isa<DeclRefExpr>(Var) && "threadprivate arg is not a DeclRefExpr");
Vars.push_back(Var);
}
OMPThreadPrivateDecl *TD =
SemaRef.OpenMP().CheckOMPThreadPrivateDecl(D->getLocation(), Vars);
TD->setAccess(AS_public);
Owner->addDecl(TD);
return TD;
}
Decl *TemplateDeclInstantiator::VisitOMPAllocateDecl(OMPAllocateDecl *D) {
SmallVector<Expr *, 5> Vars;
for (auto *I : D->varlist()) {
Expr *Var = SemaRef.SubstExpr(I, TemplateArgs).get();
assert(isa<DeclRefExpr>(Var) && "allocate arg is not a DeclRefExpr");
Vars.push_back(Var);
}
SmallVector<OMPClause *, 4> Clauses;
// Copy map clauses from the original mapper.
for (OMPClause *C : D->clauselists()) {
OMPClause *IC = nullptr;
if (auto *AC = dyn_cast<OMPAllocatorClause>(C)) {
ExprResult NewE = SemaRef.SubstExpr(AC->getAllocator(), TemplateArgs);
if (!NewE.isUsable())
continue;
IC = SemaRef.OpenMP().ActOnOpenMPAllocatorClause(
NewE.get(), AC->getBeginLoc(), AC->getLParenLoc(), AC->getEndLoc());
} else if (auto *AC = dyn_cast<OMPAlignClause>(C)) {
ExprResult NewE = SemaRef.SubstExpr(AC->getAlignment(), TemplateArgs);
if (!NewE.isUsable())
continue;
IC = SemaRef.OpenMP().ActOnOpenMPAlignClause(
NewE.get(), AC->getBeginLoc(), AC->getLParenLoc(), AC->getEndLoc());
// If align clause value ends up being invalid, this can end up null.
if (!IC)
continue;
}
Clauses.push_back(IC);
}
Sema::DeclGroupPtrTy Res = SemaRef.OpenMP().ActOnOpenMPAllocateDirective(
D->getLocation(), Vars, Clauses, Owner);
if (Res.get().isNull())
return nullptr;
return Res.get().getSingleDecl();
}
Decl *TemplateDeclInstantiator::VisitOMPRequiresDecl(OMPRequiresDecl *D) {
llvm_unreachable(
"Requires directive cannot be instantiated within a dependent context");
}
Decl *TemplateDeclInstantiator::VisitOMPDeclareReductionDecl(
OMPDeclareReductionDecl *D) {
// Instantiate type and check if it is allowed.
const bool RequiresInstantiation =
D->getType()->isDependentType() ||
D->getType()->isInstantiationDependentType() ||
D->getType()->containsUnexpandedParameterPack();
QualType SubstReductionType;
if (RequiresInstantiation) {
SubstReductionType = SemaRef.OpenMP().ActOnOpenMPDeclareReductionType(
D->getLocation(),
ParsedType::make(SemaRef.SubstType(
D->getType(), TemplateArgs, D->getLocation(), DeclarationName())));
} else {
SubstReductionType = D->getType();
}
if (SubstReductionType.isNull())
return nullptr;
Expr *Combiner = D->getCombiner();
Expr *Init = D->getInitializer();
bool IsCorrect = true;
// Create instantiated copy.
std::pair<QualType, SourceLocation> ReductionTypes[] = {
std::make_pair(SubstReductionType, D->getLocation())};
auto *PrevDeclInScope = D->getPrevDeclInScope();
if (PrevDeclInScope && !PrevDeclInScope->isInvalidDecl()) {
PrevDeclInScope = cast<OMPDeclareReductionDecl>(
cast<Decl *>(*SemaRef.CurrentInstantiationScope->findInstantiationOf(
PrevDeclInScope)));
}
auto DRD = SemaRef.OpenMP().ActOnOpenMPDeclareReductionDirectiveStart(
/*S=*/nullptr, Owner, D->getDeclName(), ReductionTypes, D->getAccess(),
PrevDeclInScope);
auto *NewDRD = cast<OMPDeclareReductionDecl>(DRD.get().getSingleDecl());
SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, NewDRD);
Expr *SubstCombiner = nullptr;
Expr *SubstInitializer = nullptr;
// Combiners instantiation sequence.
if (Combiner) {
SemaRef.OpenMP().ActOnOpenMPDeclareReductionCombinerStart(
/*S=*/nullptr, NewDRD);
SemaRef.CurrentInstantiationScope->InstantiatedLocal(
cast<DeclRefExpr>(D->getCombinerIn())->getDecl(),
cast<DeclRefExpr>(NewDRD->getCombinerIn())->getDecl());
SemaRef.CurrentInstantiationScope->InstantiatedLocal(
cast<DeclRefExpr>(D->getCombinerOut())->getDecl(),
cast<DeclRefExpr>(NewDRD->getCombinerOut())->getDecl());
auto *ThisContext = dyn_cast_or_null<CXXRecordDecl>(Owner);
Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext, Qualifiers(),
ThisContext);
SubstCombiner = SemaRef.SubstExpr(Combiner, TemplateArgs).get();
SemaRef.OpenMP().ActOnOpenMPDeclareReductionCombinerEnd(NewDRD,
SubstCombiner);
}
// Initializers instantiation sequence.
if (Init) {
VarDecl *OmpPrivParm =
SemaRef.OpenMP().ActOnOpenMPDeclareReductionInitializerStart(
/*S=*/nullptr, NewDRD);
SemaRef.CurrentInstantiationScope->InstantiatedLocal(
cast<DeclRefExpr>(D->getInitOrig())->getDecl(),
cast<DeclRefExpr>(NewDRD->getInitOrig())->getDecl());
SemaRef.CurrentInstantiationScope->InstantiatedLocal(
cast<DeclRefExpr>(D->getInitPriv())->getDecl(),
cast<DeclRefExpr>(NewDRD->getInitPriv())->getDecl());
if (D->getInitializerKind() == OMPDeclareReductionInitKind::Call) {
SubstInitializer = SemaRef.SubstExpr(Init, TemplateArgs).get();
} else {
auto *OldPrivParm =
cast<VarDecl>(cast<DeclRefExpr>(D->getInitPriv())->getDecl());
IsCorrect = IsCorrect && OldPrivParm->hasInit();
if (IsCorrect)
SemaRef.InstantiateVariableInitializer(OmpPrivParm, OldPrivParm,
TemplateArgs);
}
SemaRef.OpenMP().ActOnOpenMPDeclareReductionInitializerEnd(
NewDRD, SubstInitializer, OmpPrivParm);
}
IsCorrect = IsCorrect && SubstCombiner &&
(!Init ||
(D->getInitializerKind() == OMPDeclareReductionInitKind::Call &&
SubstInitializer) ||
(D->getInitializerKind() != OMPDeclareReductionInitKind::Call &&
!SubstInitializer));
(void)SemaRef.OpenMP().ActOnOpenMPDeclareReductionDirectiveEnd(
/*S=*/nullptr, DRD, IsCorrect && !D->isInvalidDecl());
return NewDRD;
}
Decl *
TemplateDeclInstantiator::VisitOMPDeclareMapperDecl(OMPDeclareMapperDecl *D) {
// Instantiate type and check if it is allowed.
const bool RequiresInstantiation =
D->getType()->isDependentType() ||
D->getType()->isInstantiationDependentType() ||
D->getType()->containsUnexpandedParameterPack();
QualType SubstMapperTy;
DeclarationName VN = D->getVarName();
if (RequiresInstantiation) {
SubstMapperTy = SemaRef.OpenMP().ActOnOpenMPDeclareMapperType(
D->getLocation(),
ParsedType::make(SemaRef.SubstType(D->getType(), TemplateArgs,
D->getLocation(), VN)));
} else {
SubstMapperTy = D->getType();
}
if (SubstMapperTy.isNull())
return nullptr;
// Create an instantiated copy of mapper.
auto *PrevDeclInScope = D->getPrevDeclInScope();
if (PrevDeclInScope && !PrevDeclInScope->isInvalidDecl()) {
PrevDeclInScope = cast<OMPDeclareMapperDecl>(
cast<Decl *>(*SemaRef.CurrentInstantiationScope->findInstantiationOf(
PrevDeclInScope)));
}
bool IsCorrect = true;
SmallVector<OMPClause *, 6> Clauses;
// Instantiate the mapper variable.
DeclarationNameInfo DirName;
SemaRef.OpenMP().StartOpenMPDSABlock(llvm::omp::OMPD_declare_mapper, DirName,
/*S=*/nullptr,
(*D->clauselist_begin())->getBeginLoc());
ExprResult MapperVarRef =
SemaRef.OpenMP().ActOnOpenMPDeclareMapperDirectiveVarDecl(
/*S=*/nullptr, SubstMapperTy, D->getLocation(), VN);
SemaRef.CurrentInstantiationScope->InstantiatedLocal(
cast<DeclRefExpr>(D->getMapperVarRef())->getDecl(),
cast<DeclRefExpr>(MapperVarRef.get())->getDecl());
auto *ThisContext = dyn_cast_or_null<CXXRecordDecl>(Owner);
Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext, Qualifiers(),
ThisContext);
// Instantiate map clauses.
for (OMPClause *C : D->clauselists()) {
auto *OldC = cast<OMPMapClause>(C);
SmallVector<Expr *, 4> NewVars;
for (Expr *OE : OldC->varlist()) {
Expr *NE = SemaRef.SubstExpr(OE, TemplateArgs).get();
if (!NE) {
IsCorrect = false;
break;
}
NewVars.push_back(NE);
}
if (!IsCorrect)
break;
NestedNameSpecifierLoc NewQualifierLoc =
SemaRef.SubstNestedNameSpecifierLoc(OldC->getMapperQualifierLoc(),
TemplateArgs);
CXXScopeSpec SS;
SS.Adopt(NewQualifierLoc);
DeclarationNameInfo NewNameInfo =
SemaRef.SubstDeclarationNameInfo(OldC->getMapperIdInfo(), TemplateArgs);
OMPVarListLocTy Locs(OldC->getBeginLoc(), OldC->getLParenLoc(),
OldC->getEndLoc());
OMPClause *NewC = SemaRef.OpenMP().ActOnOpenMPMapClause(
OldC->getIteratorModifier(), OldC->getMapTypeModifiers(),
OldC->getMapTypeModifiersLoc(), SS, NewNameInfo, OldC->getMapType(),
OldC->isImplicitMapType(), OldC->getMapLoc(), OldC->getColonLoc(),
NewVars, Locs);
Clauses.push_back(NewC);
}
SemaRef.OpenMP().EndOpenMPDSABlock(nullptr);
if (!IsCorrect)
return nullptr;
Sema::DeclGroupPtrTy DG = SemaRef.OpenMP().ActOnOpenMPDeclareMapperDirective(
/*S=*/nullptr, Owner, D->getDeclName(), SubstMapperTy, D->getLocation(),
VN, D->getAccess(), MapperVarRef.get(), Clauses, PrevDeclInScope);
Decl *NewDMD = DG.get().getSingleDecl();
SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, NewDMD);
return NewDMD;
}
Decl *TemplateDeclInstantiator::VisitOMPCapturedExprDecl(
OMPCapturedExprDecl * /*D*/) {
llvm_unreachable("Should not be met in templates");
}
Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D) {
return VisitFunctionDecl(D, nullptr);
}
Decl *
TemplateDeclInstantiator::VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D) {
Decl *Inst = VisitFunctionDecl(D, nullptr);
if (Inst && !D->getDescribedFunctionTemplate())
Owner->addDecl(Inst);
return Inst;
}
Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) {
return VisitCXXMethodDecl(D, nullptr);
}
Decl *TemplateDeclInstantiator::VisitRecordDecl(RecordDecl *D) {
llvm_unreachable("There are only CXXRecordDecls in C++");
}
Decl *
TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
ClassTemplateSpecializationDecl *D) {
// As a MS extension, we permit class-scope explicit specialization
// of member class templates.
ClassTemplateDecl *ClassTemplate = D->getSpecializedTemplate();
assert(ClassTemplate->getDeclContext()->isRecord() &&
D->getTemplateSpecializationKind() == TSK_ExplicitSpecialization &&
"can only instantiate an explicit specialization "
"for a member class template");
// Lookup the already-instantiated declaration in the instantiation
// of the class template.
ClassTemplateDecl *InstClassTemplate =
cast_or_null<ClassTemplateDecl>(SemaRef.FindInstantiatedDecl(
D->getLocation(), ClassTemplate, TemplateArgs));
if (!InstClassTemplate)
return nullptr;
// Substitute into the template arguments of the class template explicit
// specialization.
TemplateArgumentListInfo InstTemplateArgs;
if (const ASTTemplateArgumentListInfo *TemplateArgsInfo =
D->getTemplateArgsAsWritten()) {
InstTemplateArgs.setLAngleLoc(TemplateArgsInfo->getLAngleLoc());
InstTemplateArgs.setRAngleLoc(TemplateArgsInfo->getRAngleLoc());
if (SemaRef.SubstTemplateArguments(TemplateArgsInfo->arguments(),
TemplateArgs, InstTemplateArgs))
return nullptr;
}
// Check that the template argument list is well-formed for this
// class template.
Sema::CheckTemplateArgumentInfo CTAI;
if (SemaRef.CheckTemplateArgumentList(
InstClassTemplate, D->getLocation(), InstTemplateArgs,
/*DefaultArgs=*/{}, /*PartialTemplateArgs=*/false, CTAI,
/*UpdateArgsWithConversions=*/true))
return nullptr;
// Figure out where to insert this class template explicit specialization
// in the member template's set of class template explicit specializations.
void *InsertPos = nullptr;
ClassTemplateSpecializationDecl *PrevDecl =
InstClassTemplate->findSpecialization(CTAI.CanonicalConverted, InsertPos);
// Check whether we've already seen a conflicting instantiation of this
// declaration (for instance, if there was a prior implicit instantiation).
bool Ignored;
if (PrevDecl &&
SemaRef.CheckSpecializationInstantiationRedecl(D->getLocation(),
D->getSpecializationKind(),
PrevDecl,
PrevDecl->getSpecializationKind(),
PrevDecl->getPointOfInstantiation(),
Ignored))
return nullptr;
// If PrevDecl was a definition and D is also a definition, diagnose.
// This happens in cases like:
//
// template<typename T, typename U>
// struct Outer {
// template<typename X> struct Inner;
// template<> struct Inner<T> {};
// template<> struct Inner<U> {};
// };
//
// Outer<int, int> outer; // error: the explicit specializations of Inner
// // have the same signature.
if (PrevDecl && PrevDecl->getDefinition() &&
D->isThisDeclarationADefinition()) {
SemaRef.Diag(D->getLocation(), diag::err_redefinition) << PrevDecl;
SemaRef.Diag(PrevDecl->getDefinition()->getLocation(),
diag::note_previous_definition);
return nullptr;
}
// Create the class template partial specialization declaration.
ClassTemplateSpecializationDecl *InstD =
ClassTemplateSpecializationDecl::Create(
SemaRef.Context, D->getTagKind(), Owner, D->getBeginLoc(),
D->getLocation(), InstClassTemplate, CTAI.CanonicalConverted,
CTAI.StrictPackMatch, PrevDecl);
InstD->setTemplateArgsAsWritten(InstTemplateArgs);
// Add this partial specialization to the set of class template partial
// specializations.
if (!PrevDecl)
InstClassTemplate->AddSpecialization(InstD, InsertPos);
// Substitute the nested name specifier, if any.
if (SubstQualifier(D, InstD))
return nullptr;
InstD->setAccess(D->getAccess());
InstD->setInstantiationOfMemberClass(D, TSK_ImplicitInstantiation);
InstD->setSpecializationKind(D->getSpecializationKind());
InstD->setExternKeywordLoc(D->getExternKeywordLoc());
InstD->setTemplateKeywordLoc(D->getTemplateKeywordLoc());
Owner->addDecl(InstD);
// Instantiate the members of the class-scope explicit specialization eagerly.
// We don't have support for lazy instantiation of an explicit specialization
// yet, and MSVC eagerly instantiates in this case.
// FIXME: This is wrong in standard C++.
if (D->isThisDeclarationADefinition() &&
SemaRef.InstantiateClass(D->getLocation(), InstD, D, TemplateArgs,
TSK_ImplicitInstantiation,
/*Complain=*/true))
return nullptr;
return InstD;
}
Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
VarTemplateSpecializationDecl *D) {
TemplateArgumentListInfo VarTemplateArgsInfo;
VarTemplateDecl *VarTemplate = D->getSpecializedTemplate();
assert(VarTemplate &&
"A template specialization without specialized template?");
VarTemplateDecl *InstVarTemplate =
cast_or_null<VarTemplateDecl>(SemaRef.FindInstantiatedDecl(
D->getLocation(), VarTemplate, TemplateArgs));
if (!InstVarTemplate)
return nullptr;
// Substitute the current template arguments.
if (const ASTTemplateArgumentListInfo *TemplateArgsInfo =
D->getTemplateArgsAsWritten()) {
VarTemplateArgsInfo.setLAngleLoc(TemplateArgsInfo->getLAngleLoc());
VarTemplateArgsInfo.setRAngleLoc(TemplateArgsInfo->getRAngleLoc());
if (SemaRef.SubstTemplateArguments(TemplateArgsInfo->arguments(),
TemplateArgs, VarTemplateArgsInfo))
return nullptr;
}
// Check that the template argument list is well-formed for this template.
Sema::CheckTemplateArgumentInfo CTAI;
if (SemaRef.CheckTemplateArgumentList(
InstVarTemplate, D->getLocation(), VarTemplateArgsInfo,
/*DefaultArgs=*/{}, /*PartialTemplateArgs=*/false, CTAI,
/*UpdateArgsWithConversions=*/true))
return nullptr;
// Check whether we've already seen a declaration of this specialization.
void *InsertPos = nullptr;
VarTemplateSpecializationDecl *PrevDecl =
InstVarTemplate->findSpecialization(CTAI.CanonicalConverted, InsertPos);
// Check whether we've already seen a conflicting instantiation of this
// declaration (for instance, if there was a prior implicit instantiation).
bool Ignored;
if (PrevDecl && SemaRef.CheckSpecializationInstantiationRedecl(
D->getLocation(), D->getSpecializationKind(), PrevDecl,
PrevDecl->getSpecializationKind(),
PrevDecl->getPointOfInstantiation(), Ignored))
return nullptr;
return VisitVarTemplateSpecializationDecl(InstVarTemplate, D,
VarTemplateArgsInfo,
CTAI.CanonicalConverted, PrevDecl);
}
Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
VarTemplateDecl *VarTemplate, VarDecl *D,
const TemplateArgumentListInfo &TemplateArgsInfo,
ArrayRef<TemplateArgument> Converted,
VarTemplateSpecializationDecl *PrevDecl) {
// Do substitution on the type of the declaration
TypeSourceInfo *DI =
SemaRef.SubstType(D->getTypeSourceInfo(), TemplateArgs,
D->getTypeSpecStartLoc(), D->getDeclName());
if (!DI)
return nullptr;
if (DI->getType()->isFunctionType()) {
SemaRef.Diag(D->getLocation(), diag::err_variable_instantiates_to_function)
<< D->isStaticDataMember() << DI->getType();
return nullptr;
}
// Build the instantiated declaration
VarTemplateSpecializationDecl *Var = VarTemplateSpecializationDecl::Create(
SemaRef.Context, Owner, D->getInnerLocStart(), D->getLocation(),
VarTemplate, DI->getType(), DI, D->getStorageClass(), Converted);
Var->setTemplateArgsAsWritten(TemplateArgsInfo);
if (!PrevDecl) {
void *InsertPos = nullptr;
VarTemplate->findSpecialization(Converted, InsertPos);
VarTemplate->AddSpecialization(Var, InsertPos);
}
if (SemaRef.getLangOpts().OpenCL)
SemaRef.deduceOpenCLAddressSpace(Var);
// Substitute the nested name specifier, if any.
if (SubstQualifier(D, Var))
return nullptr;
SemaRef.BuildVariableInstantiation(Var, D, TemplateArgs, LateAttrs, Owner,
StartingScope, false, PrevDecl);
return Var;
}
Decl *TemplateDeclInstantiator::VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *D) {
llvm_unreachable("@defs is not supported in Objective-C++");
}
Decl *TemplateDeclInstantiator::VisitFriendTemplateDecl(FriendTemplateDecl *D) {
// FIXME: We need to be able to instantiate FriendTemplateDecls.
unsigned DiagID = SemaRef.getDiagnostics().getCustomDiagID(
DiagnosticsEngine::Error,
"cannot instantiate %0 yet");
SemaRef.Diag(D->getLocation(), DiagID)
<< D->getDeclKindName();
return nullptr;
}
Decl *TemplateDeclInstantiator::VisitConceptDecl(ConceptDecl *D) {
llvm_unreachable("Concept definitions cannot reside inside a template");
}
Decl *TemplateDeclInstantiator::VisitImplicitConceptSpecializationDecl(
ImplicitConceptSpecializationDecl *D) {
llvm_unreachable("Concept specializations cannot reside inside a template");
}
Decl *
TemplateDeclInstantiator::VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D) {
return RequiresExprBodyDecl::Create(SemaRef.Context, D->getDeclContext(),
D->getBeginLoc());
}
Decl *TemplateDeclInstantiator::VisitDecl(Decl *D) {
llvm_unreachable("Unexpected decl");
}
Decl *Sema::SubstDecl(Decl *D, DeclContext *Owner,
const MultiLevelTemplateArgumentList &TemplateArgs) {
TemplateDeclInstantiator Instantiator(*this, Owner, TemplateArgs);
if (D->isInvalidDecl())
return nullptr;
Decl *SubstD;
runWithSufficientStackSpace(D->getLocation(), [&] {
SubstD = Instantiator.Visit(D);
});
return SubstD;
}
void TemplateDeclInstantiator::adjustForRewrite(RewriteKind RK,
FunctionDecl *Orig, QualType &T,
TypeSourceInfo *&TInfo,
DeclarationNameInfo &NameInfo) {
assert(RK == RewriteKind::RewriteSpaceshipAsEqualEqual);
// C++2a [class.compare.default]p3:
// the return type is replaced with bool
auto *FPT = T->castAs<FunctionProtoType>();
T = SemaRef.Context.getFunctionType(
SemaRef.Context.BoolTy, FPT->getParamTypes(), FPT->getExtProtoInfo());
// Update the return type in the source info too. The most straightforward
// way is to create new TypeSourceInfo for the new type. Use the location of
// the '= default' as the location of the new type.
//
// FIXME: Set the correct return type when we initially transform the type,
// rather than delaying it to now.
TypeSourceInfo *NewTInfo =
SemaRef.Context.getTrivialTypeSourceInfo(T, Orig->getEndLoc());
auto OldLoc = TInfo->getTypeLoc().getAsAdjusted<FunctionProtoTypeLoc>();
assert(OldLoc && "type of function is not a function type?");
auto NewLoc = NewTInfo->getTypeLoc().castAs<FunctionProtoTypeLoc>();
for (unsigned I = 0, N = OldLoc.getNumParams(); I != N; ++I)
NewLoc.setParam(I, OldLoc.getParam(I));
TInfo = NewTInfo;
// and the declarator-id is replaced with operator==
NameInfo.setName(
SemaRef.Context.DeclarationNames.getCXXOperatorName(OO_EqualEqual));
}
FunctionDecl *Sema::SubstSpaceshipAsEqualEqual(CXXRecordDecl *RD,
FunctionDecl *Spaceship) {
if (Spaceship->isInvalidDecl())
return nullptr;
// C++2a [class.compare.default]p3:
// an == operator function is declared implicitly [...] with the same
// access and function-definition and in the same class scope as the
// three-way comparison operator function
MultiLevelTemplateArgumentList NoTemplateArgs;
NoTemplateArgs.setKind(TemplateSubstitutionKind::Rewrite);
NoTemplateArgs.addOuterRetainedLevels(RD->getTemplateDepth());
TemplateDeclInstantiator Instantiator(*this, RD, NoTemplateArgs);
Decl *R;
if (auto *MD = dyn_cast<CXXMethodDecl>(Spaceship)) {
R = Instantiator.VisitCXXMethodDecl(
MD, /*TemplateParams=*/nullptr,
TemplateDeclInstantiator::RewriteKind::RewriteSpaceshipAsEqualEqual);
} else {
assert(Spaceship->getFriendObjectKind() &&
"defaulted spaceship is neither a member nor a friend");
R = Instantiator.VisitFunctionDecl(
Spaceship, /*TemplateParams=*/nullptr,
TemplateDeclInstantiator::RewriteKind::RewriteSpaceshipAsEqualEqual);
if (!R)
return nullptr;
FriendDecl *FD =
FriendDecl::Create(Context, RD, Spaceship->getLocation(),
cast<NamedDecl>(R), Spaceship->getBeginLoc());
FD->setAccess(AS_public);
RD->addDecl(FD);
}
return cast_or_null<FunctionDecl>(R);
}
/// Instantiates a nested template parameter list in the current
/// instantiation context.
///
/// \param L The parameter list to instantiate
///
/// \returns NULL if there was an error
TemplateParameterList *
TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) {
// Get errors for all the parameters before bailing out.
bool Invalid = false;
unsigned N = L->size();
typedef SmallVector<NamedDecl *, 8> ParamVector;
ParamVector Params;
Params.reserve(N);
for (auto &P : *L) {
NamedDecl *D = cast_or_null<NamedDecl>(Visit(P));
Params.push_back(D);
Invalid = Invalid || !D || D->isInvalidDecl();
}
// Clean up if we had an error.
if (Invalid)
return nullptr;
Expr *InstRequiresClause = L->getRequiresClause();
TemplateParameterList *InstL
= TemplateParameterList::Create(SemaRef.Context, L->getTemplateLoc(),
L->getLAngleLoc(), Params,
L->getRAngleLoc(), InstRequiresClause);
return InstL;
}
TemplateParameterList *
Sema::SubstTemplateParams(TemplateParameterList *Params, DeclContext *Owner,
const MultiLevelTemplateArgumentList &TemplateArgs,
bool EvaluateConstraints) {
TemplateDeclInstantiator Instantiator(*this, Owner, TemplateArgs);
Instantiator.setEvaluateConstraints(EvaluateConstraints);
return Instantiator.SubstTemplateParams(Params);
}
/// Instantiate the declaration of a class template partial
/// specialization.
///
/// \param ClassTemplate the (instantiated) class template that is partially
// specialized by the instantiation of \p PartialSpec.
///
/// \param PartialSpec the (uninstantiated) class template partial
/// specialization that we are instantiating.
///
/// \returns The instantiated partial specialization, if successful; otherwise,
/// NULL to indicate an error.
ClassTemplatePartialSpecializationDecl *
TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
ClassTemplateDecl *ClassTemplate,
ClassTemplatePartialSpecializationDecl *PartialSpec) {
// Create a local instantiation scope for this class template partial
// specialization, which will contain the instantiations of the template
// parameters.
LocalInstantiationScope Scope(SemaRef);
// Substitute into the template parameters of the class template partial
// specialization.
TemplateParameterList *TempParams = PartialSpec->getTemplateParameters();
TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
if (!InstParams)
return nullptr;
// Substitute into the template arguments of the class template partial
// specialization.
const ASTTemplateArgumentListInfo *TemplArgInfo
= PartialSpec->getTemplateArgsAsWritten();
TemplateArgumentListInfo InstTemplateArgs(TemplArgInfo->LAngleLoc,
TemplArgInfo->RAngleLoc);
if (SemaRef.SubstTemplateArguments(TemplArgInfo->arguments(), TemplateArgs,
InstTemplateArgs))
return nullptr;
// Check that the template argument list is well-formed for this
// class template.
Sema::CheckTemplateArgumentInfo CTAI;
if (SemaRef.CheckTemplateArgumentList(
ClassTemplate, PartialSpec->getLocation(), InstTemplateArgs,
/*DefaultArgs=*/{},
/*PartialTemplateArgs=*/false, CTAI))
return nullptr;
// Check these arguments are valid for a template partial specialization.
if (SemaRef.CheckTemplatePartialSpecializationArgs(
PartialSpec->getLocation(), ClassTemplate, InstTemplateArgs.size(),
CTAI.CanonicalConverted))
return nullptr;
// Figure out where to insert this class template partial specialization
// in the member template's set of class template partial specializations.
void *InsertPos = nullptr;
ClassTemplateSpecializationDecl *PrevDecl =
ClassTemplate->findPartialSpecialization(CTAI.CanonicalConverted,
InstParams, InsertPos);
// Build the type that describes the converted template arguments of the class
// template partial specialization.
TypeSourceInfo *WrittenTy = SemaRef.Context.getTemplateSpecializationTypeInfo(
TemplateName(ClassTemplate), TemplArgInfo->getLAngleLoc(),
InstTemplateArgs, CTAI.CanonicalConverted);
// Create the class template partial specialization declaration.
ClassTemplatePartialSpecializationDecl *InstPartialSpec =
ClassTemplatePartialSpecializationDecl::Create(
SemaRef.Context, PartialSpec->getTagKind(), Owner,
PartialSpec->getBeginLoc(), PartialSpec->getLocation(), InstParams,
ClassTemplate, CTAI.CanonicalConverted, WrittenTy->getType(),
/*PrevDecl=*/nullptr);
InstPartialSpec->setTemplateArgsAsWritten(InstTemplateArgs);
// Substitute the nested name specifier, if any.
if (SubstQualifier(PartialSpec, InstPartialSpec))
return nullptr;
InstPartialSpec->setInstantiatedFromMember(PartialSpec);
if (PrevDecl) {
// We've already seen a partial specialization with the same template
// parameters and template arguments. This can happen, for example, when
// substituting the outer template arguments ends up causing two
// class template partial specializations of a member class template
// to have identical forms, e.g.,
//
// template<typename T, typename U>
// struct Outer {
// template<typename X, typename Y> struct Inner;
// template<typename Y> struct Inner<T, Y>;
// template<typename Y> struct Inner<U, Y>;
// };
//
// Outer<int, int> outer; // error: the partial specializations of Inner
// // have the same signature.
SemaRef.Diag(InstPartialSpec->getLocation(),
diag::err_partial_spec_redeclared)
<< InstPartialSpec;
SemaRef.Diag(PrevDecl->getLocation(), diag::note_prev_partial_spec_here)
<< SemaRef.Context.getTypeDeclType(PrevDecl);
return nullptr;
}
// Check the completed partial specialization.
SemaRef.CheckTemplatePartialSpecialization(InstPartialSpec);
// Add this partial specialization to the set of class template partial
// specializations.
ClassTemplate->AddPartialSpecialization(InstPartialSpec,
/*InsertPos=*/nullptr);
return InstPartialSpec;
}
/// Instantiate the declaration of a variable template partial
/// specialization.
///
/// \param VarTemplate the (instantiated) variable template that is partially
/// specialized by the instantiation of \p PartialSpec.
///
/// \param PartialSpec the (uninstantiated) variable template partial
/// specialization that we are instantiating.
///
/// \returns The instantiated partial specialization, if successful; otherwise,
/// NULL to indicate an error.
VarTemplatePartialSpecializationDecl *
TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization(
VarTemplateDecl *VarTemplate,
VarTemplatePartialSpecializationDecl *PartialSpec) {
// Create a local instantiation scope for this variable template partial
// specialization, which will contain the instantiations of the template
// parameters.
LocalInstantiationScope Scope(SemaRef);
// Substitute into the template parameters of the variable template partial
// specialization.
TemplateParameterList *TempParams = PartialSpec->getTemplateParameters();
TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
if (!InstParams)
return nullptr;
// Substitute into the template arguments of the variable template partial
// specialization.
const ASTTemplateArgumentListInfo *TemplArgInfo
= PartialSpec->getTemplateArgsAsWritten();
TemplateArgumentListInfo InstTemplateArgs(TemplArgInfo->LAngleLoc,
TemplArgInfo->RAngleLoc);
if (SemaRef.SubstTemplateArguments(TemplArgInfo->arguments(), TemplateArgs,
InstTemplateArgs))
return nullptr;
// Check that the template argument list is well-formed for this
// class template.
Sema::CheckTemplateArgumentInfo CTAI;
if (SemaRef.CheckTemplateArgumentList(VarTemplate, PartialSpec->getLocation(),
InstTemplateArgs, /*DefaultArgs=*/{},
/*PartialTemplateArgs=*/false, CTAI))
return nullptr;
// Check these arguments are valid for a template partial specialization.
if (SemaRef.CheckTemplatePartialSpecializationArgs(
PartialSpec->getLocation(), VarTemplate, InstTemplateArgs.size(),
CTAI.CanonicalConverted))
return nullptr;
// Figure out where to insert this variable template partial specialization
// in the member template's set of variable template partial specializations.
void *InsertPos = nullptr;
VarTemplateSpecializationDecl *PrevDecl =
VarTemplate->findPartialSpecialization(CTAI.CanonicalConverted,
InstParams, InsertPos);
// Do substitution on the type of the declaration
TypeSourceInfo *DI = SemaRef.SubstType(
PartialSpec->getTypeSourceInfo(), TemplateArgs,
PartialSpec->getTypeSpecStartLoc(), PartialSpec->getDeclName());
if (!DI)
return nullptr;
if (DI->getType()->isFunctionType()) {
SemaRef.Diag(PartialSpec->getLocation(),
diag::err_variable_instantiates_to_function)
<< PartialSpec->isStaticDataMember() << DI->getType();
return nullptr;
}
// Create the variable template partial specialization declaration.
VarTemplatePartialSpecializationDecl *InstPartialSpec =
VarTemplatePartialSpecializationDecl::Create(
SemaRef.Context, Owner, PartialSpec->getInnerLocStart(),
PartialSpec->getLocation(), InstParams, VarTemplate, DI->getType(),
DI, PartialSpec->getStorageClass(), CTAI.CanonicalConverted);
InstPartialSpec->setTemplateArgsAsWritten(InstTemplateArgs);
// Substitute the nested name specifier, if any.
if (SubstQualifier(PartialSpec, InstPartialSpec))
return nullptr;
InstPartialSpec->setInstantiatedFromMember(PartialSpec);
if (PrevDecl) {
// We've already seen a partial specialization with the same template
// parameters and template arguments. This can happen, for example, when
// substituting the outer template arguments ends up causing two
// variable template partial specializations of a member variable template
// to have identical forms, e.g.,
//
// template<typename T, typename U>
// struct Outer {
// template<typename X, typename Y> pair<X,Y> p;
// template<typename Y> pair<T, Y> p;
// template<typename Y> pair<U, Y> p;
// };
//
// Outer<int, int> outer; // error: the partial specializations of Inner
// // have the same signature.
SemaRef.Diag(PartialSpec->getLocation(),
diag::err_var_partial_spec_redeclared)
<< InstPartialSpec;
SemaRef.Diag(PrevDecl->getLocation(),
diag::note_var_prev_partial_spec_here);
return nullptr;
}
// Check the completed partial specialization.
SemaRef.CheckTemplatePartialSpecialization(InstPartialSpec);
// Add this partial specialization to the set of variable template partial
// specializations. The instantiation of the initializer is not necessary.
VarTemplate->AddPartialSpecialization(InstPartialSpec, /*InsertPos=*/nullptr);
SemaRef.BuildVariableInstantiation(InstPartialSpec, PartialSpec, TemplateArgs,
LateAttrs, Owner, StartingScope);
return InstPartialSpec;
}
TypeSourceInfo*
TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
SmallVectorImpl<ParmVarDecl *> &Params) {
TypeSourceInfo *OldTInfo = D->getTypeSourceInfo();
assert(OldTInfo && "substituting function without type source info");
assert(Params.empty() && "parameter vector is non-empty at start");
CXXRecordDecl *ThisContext = nullptr;
Qualifiers ThisTypeQuals;
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
ThisContext = cast<CXXRecordDecl>(Owner);
ThisTypeQuals = Method->getFunctionObjectParameterType().getQualifiers();
}
TypeSourceInfo *NewTInfo = SemaRef.SubstFunctionDeclType(
OldTInfo, TemplateArgs, D->getTypeSpecStartLoc(), D->getDeclName(),
ThisContext, ThisTypeQuals, EvaluateConstraints);
if (!NewTInfo)
return nullptr;
TypeLoc OldTL = OldTInfo->getTypeLoc().IgnoreParens();
if (FunctionProtoTypeLoc OldProtoLoc = OldTL.getAs<FunctionProtoTypeLoc>()) {
if (NewTInfo != OldTInfo) {
// Get parameters from the new type info.
TypeLoc NewTL = NewTInfo->getTypeLoc().IgnoreParens();
FunctionProtoTypeLoc NewProtoLoc = NewTL.castAs<FunctionProtoTypeLoc>();
unsigned NewIdx = 0;
for (unsigned OldIdx = 0, NumOldParams = OldProtoLoc.getNumParams();
OldIdx != NumOldParams; ++OldIdx) {
ParmVarDecl *OldParam = OldProtoLoc.getParam(OldIdx);
if (!OldParam)
return nullptr;
LocalInstantiationScope *Scope = SemaRef.CurrentInstantiationScope;
UnsignedOrNone NumArgumentsInExpansion = std::nullopt;
if (OldParam->isParameterPack())
NumArgumentsInExpansion =
SemaRef.getNumArgumentsInExpansion(OldParam->getType(),
TemplateArgs);
if (!NumArgumentsInExpansion) {
// Simple case: normal parameter, or a parameter pack that's
// instantiated to a (still-dependent) parameter pack.
ParmVarDecl *NewParam = NewProtoLoc.getParam(NewIdx++);
Params.push_back(NewParam);
Scope->InstantiatedLocal(OldParam, NewParam);
} else {
// Parameter pack expansion: make the instantiation an argument pack.
Scope->MakeInstantiatedLocalArgPack(OldParam);
for (unsigned I = 0; I != *NumArgumentsInExpansion; ++I) {
ParmVarDecl *NewParam = NewProtoLoc.getParam(NewIdx++);
Params.push_back(NewParam);
Scope->InstantiatedLocalPackArg(OldParam, NewParam);
}
}
}
} else {
// The function type itself was not dependent and therefore no
// substitution occurred. However, we still need to instantiate
// the function parameters themselves.
const FunctionProtoType *OldProto =
cast<FunctionProtoType>(OldProtoLoc.getType());
for (unsigned i = 0, i_end = OldProtoLoc.getNumParams(); i != i_end;
++i) {
ParmVarDecl *OldParam = OldProtoLoc.getParam(i);
if (!OldParam) {
Params.push_back(SemaRef.BuildParmVarDeclForTypedef(
D, D->getLocation(), OldProto->getParamType(i)));
continue;
}
ParmVarDecl *Parm =
cast_or_null<ParmVarDecl>(VisitParmVarDecl(OldParam));
if (!Parm)
return nullptr;
Params.push_back(Parm);
}
}
} else {
// If the type of this function, after ignoring parentheses, is not
// *directly* a function type, then we're instantiating a function that
// was declared via a typedef or with attributes, e.g.,
//
// typedef int functype(int, int);
// functype func;
// int __cdecl meth(int, int);
//
// In this case, we'll just go instantiate the ParmVarDecls that we
// synthesized in the method declaration.
SmallVector<QualType, 4> ParamTypes;
Sema::ExtParameterInfoBuilder ExtParamInfos;
if (SemaRef.SubstParmTypes(D->getLocation(), D->parameters(), nullptr,
TemplateArgs, ParamTypes, &Params,
ExtParamInfos))
return nullptr;
}
return NewTInfo;
}
void Sema::addInstantiatedLocalVarsToScope(FunctionDecl *Function,
const FunctionDecl *PatternDecl,
LocalInstantiationScope &Scope) {
LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(getFunctionScopes().back());
for (auto *decl : PatternDecl->decls()) {
if (!isa<VarDecl>(decl) || isa<ParmVarDecl>(decl))
continue;
VarDecl *VD = cast<VarDecl>(decl);
IdentifierInfo *II = VD->getIdentifier();
auto it = llvm::find_if(Function->decls(), [&](Decl *inst) {
VarDecl *InstVD = dyn_cast<VarDecl>(inst);
return InstVD && InstVD->isLocalVarDecl() &&
InstVD->getIdentifier() == II;
});
if (it == Function->decls().end())
continue;
Scope.InstantiatedLocal(VD, *it);
LSI->addCapture(cast<VarDecl>(*it), /*isBlock=*/false, /*isByref=*/false,
/*isNested=*/false, VD->getLocation(), SourceLocation(),
VD->getType(), /*Invalid=*/false);
}
}
bool Sema::addInstantiatedParametersToScope(
FunctionDecl *Function, const FunctionDecl *PatternDecl,
LocalInstantiationScope &Scope,
const MultiLevelTemplateArgumentList &TemplateArgs) {
unsigned FParamIdx = 0;
for (unsigned I = 0, N = PatternDecl->getNumParams(); I != N; ++I) {
const ParmVarDecl *PatternParam = PatternDecl->getParamDecl(I);
if (!PatternParam->isParameterPack()) {
// Simple case: not a parameter pack.
assert(FParamIdx < Function->getNumParams());
ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx);
FunctionParam->setDeclName(PatternParam->getDeclName());
// If the parameter's type is not dependent, update it to match the type
// in the pattern. They can differ in top-level cv-qualifiers, and we want
// the pattern's type here. If the type is dependent, they can't differ,
// per core issue 1668. Substitute into the type from the pattern, in case
// it's instantiation-dependent.
// FIXME: Updating the type to work around this is at best fragile.
if (!PatternDecl->getType()->isDependentType()) {
QualType T = SubstType(PatternParam->getType(), TemplateArgs,
FunctionParam->getLocation(),
FunctionParam->getDeclName());
if (T.isNull())
return true;
FunctionParam->setType(T);
}
Scope.InstantiatedLocal(PatternParam, FunctionParam);
++FParamIdx;
continue;
}
// Expand the parameter pack.
Scope.MakeInstantiatedLocalArgPack(PatternParam);
UnsignedOrNone NumArgumentsInExpansion =
getNumArgumentsInExpansion(PatternParam->getType(), TemplateArgs);
if (NumArgumentsInExpansion) {
QualType PatternType =
PatternParam->getType()->castAs<PackExpansionType>()->getPattern();
for (unsigned Arg = 0; Arg < *NumArgumentsInExpansion; ++Arg) {
ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx);
FunctionParam->setDeclName(PatternParam->getDeclName());
if (!PatternDecl->getType()->isDependentType()) {
Sema::ArgPackSubstIndexRAII SubstIndex(*this, Arg);
QualType T =
SubstType(PatternType, TemplateArgs, FunctionParam->getLocation(),
FunctionParam->getDeclName());
if (T.isNull())
return true;
FunctionParam->setType(T);
}
Scope.InstantiatedLocalPackArg(PatternParam, FunctionParam);
++FParamIdx;
}
}
}
return false;
}
bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD,
ParmVarDecl *Param) {
assert(Param->hasUninstantiatedDefaultArg());
// FIXME: We don't track member specialization info for non-defining
// friend declarations, so we will not be able to later find the function
// pattern. As a workaround, don't instantiate the default argument in this
// case. This is correct per the standard and only an issue for recovery
// purposes. [dcl.fct.default]p4:
// if a friend declaration D specifies a default argument expression,
// that declaration shall be a definition.
if (FD->getFriendObjectKind() != Decl::FOK_None &&
!FD->getTemplateInstantiationPattern())
return true;
// Instantiate the expression.
//
// FIXME: Pass in a correct Pattern argument, otherwise
// getTemplateInstantiationArgs uses the lexical context of FD, e.g.
//
// template<typename T>
// struct A {
// static int FooImpl();
//
// template<typename Tp>
// // bug: default argument A<T>::FooImpl() is evaluated with 2-level
// // template argument list [[T], [Tp]], should be [[Tp]].
// friend A<Tp> Foo(int a);
// };
//
// template<typename T>
// A<T> Foo(int a = A<T>::FooImpl());
MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
FD, FD->getLexicalDeclContext(),
/*Final=*/false, /*Innermost=*/std::nullopt,
/*RelativeToPrimary=*/true, /*Pattern=*/nullptr,
/*ForConstraintInstantiation=*/false, /*SkipForSpecialization=*/false,
/*ForDefaultArgumentSubstitution=*/true);
if (SubstDefaultArgument(CallLoc, Param, TemplateArgs, /*ForCallExpr*/ true))
return true;
if (ASTMutationListener *L = getASTMutationListener())
L->DefaultArgumentInstantiated(Param);
return false;
}
void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
FunctionDecl *Decl) {
const FunctionProtoType *Proto = Decl->getType()->castAs<FunctionProtoType>();
if (Proto->getExceptionSpecType() != EST_Uninstantiated)
return;
InstantiatingTemplate Inst(*this, PointOfInstantiation, Decl,
InstantiatingTemplate::ExceptionSpecification());
if (Inst.isInvalid()) {
// We hit the instantiation depth limit. Clear the exception specification
// so that our callers don't have to cope with EST_Uninstantiated.
UpdateExceptionSpec(Decl, EST_None);
return;
}
if (Inst.isAlreadyInstantiating()) {
// This exception specification indirectly depends on itself. Reject.
// FIXME: Corresponding rule in the standard?
Diag(PointOfInstantiation, diag::err_exception_spec_cycle) << Decl;
UpdateExceptionSpec(Decl, EST_None);
return;
}
// Enter the scope of this instantiation. We don't use
// PushDeclContext because we don't have a scope.
Sema::ContextRAII savedContext(*this, Decl);
LocalInstantiationScope Scope(*this);
MultiLevelTemplateArgumentList TemplateArgs =
getTemplateInstantiationArgs(Decl, Decl->getLexicalDeclContext(),
/*Final=*/false, /*Innermost=*/std::nullopt,
/*RelativeToPrimary*/ true);
// FIXME: We can't use getTemplateInstantiationPattern(false) in general
// here, because for a non-defining friend declaration in a class template,
// we don't store enough information to map back to the friend declaration in
// the template.
FunctionDecl *Template = Proto->getExceptionSpecTemplate();
if (addInstantiatedParametersToScope(Decl, Template, Scope, TemplateArgs)) {
UpdateExceptionSpec(Decl, EST_None);
return;
}
// The noexcept specification could reference any lambda captures. Ensure
// those are added to the LocalInstantiationScope.
LambdaScopeForCallOperatorInstantiationRAII PushLambdaCaptures(
*this, Decl, TemplateArgs, Scope,
/*ShouldAddDeclsFromParentScope=*/false);
SubstExceptionSpec(Decl, Template->getType()->castAs<FunctionProtoType>(),
TemplateArgs);
}
/// Initializes the common fields of an instantiation function
/// declaration (New) from the corresponding fields of its template (Tmpl).
///
/// \returns true if there was an error
bool
TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
FunctionDecl *Tmpl) {
New->setImplicit(Tmpl->isImplicit());
// Forward the mangling number from the template to the instantiated decl.
SemaRef.Context.setManglingNumber(New,
SemaRef.Context.getManglingNumber(Tmpl));
// If we are performing substituting explicitly-specified template arguments
// or deduced template arguments into a function template and we reach this
// point, we are now past the point where SFINAE applies and have committed
// to keeping the new function template specialization. We therefore
// convert the active template instantiation for the function template
// into a template instantiation for this specific function template
// specialization, which is not a SFINAE context, so that we diagnose any
// further errors in the declaration itself.
//
// FIXME: This is a hack.
typedef Sema::CodeSynthesisContext ActiveInstType;
ActiveInstType &ActiveInst = SemaRef.CodeSynthesisContexts.back();
if (ActiveInst.Kind == ActiveInstType::ExplicitTemplateArgumentSubstitution ||
ActiveInst.Kind == ActiveInstType::DeducedTemplateArgumentSubstitution) {
if (isa<FunctionTemplateDecl>(ActiveInst.Entity)) {
SemaRef.InstantiatingSpecializations.erase(
{ActiveInst.Entity->getCanonicalDecl(), ActiveInst.Kind});
atTemplateEnd(SemaRef.TemplateInstCallbacks, SemaRef, ActiveInst);
ActiveInst.Kind = ActiveInstType::TemplateInstantiation;
ActiveInst.Entity = New;
atTemplateBegin(SemaRef.TemplateInstCallbacks, SemaRef, ActiveInst);
}
}
const FunctionProtoType *Proto = Tmpl->getType()->getAs<FunctionProtoType>();
assert(Proto && "Function template without prototype?");
if (Proto->hasExceptionSpec() || Proto->getNoReturnAttr()) {
FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo();
// DR1330: In C++11, defer instantiation of a non-trivial
// exception specification.
// DR1484: Local classes and their members are instantiated along with the
// containing function.
if (SemaRef.getLangOpts().CPlusPlus11 &&
EPI.ExceptionSpec.Type != EST_None &&
EPI.ExceptionSpec.Type != EST_DynamicNone &&
EPI.ExceptionSpec.Type != EST_BasicNoexcept &&
!Tmpl->isInLocalScopeForInstantiation()) {
FunctionDecl *ExceptionSpecTemplate = Tmpl;
if (EPI.ExceptionSpec.Type == EST_Uninstantiated)
ExceptionSpecTemplate = EPI.ExceptionSpec.SourceTemplate;
ExceptionSpecificationType NewEST = EST_Uninstantiated;
if (EPI.ExceptionSpec.Type == EST_Unevaluated)
NewEST = EST_Unevaluated;
// Mark the function has having an uninstantiated exception specification.
const FunctionProtoType *NewProto
= New->getType()->getAs<FunctionProtoType>();
assert(NewProto && "Template instantiation without function prototype?");
EPI = NewProto->getExtProtoInfo();
EPI.ExceptionSpec.Type = NewEST;
EPI.ExceptionSpec.SourceDecl = New;
EPI.ExceptionSpec.SourceTemplate = ExceptionSpecTemplate;
New->setType(SemaRef.Context.getFunctionType(
NewProto->getReturnType(), NewProto->getParamTypes(), EPI));
} else {
Sema::ContextRAII SwitchContext(SemaRef, New);
SemaRef.SubstExceptionSpec(New, Proto, TemplateArgs);
}
}
// Get the definition. Leaves the variable unchanged if undefined.
const FunctionDecl *Definition = Tmpl;
Tmpl->isDefined(Definition);
SemaRef.InstantiateAttrs(TemplateArgs, Definition, New,
LateAttrs, StartingScope);
return false;
}
/// Initializes common fields of an instantiated method
/// declaration (New) from the corresponding fields of its template
/// (Tmpl).
///
/// \returns true if there was an error
bool
TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New,
CXXMethodDecl *Tmpl) {
if (InitFunctionInstantiation(New, Tmpl))
return true;
if (isa<CXXDestructorDecl>(New) && SemaRef.getLangOpts().CPlusPlus11)
SemaRef.AdjustDestructorExceptionSpec(cast<CXXDestructorDecl>(New));
New->setAccess(Tmpl->getAccess());
if (Tmpl->isVirtualAsWritten())
New->setVirtualAsWritten(true);
// FIXME: New needs a pointer to Tmpl
return false;
}
bool TemplateDeclInstantiator::SubstDefaultedFunction(FunctionDecl *New,
FunctionDecl *Tmpl) {
// Transfer across any unqualified lookups.
if (auto *DFI = Tmpl->getDefalutedOrDeletedInfo()) {
SmallVector<DeclAccessPair, 32> Lookups;
Lookups.reserve(DFI->getUnqualifiedLookups().size());
bool AnyChanged = false;
for (DeclAccessPair DA : DFI->getUnqualifiedLookups()) {
NamedDecl *D = SemaRef.FindInstantiatedDecl(New->getLocation(),
DA.getDecl(), TemplateArgs);
if (!D)
return true;
AnyChanged |= (D != DA.getDecl());
Lookups.push_back(DeclAccessPair::make(D, DA.getAccess()));
}
// It's unlikely that substitution will change any declarations. Don't
// store an unnecessary copy in that case.
New->setDefaultedOrDeletedInfo(
AnyChanged ? FunctionDecl::DefaultedOrDeletedFunctionInfo::Create(
SemaRef.Context, Lookups)
: DFI);
}
SemaRef.SetDeclDefaulted(New, Tmpl->getLocation());
return false;
}
FunctionDecl *Sema::InstantiateFunctionDeclaration(
FunctionTemplateDecl *FTD, const TemplateArgumentList *Args,
SourceLocation Loc, CodeSynthesisContext::SynthesisKind CSC) {
FunctionDecl *FD = FTD->getTemplatedDecl();
sema::TemplateDeductionInfo Info(Loc);
InstantiatingTemplate Inst(*this, Loc, FTD, Args->asArray(), CSC, Info);
if (Inst.isInvalid())
return nullptr;
ContextRAII SavedContext(*this, FD);
MultiLevelTemplateArgumentList MArgs(FTD, Args->asArray(),
/*Final=*/false);
return cast_or_null<FunctionDecl>(SubstDecl(FD, FD->getParent(), MArgs));
}
void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
FunctionDecl *Function,
bool Recursive,
bool DefinitionRequired,
bool AtEndOfTU) {
if (Function->isInvalidDecl() || isa<CXXDeductionGuideDecl>(Function))
return;
// Never instantiate an explicit specialization except if it is a class scope
// explicit specialization.
TemplateSpecializationKind TSK =
Function->getTemplateSpecializationKindForInstantiation();
if (TSK == TSK_ExplicitSpecialization)
return;
// Never implicitly instantiate a builtin; we don't actually need a function
// body.
if (Function->getBuiltinID() && TSK == TSK_ImplicitInstantiation &&
!DefinitionRequired)
return;
// Don't instantiate a definition if we already have one.
const FunctionDecl *ExistingDefn = nullptr;
if (Function->isDefined(ExistingDefn,
/*CheckForPendingFriendDefinition=*/true)) {
if (ExistingDefn->isThisDeclarationADefinition())
return;
// If we're asked to instantiate a function whose body comes from an
// instantiated friend declaration, attach the instantiated body to the
// corresponding declaration of the function.
assert(ExistingDefn->isThisDeclarationInstantiatedFromAFriendDefinition());
Function = const_cast<FunctionDecl*>(ExistingDefn);
}
// Find the function body that we'll be substituting.
const FunctionDecl *PatternDecl = Function->getTemplateInstantiationPattern();
assert(PatternDecl && "instantiating a non-template");
const FunctionDecl *PatternDef = PatternDecl->getDefinition();
Stmt *Pattern = nullptr;
if (PatternDef) {
Pattern = PatternDef->getBody(PatternDef);
PatternDecl = PatternDef;
if (PatternDef->willHaveBody())
PatternDef = nullptr;
}
// True is the template definition is unreachable, otherwise false.
bool Unreachable = false;
// FIXME: We need to track the instantiation stack in order to know which
// definitions should be visible within this instantiation.
if (DiagnoseUninstantiableTemplate(
PointOfInstantiation, Function,
Function->getInstantiatedFromMemberFunction(), PatternDecl,
PatternDef, TSK,
/*Complain*/ DefinitionRequired, &Unreachable)) {
if (DefinitionRequired)
Function->setInvalidDecl();
else if (TSK == TSK_ExplicitInstantiationDefinition ||
(Function->isConstexpr() && !Recursive)) {
// Try again at the end of the translation unit (at which point a
// definition will be required).
assert(!Recursive);
Function->setInstantiationIsPending(true);
PendingInstantiations.push_back(
std::make_pair(Function, PointOfInstantiation));
if (llvm::isTimeTraceVerbose()) {
llvm::timeTraceAddInstantEvent("DeferInstantiation", [&] {
std::string Name;
llvm::raw_string_ostream OS(Name);
Function->getNameForDiagnostic(OS, getPrintingPolicy(),
/*Qualified=*/true);
return Name;
});
}
} else if (TSK == TSK_ImplicitInstantiation) {
if (AtEndOfTU && !getDiagnostics().hasErrorOccurred() &&
!getSourceManager().isInSystemHeader(PatternDecl->getBeginLoc())) {
Diag(PointOfInstantiation, diag::warn_func_template_missing)
<< Function;
if (Unreachable) {
// FIXME: would be nice to mention which module the function template
// comes from.
Diag(PatternDecl->getLocation(),
diag::note_unreachable_template_decl);
} else {
Diag(PatternDecl->getLocation(), diag::note_forward_template_decl);
if (getLangOpts().CPlusPlus11)
Diag(PointOfInstantiation, diag::note_inst_declaration_hint)
<< Function;
}
}
}
return;
}
// Postpone late parsed template instantiations.
if (PatternDecl->isLateTemplateParsed() &&
!LateTemplateParser) {
Function->setInstantiationIsPending(true);
LateParsedInstantiations.push_back(
std::make_pair(Function, PointOfInstantiation));
return;
}
llvm::TimeTraceScope TimeScope("InstantiateFunction", [&]() {
llvm::TimeTraceMetadata M;
llvm::raw_string_ostream OS(M.Detail);
Function->getNameForDiagnostic(OS, getPrintingPolicy(),
/*Qualified=*/true);
if (llvm::isTimeTraceVerbose()) {
auto Loc = SourceMgr.getExpansionLoc(Function->getLocation());
M.File = SourceMgr.getFilename(Loc);
M.Line = SourceMgr.getExpansionLineNumber(Loc);
}
return M;
});
// If we're performing recursive template instantiation, create our own
// queue of pending implicit instantiations that we will instantiate later,
// while we're still within our own instantiation context.
// This has to happen before LateTemplateParser below is called, so that
// it marks vtables used in late parsed templates as used.
GlobalEagerInstantiationScope GlobalInstantiations(*this,
/*Enabled=*/Recursive,
/*AtEndOfTU=*/AtEndOfTU);
LocalEagerInstantiationScope LocalInstantiations(*this,
/*AtEndOfTU=*/AtEndOfTU);
// Call the LateTemplateParser callback if there is a need to late parse
// a templated function definition.
if (!Pattern && PatternDecl->isLateTemplateParsed() &&
LateTemplateParser) {
// FIXME: Optimize to allow individual templates to be deserialized.
if (PatternDecl->isFromASTFile())
ExternalSource->ReadLateParsedTemplates(LateParsedTemplateMap);
auto LPTIter = LateParsedTemplateMap.find(PatternDecl);
assert(LPTIter != LateParsedTemplateMap.end() &&
"missing LateParsedTemplate");
LateTemplateParser(OpaqueParser, *LPTIter->second);
Pattern = PatternDecl->getBody(PatternDecl);
updateAttrsForLateParsedTemplate(PatternDecl, Function);
}
// Note, we should never try to instantiate a deleted function template.
assert((Pattern || PatternDecl->isDefaulted() ||
PatternDecl->hasSkippedBody()) &&
"unexpected kind of function template definition");
// C++1y [temp.explicit]p10:
// Except for inline functions, declarations with types deduced from their
// initializer or return value, and class template specializations, other
// explicit instantiation declarations have the effect of suppressing the
// implicit instantiation of the entity to which they refer.
if (TSK == TSK_ExplicitInstantiationDeclaration &&
!PatternDecl->isInlined() &&
!PatternDecl->getReturnType()->getContainedAutoType())
return;
if (PatternDecl->isInlined()) {
// Function, and all later redeclarations of it (from imported modules,
// for instance), are now implicitly inline.
for (auto *D = Function->getMostRecentDecl(); /**/;
D = D->getPreviousDecl()) {
D->setImplicitlyInline();
if (D == Function)
break;
}
}
InstantiatingTemplate Inst(*this, PointOfInstantiation, Function);
if (Inst.isInvalid() || Inst.isAlreadyInstantiating())
return;
PrettyDeclStackTraceEntry CrashInfo(Context, Function, SourceLocation(),
"instantiating function definition");
// The instantiation is visible here, even if it was first declared in an
// unimported module.
Function->setVisibleDespiteOwningModule();
// Copy the source locations from the pattern.
Function->setLocation(PatternDecl->getLocation());
Function->setInnerLocStart(PatternDecl->getInnerLocStart());
Function->setRangeEnd(PatternDecl->getEndLoc());
Function->setDeclarationNameLoc(PatternDecl->getNameInfo().getInfo());
EnterExpressionEvaluationContext EvalContext(
*this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
Qualifiers ThisTypeQuals;
CXXRecordDecl *ThisContext = nullptr;
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Function)) {
ThisContext = Method->getParent();
ThisTypeQuals = Method->getMethodQualifiers();
}
CXXThisScopeRAII ThisScope(*this, ThisContext, ThisTypeQuals);
// Introduce a new scope where local variable instantiations will be
// recorded, unless we're actually a member function within a local
// class, in which case we need to merge our results with the parent
// scope (of the enclosing function). The exception is instantiating
// a function template specialization, since the template to be
// instantiated already has references to locals properly substituted.
bool MergeWithParentScope = false;
if (CXXRecordDecl *Rec = dyn_cast<CXXRecordDecl>(Function->getDeclContext()))
MergeWithParentScope =
Rec->isLocalClass() && !Function->isFunctionTemplateSpecialization();
LocalInstantiationScope Scope(*this, MergeWithParentScope);
auto RebuildTypeSourceInfoForDefaultSpecialMembers = [&]() {
// Special members might get their TypeSourceInfo set up w.r.t the
// PatternDecl context, in which case parameters could still be pointing
// back to the original class, make sure arguments are bound to the
// instantiated record instead.
assert(PatternDecl->isDefaulted() &&
"Special member needs to be defaulted");
auto PatternSM = getDefaultedFunctionKind(PatternDecl).asSpecialMember();
if (!(PatternSM == CXXSpecialMemberKind::CopyConstructor ||
PatternSM == CXXSpecialMemberKind::CopyAssignment ||
PatternSM == CXXSpecialMemberKind::MoveConstructor ||
PatternSM == CXXSpecialMemberKind::MoveAssignment))
return;
auto *NewRec = dyn_cast<CXXRecordDecl>(Function->getDeclContext());
const auto *PatternRec =
dyn_cast<CXXRecordDecl>(PatternDecl->getDeclContext());
if (!NewRec || !PatternRec)
return;
if (!PatternRec->isLambda())
return;
struct SpecialMemberTypeInfoRebuilder
: TreeTransform<SpecialMemberTypeInfoRebuilder> {
using Base = TreeTransform<SpecialMemberTypeInfoRebuilder>;
const CXXRecordDecl *OldDecl;
CXXRecordDecl *NewDecl;
SpecialMemberTypeInfoRebuilder(Sema &SemaRef, const CXXRecordDecl *O,
CXXRecordDecl *N)
: TreeTransform(SemaRef), OldDecl(O), NewDecl(N) {}
bool TransformExceptionSpec(SourceLocation Loc,
FunctionProtoType::ExceptionSpecInfo &ESI,
SmallVectorImpl<QualType> &Exceptions,
bool &Changed) {
return false;
}
QualType TransformRecordType(TypeLocBuilder &TLB, RecordTypeLoc TL) {
const RecordType *T = TL.getTypePtr();
RecordDecl *Record = cast_or_null<RecordDecl>(
getDerived().TransformDecl(TL.getNameLoc(), T->getDecl()));
if (Record != OldDecl)
return Base::TransformRecordType(TLB, TL);
QualType Result = getDerived().RebuildRecordType(NewDecl);
if (Result.isNull())
return QualType();
RecordTypeLoc NewTL = TLB.push<RecordTypeLoc>(Result);
NewTL.setNameLoc(TL.getNameLoc());
return Result;
}
} IR{*this, PatternRec, NewRec};
TypeSourceInfo *NewSI = IR.TransformType(Function->getTypeSourceInfo());
assert(NewSI && "Type Transform failed?");
Function->setType(NewSI->getType());
Function->setTypeSourceInfo(NewSI);
ParmVarDecl *Parm = Function->getParamDecl(0);
TypeSourceInfo *NewParmSI = IR.TransformType(Parm->getTypeSourceInfo());
assert(NewParmSI && "Type transformation failed.");
Parm->setType(NewParmSI->getType());
Parm->setTypeSourceInfo(NewParmSI);
};
if (PatternDecl->isDefaulted()) {
RebuildTypeSourceInfoForDefaultSpecialMembers();
SetDeclDefaulted(Function, PatternDecl->getLocation());
} else {
NamedDecl *ND = Function;
DeclContext *DC = ND->getLexicalDeclContext();
std::optional<ArrayRef<TemplateArgument>> Innermost;
if (auto *Primary = Function->getPrimaryTemplate();
Primary &&
!isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function) &&
Function->getTemplateSpecializationKind() !=
TSK_ExplicitSpecialization) {
auto It = llvm::find_if(Primary->redecls(),
[](const RedeclarableTemplateDecl *RTD) {
return cast<FunctionTemplateDecl>(RTD)
->isCompatibleWithDefinition();
});
assert(It != Primary->redecls().end() &&
"Should't get here without a definition");
if (FunctionDecl *Def = cast<FunctionTemplateDecl>(*It)
->getTemplatedDecl()
->getDefinition())
DC = Def->getLexicalDeclContext();
else
DC = (*It)->getLexicalDeclContext();
Innermost.emplace(Function->getTemplateSpecializationArgs()->asArray());
}
MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
Function, DC, /*Final=*/false, Innermost, false, PatternDecl);
// Substitute into the qualifier; we can get a substitution failure here
// through evil use of alias templates.
// FIXME: Is CurContext correct for this? Should we go to the (instantiation
// of the) lexical context of the pattern?
SubstQualifier(*this, PatternDecl, Function, TemplateArgs);
ActOnStartOfFunctionDef(nullptr, Function);
// Enter the scope of this instantiation. We don't use
// PushDeclContext because we don't have a scope.
Sema::ContextRAII savedContext(*this, Function);
FPFeaturesStateRAII SavedFPFeatures(*this);
CurFPFeatures = FPOptions(getLangOpts());
FpPragmaStack.CurrentValue = FPOptionsOverride();
if (addInstantiatedParametersToScope(Function, PatternDecl, Scope,
TemplateArgs))
return;
StmtResult Body;
if (PatternDecl->hasSkippedBody()) {
ActOnSkippedFunctionBody(Function);
Body = nullptr;
} else {
if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(Function)) {
// If this is a constructor, instantiate the member initializers.
InstantiateMemInitializers(Ctor, cast<CXXConstructorDecl>(PatternDecl),
TemplateArgs);
// If this is an MS ABI dllexport default constructor, instantiate any
// default arguments.
if (Context.getTargetInfo().getCXXABI().isMicrosoft() &&
Ctor->isDefaultConstructor()) {
InstantiateDefaultCtorDefaultArgs(Ctor);
}
}
// Instantiate the function body.
Body = SubstStmt(Pattern, TemplateArgs);
if (Body.isInvalid())
Function->setInvalidDecl();
}
// FIXME: finishing the function body while in an expression evaluation
// context seems wrong. Investigate more.
ActOnFinishFunctionBody(Function, Body.get(), /*IsInstantiation=*/true);
PerformDependentDiagnostics(PatternDecl, TemplateArgs);
if (auto *Listener = getASTMutationListener())
Listener->FunctionDefinitionInstantiated(Function);
savedContext.pop();
}
DeclGroupRef DG(Function);
Consumer.HandleTopLevelDecl(DG);
// This class may have local implicit instantiations that need to be
// instantiation within this scope.
LocalInstantiations.perform();
Scope.Exit();
GlobalInstantiations.perform();
}
VarTemplateSpecializationDecl *Sema::BuildVarTemplateInstantiation(
VarTemplateDecl *VarTemplate, VarDecl *FromVar,
const TemplateArgumentList *PartialSpecArgs,
const TemplateArgumentListInfo &TemplateArgsInfo,
SmallVectorImpl<TemplateArgument> &Converted,
SourceLocation PointOfInstantiation, LateInstantiatedAttrVec *LateAttrs,
LocalInstantiationScope *StartingScope) {
if (FromVar->isInvalidDecl())
return nullptr;
InstantiatingTemplate Inst(*this, PointOfInstantiation, FromVar);
if (Inst.isInvalid())
return nullptr;
// Instantiate the first declaration of the variable template: for a partial
// specialization of a static data member template, the first declaration may
// or may not be the declaration in the class; if it's in the class, we want
// to instantiate a member in the class (a declaration), and if it's outside,
// we want to instantiate a definition.
//
// If we're instantiating an explicitly-specialized member template or member
// partial specialization, don't do this. The member specialization completely
// replaces the original declaration in this case.
bool IsMemberSpec = false;
MultiLevelTemplateArgumentList MultiLevelList;
if (auto *PartialSpec =
dyn_cast<VarTemplatePartialSpecializationDecl>(FromVar)) {
assert(PartialSpecArgs);
IsMemberSpec = PartialSpec->isMemberSpecialization();
MultiLevelList.addOuterTemplateArguments(
PartialSpec, PartialSpecArgs->asArray(), /*Final=*/false);
} else {
assert(VarTemplate == FromVar->getDescribedVarTemplate());
IsMemberSpec = VarTemplate->isMemberSpecialization();
MultiLevelList.addOuterTemplateArguments(VarTemplate, Converted,
/*Final=*/false);
}
if (!IsMemberSpec)
FromVar = FromVar->getFirstDecl();
TemplateDeclInstantiator Instantiator(*this, FromVar->getDeclContext(),
MultiLevelList);
// TODO: Set LateAttrs and StartingScope ...
return cast_or_null<VarTemplateSpecializationDecl>(
Instantiator.VisitVarTemplateSpecializationDecl(
VarTemplate, FromVar, TemplateArgsInfo, Converted));
}
VarTemplateSpecializationDecl *Sema::CompleteVarTemplateSpecializationDecl(
VarTemplateSpecializationDecl *VarSpec, VarDecl *PatternDecl,
const MultiLevelTemplateArgumentList &TemplateArgs) {
assert(PatternDecl->isThisDeclarationADefinition() &&
"don't have a definition to instantiate from");
// Do substitution on the type of the declaration
TypeSourceInfo *DI =
SubstType(PatternDecl->getTypeSourceInfo(), TemplateArgs,
PatternDecl->getTypeSpecStartLoc(), PatternDecl->getDeclName());
if (!DI)
return nullptr;
// Update the type of this variable template specialization.
VarSpec->setType(DI->getType());
// Convert the declaration into a definition now.
VarSpec->setCompleteDefinition();
// Instantiate the initializer.
InstantiateVariableInitializer(VarSpec, PatternDecl, TemplateArgs);
if (getLangOpts().OpenCL)
deduceOpenCLAddressSpace(VarSpec);
return VarSpec;
}
void Sema::BuildVariableInstantiation(
VarDecl *NewVar, VarDecl *OldVar,
const MultiLevelTemplateArgumentList &TemplateArgs,
LateInstantiatedAttrVec *LateAttrs, DeclContext *Owner,
LocalInstantiationScope *StartingScope,
bool InstantiatingVarTemplate,
VarTemplateSpecializationDecl *PrevDeclForVarTemplateSpecialization) {
// Instantiating a partial specialization to produce a partial
// specialization.
bool InstantiatingVarTemplatePartialSpec =
isa<VarTemplatePartialSpecializationDecl>(OldVar) &&
isa<VarTemplatePartialSpecializationDecl>(NewVar);
// Instantiating from a variable template (or partial specialization) to
// produce a variable template specialization.
bool InstantiatingSpecFromTemplate =
isa<VarTemplateSpecializationDecl>(NewVar) &&
(OldVar->getDescribedVarTemplate() ||
isa<VarTemplatePartialSpecializationDecl>(OldVar));
// If we are instantiating a local extern declaration, the
// instantiation belongs lexically to the containing function.
// If we are instantiating a static data member defined
// out-of-line, the instantiation will have the same lexical
// context (which will be a namespace scope) as the template.
if (OldVar->isLocalExternDecl()) {
NewVar->setLocalExternDecl();
NewVar->setLexicalDeclContext(Owner);
} else if (OldVar->isOutOfLine())
NewVar->setLexicalDeclContext(OldVar->getLexicalDeclContext());
NewVar->setTSCSpec(OldVar->getTSCSpec());
NewVar->setInitStyle(OldVar->getInitStyle());
NewVar->setCXXForRangeDecl(OldVar->isCXXForRangeDecl());
NewVar->setObjCForDecl(OldVar->isObjCForDecl());
NewVar->setConstexpr(OldVar->isConstexpr());
NewVar->setInitCapture(OldVar->isInitCapture());
NewVar->setPreviousDeclInSameBlockScope(
OldVar->isPreviousDeclInSameBlockScope());
NewVar->setAccess(OldVar->getAccess());
if (!OldVar->isStaticDataMember()) {
if (OldVar->isUsed(false))
NewVar->setIsUsed();
NewVar->setReferenced(OldVar->isReferenced());
}
InstantiateAttrs(TemplateArgs, OldVar, NewVar, LateAttrs, StartingScope);
LookupResult Previous(
*this, NewVar->getDeclName(), NewVar->getLocation(),
NewVar->isLocalExternDecl() ? Sema::LookupRedeclarationWithLinkage
: Sema::LookupOrdinaryName,
NewVar->isLocalExternDecl() ? RedeclarationKind::ForExternalRedeclaration
: forRedeclarationInCurContext());
if (NewVar->isLocalExternDecl() && OldVar->getPreviousDecl() &&
(!OldVar->getPreviousDecl()->getDeclContext()->isDependentContext() ||
OldVar->getPreviousDecl()->getDeclContext()==OldVar->getDeclContext())) {
// We have a previous declaration. Use that one, so we merge with the
// right type.
if (NamedDecl *NewPrev = FindInstantiatedDecl(
NewVar->getLocation(), OldVar->getPreviousDecl(), TemplateArgs))
Previous.addDecl(NewPrev);
} else if (!isa<VarTemplateSpecializationDecl>(NewVar) &&
OldVar->hasLinkage()) {
LookupQualifiedName(Previous, NewVar->getDeclContext(), false);
} else if (PrevDeclForVarTemplateSpecialization) {
Previous.addDecl(PrevDeclForVarTemplateSpecialization);
}
CheckVariableDeclaration(NewVar, Previous);
if (!InstantiatingVarTemplate) {
NewVar->getLexicalDeclContext()->addHiddenDecl(NewVar);
if (!NewVar->isLocalExternDecl() || !NewVar->getPreviousDecl())
NewVar->getDeclContext()->makeDeclVisibleInContext(NewVar);
}
if (!OldVar->isOutOfLine()) {
if (NewVar->getDeclContext()->isFunctionOrMethod())
CurrentInstantiationScope->InstantiatedLocal(OldVar, NewVar);
}
// Link instantiations of static data members back to the template from
// which they were instantiated.
//
// Don't do this when instantiating a template (we link the template itself
// back in that case) nor when instantiating a static data member template
// (that's not a member specialization).
if (NewVar->isStaticDataMember() && !InstantiatingVarTemplate &&
!InstantiatingSpecFromTemplate)
NewVar->setInstantiationOfStaticDataMember(OldVar,
TSK_ImplicitInstantiation);
// If the pattern is an (in-class) explicit specialization, then the result
// is also an explicit specialization.
if (VarTemplateSpecializationDecl *OldVTSD =
dyn_cast<VarTemplateSpecializationDecl>(OldVar)) {
if (OldVTSD->getSpecializationKind() == TSK_ExplicitSpecialization &&
!isa<VarTemplatePartialSpecializationDecl>(OldVTSD))
cast<VarTemplateSpecializationDecl>(NewVar)->setSpecializationKind(
TSK_ExplicitSpecialization);
}
// Forward the mangling number from the template to the instantiated decl.
Context.setManglingNumber(NewVar, Context.getManglingNumber(OldVar));
Context.setStaticLocalNumber(NewVar, Context.getStaticLocalNumber(OldVar));
// Figure out whether to eagerly instantiate the initializer.
if (InstantiatingVarTemplate || InstantiatingVarTemplatePartialSpec) {
// We're producing a template. Don't instantiate the initializer yet.
} else if (NewVar->getType()->isUndeducedType()) {
// We need the type to complete the declaration of the variable.
InstantiateVariableInitializer(NewVar, OldVar, TemplateArgs);
} else if (InstantiatingSpecFromTemplate ||
(OldVar->isInline() && OldVar->isThisDeclarationADefinition() &&
!NewVar->isThisDeclarationADefinition())) {
// Delay instantiation of the initializer for variable template
// specializations or inline static data members until a definition of the
// variable is needed.
} else {
InstantiateVariableInitializer(NewVar, OldVar, TemplateArgs);
}
// Diagnose unused local variables with dependent types, where the diagnostic
// will have been deferred.
if (!NewVar->isInvalidDecl() &&
NewVar->getDeclContext()->isFunctionOrMethod() &&
OldVar->getType()->isDependentType())
DiagnoseUnusedDecl(NewVar);
}
void Sema::InstantiateVariableInitializer(
VarDecl *Var, VarDecl *OldVar,
const MultiLevelTemplateArgumentList &TemplateArgs) {
if (ASTMutationListener *L = getASTContext().getASTMutationListener())
L->VariableDefinitionInstantiated(Var);
// We propagate the 'inline' flag with the initializer, because it
// would otherwise imply that the variable is a definition for a
// non-static data member.
if (OldVar->isInlineSpecified())
Var->setInlineSpecified();
else if (OldVar->isInline())
Var->setImplicitlyInline();
if (OldVar->getInit()) {
EnterExpressionEvaluationContext Evaluated(
*this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated, Var);
currentEvaluationContext().InLifetimeExtendingContext =
parentEvaluationContext().InLifetimeExtendingContext;
currentEvaluationContext().RebuildDefaultArgOrDefaultInit =
parentEvaluationContext().RebuildDefaultArgOrDefaultInit;
// Instantiate the initializer.
ExprResult Init;
{
ContextRAII SwitchContext(*this, Var->getDeclContext());
Init = SubstInitializer(OldVar->getInit(), TemplateArgs,
OldVar->getInitStyle() == VarDecl::CallInit);
}
if (!Init.isInvalid()) {
Expr *InitExpr = Init.get();
if (Var->hasAttr<DLLImportAttr>() &&
(!InitExpr ||
!InitExpr->isConstantInitializer(getASTContext(), false))) {
// Do not dynamically initialize dllimport variables.
} else if (InitExpr) {
bool DirectInit = OldVar->isDirectInit();
AddInitializerToDecl(Var, InitExpr, DirectInit);
} else
ActOnUninitializedDecl(Var);
} else {
// FIXME: Not too happy about invalidating the declaration
// because of a bogus initializer.
Var->setInvalidDecl();
}
} else {
// `inline` variables are a definition and declaration all in one; we won't
// pick up an initializer from anywhere else.
if (Var->isStaticDataMember() && !Var->isInline()) {
if (!Var->isOutOfLine())
return;
// If the declaration inside the class had an initializer, don't add
// another one to the out-of-line definition.
if (OldVar->getFirstDecl()->hasInit())
return;
}
// We'll add an initializer to a for-range declaration later.
if (Var->isCXXForRangeDecl() || Var->isObjCForDecl())
return;
ActOnUninitializedDecl(Var);
}
if (getLangOpts().CUDA)
CUDA().checkAllowedInitializer(Var);
}
void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
VarDecl *Var, bool Recursive,
bool DefinitionRequired, bool AtEndOfTU) {
if (Var->isInvalidDecl())
return;
// Never instantiate an explicitly-specialized entity.
TemplateSpecializationKind TSK =
Var->getTemplateSpecializationKindForInstantiation();
if (TSK == TSK_ExplicitSpecialization)
return;
// Find the pattern and the arguments to substitute into it.
VarDecl *PatternDecl = Var->getTemplateInstantiationPattern();
assert(PatternDecl && "no pattern for templated variable");
MultiLevelTemplateArgumentList TemplateArgs =
getTemplateInstantiationArgs(Var);
VarTemplateSpecializationDecl *VarSpec =
dyn_cast<VarTemplateSpecializationDecl>(Var);
if (VarSpec) {
// If this is a static data member template, there might be an
// uninstantiated initializer on the declaration. If so, instantiate
// it now.
//
// FIXME: This largely duplicates what we would do below. The difference
// is that along this path we may instantiate an initializer from an
// in-class declaration of the template and instantiate the definition
// from a separate out-of-class definition.
if (PatternDecl->isStaticDataMember() &&
(PatternDecl = PatternDecl->getFirstDecl())->hasInit() &&
!Var->hasInit()) {
// FIXME: Factor out the duplicated instantiation context setup/tear down
// code here.
InstantiatingTemplate Inst(*this, PointOfInstantiation, Var);
if (Inst.isInvalid() || Inst.isAlreadyInstantiating())
return;
PrettyDeclStackTraceEntry CrashInfo(Context, Var, SourceLocation(),
"instantiating variable initializer");
// The instantiation is visible here, even if it was first declared in an
// unimported module.
Var->setVisibleDespiteOwningModule();
// If we're performing recursive template instantiation, create our own
// queue of pending implicit instantiations that we will instantiate
// later, while we're still within our own instantiation context.
GlobalEagerInstantiationScope GlobalInstantiations(
*this,
/*Enabled=*/Recursive, /*AtEndOfTU=*/AtEndOfTU);
LocalInstantiationScope Local(*this);
LocalEagerInstantiationScope LocalInstantiations(*this,
/*AtEndOfTU=*/AtEndOfTU);
// Enter the scope of this instantiation. We don't use
// PushDeclContext because we don't have a scope.
ContextRAII PreviousContext(*this, Var->getDeclContext());
InstantiateVariableInitializer(Var, PatternDecl, TemplateArgs);
PreviousContext.pop();
// This variable may have local implicit instantiations that need to be
// instantiated within this scope.
LocalInstantiations.perform();
Local.Exit();
GlobalInstantiations.perform();
}
} else {
assert(Var->isStaticDataMember() && PatternDecl->isStaticDataMember() &&
"not a static data member?");
}
VarDecl *Def = PatternDecl->getDefinition(getASTContext());
// If we don't have a definition of the variable template, we won't perform
// any instantiation. Rather, we rely on the user to instantiate this
// definition (or provide a specialization for it) in another translation
// unit.
if (!Def && !DefinitionRequired) {
if (TSK == TSK_ExplicitInstantiationDefinition) {
PendingInstantiations.push_back(
std::make_pair(Var, PointOfInstantiation));
} else if (TSK == TSK_ImplicitInstantiation) {
// Warn about missing definition at the end of translation unit.
if (AtEndOfTU && !getDiagnostics().hasErrorOccurred() &&
!getSourceManager().isInSystemHeader(PatternDecl->getBeginLoc())) {
Diag(PointOfInstantiation, diag::warn_var_template_missing)
<< Var;
Diag(PatternDecl->getLocation(), diag::note_forward_template_decl);
if (getLangOpts().CPlusPlus11)
Diag(PointOfInstantiation, diag::note_inst_declaration_hint) << Var;
}
return;
}
}
// FIXME: We need to track the instantiation stack in order to know which
// definitions should be visible within this instantiation.
// FIXME: Produce diagnostics when Var->getInstantiatedFromStaticDataMember().
if (DiagnoseUninstantiableTemplate(PointOfInstantiation, Var,
/*InstantiatedFromMember*/false,
PatternDecl, Def, TSK,
/*Complain*/DefinitionRequired))
return;
// C++11 [temp.explicit]p10:
// Except for inline functions, const variables of literal types, variables
// of reference types, [...] explicit instantiation declarations
// have the effect of suppressing the implicit instantiation of the entity
// to which they refer.
//
// FIXME: That's not exactly the same as "might be usable in constant
// expressions", which only allows constexpr variables and const integral
// types, not arbitrary const literal types.
if (TSK == TSK_ExplicitInstantiationDeclaration &&
!Var->mightBeUsableInConstantExpressions(getASTContext()))
return;
// Make sure to pass the instantiated variable to the consumer at the end.
struct PassToConsumerRAII {
ASTConsumer &Consumer;
VarDecl *Var;
PassToConsumerRAII(ASTConsumer &Consumer, VarDecl *Var)
: Consumer(Consumer), Var(Var) { }
~PassToConsumerRAII() {
Consumer.HandleCXXStaticMemberVarInstantiation(Var);
}
} PassToConsumerRAII(Consumer, Var);
// If we already have a definition, we're done.
if (VarDecl *Def = Var->getDefinition()) {
// We may be explicitly instantiating something we've already implicitly
// instantiated.
Def->setTemplateSpecializationKind(Var->getTemplateSpecializationKind(),
PointOfInstantiation);
return;
}
InstantiatingTemplate Inst(*this, PointOfInstantiation, Var);
if (Inst.isInvalid() || Inst.isAlreadyInstantiating())
return;
PrettyDeclStackTraceEntry CrashInfo(Context, Var, SourceLocation(),
"instantiating variable definition");
// If we're performing recursive template instantiation, create our own
// queue of pending implicit instantiations that we will instantiate later,
// while we're still within our own instantiation context.
GlobalEagerInstantiationScope GlobalInstantiations(*this,
/*Enabled=*/Recursive,
/*AtEndOfTU=*/AtEndOfTU);
// Enter the scope of this instantiation. We don't use
// PushDeclContext because we don't have a scope.
ContextRAII PreviousContext(*this, Var->getDeclContext());
LocalInstantiationScope Local(*this);
LocalEagerInstantiationScope LocalInstantiations(*this,
/*AtEndOfTU=*/AtEndOfTU);
VarDecl *OldVar = Var;
if (Def->isStaticDataMember() && !Def->isOutOfLine()) {
// We're instantiating an inline static data member whose definition was
// provided inside the class.
InstantiateVariableInitializer(Var, Def, TemplateArgs);
} else if (!VarSpec) {
Var = cast_or_null<VarDecl>(SubstDecl(Def, Var->getDeclContext(),
TemplateArgs));
} else if (Var->isStaticDataMember() &&
Var->getLexicalDeclContext()->isRecord()) {
// We need to instantiate the definition of a static data member template,
// and all we have is the in-class declaration of it. Instantiate a separate
// declaration of the definition.
TemplateDeclInstantiator Instantiator(*this, Var->getDeclContext(),
TemplateArgs);
TemplateArgumentListInfo TemplateArgInfo;
if (const ASTTemplateArgumentListInfo *ArgInfo =
VarSpec->getTemplateArgsAsWritten()) {
TemplateArgInfo.setLAngleLoc(ArgInfo->getLAngleLoc());
TemplateArgInfo.setRAngleLoc(ArgInfo->getRAngleLoc());
for (const TemplateArgumentLoc &Arg : ArgInfo->arguments())
TemplateArgInfo.addArgument(Arg);
}
Var = cast_or_null<VarDecl>(Instantiator.VisitVarTemplateSpecializationDecl(
VarSpec->getSpecializedTemplate(), Def, TemplateArgInfo,
VarSpec->getTemplateArgs().asArray(), VarSpec));
if (Var) {
llvm::PointerUnion<VarTemplateDecl *,
VarTemplatePartialSpecializationDecl *> PatternPtr =
VarSpec->getSpecializedTemplateOrPartial();
if (VarTemplatePartialSpecializationDecl *Partial =
PatternPtr.dyn_cast<VarTemplatePartialSpecializationDecl *>())
cast<VarTemplateSpecializationDecl>(Var)->setInstantiationOf(
Partial, &VarSpec->getTemplateInstantiationArgs());
// Attach the initializer.
InstantiateVariableInitializer(Var, Def, TemplateArgs);
}
} else
// Complete the existing variable's definition with an appropriately
// substituted type and initializer.
Var = CompleteVarTemplateSpecializationDecl(VarSpec, Def, TemplateArgs);
PreviousContext.pop();
if (Var) {
PassToConsumerRAII.Var = Var;
Var->setTemplateSpecializationKind(OldVar->getTemplateSpecializationKind(),
OldVar->getPointOfInstantiation());
}
// This variable may have local implicit instantiations that need to be
// instantiated within this scope.
LocalInstantiations.perform();
Local.Exit();
GlobalInstantiations.perform();
}
void
Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
const CXXConstructorDecl *Tmpl,
const MultiLevelTemplateArgumentList &TemplateArgs) {
SmallVector<CXXCtorInitializer*, 4> NewInits;
bool AnyErrors = Tmpl->isInvalidDecl();
// Instantiate all the initializers.
for (const auto *Init : Tmpl->inits()) {
// Only instantiate written initializers, let Sema re-construct implicit
// ones.
if (!Init->isWritten())
continue;
SourceLocation EllipsisLoc;
if (Init->isPackExpansion()) {
// This is a pack expansion. We should expand it now.
TypeLoc BaseTL = Init->getTypeSourceInfo()->getTypeLoc();
SmallVector<UnexpandedParameterPack, 4> Unexpanded;
collectUnexpandedParameterPacks(BaseTL, Unexpanded);
collectUnexpandedParameterPacks(Init->getInit(), Unexpanded);
bool ShouldExpand = false;
bool RetainExpansion = false;
UnsignedOrNone NumExpansions = std::nullopt;
if (CheckParameterPacksForExpansion(Init->getEllipsisLoc(),
BaseTL.getSourceRange(),
Unexpanded,
TemplateArgs, ShouldExpand,
RetainExpansion,
NumExpansions)) {
AnyErrors = true;
New->setInvalidDecl();
continue;
}
assert(ShouldExpand && "Partial instantiation of base initializer?");
// Loop over all of the arguments in the argument pack(s),
for (unsigned I = 0; I != *NumExpansions; ++I) {
Sema::ArgPackSubstIndexRAII SubstIndex(*this, I);
// Instantiate the initializer.
ExprResult TempInit = SubstInitializer(Init->getInit(), TemplateArgs,
/*CXXDirectInit=*/true);
if (TempInit.isInvalid()) {
AnyErrors = true;
break;
}
// Instantiate the base type.
TypeSourceInfo *BaseTInfo = SubstType(Init->getTypeSourceInfo(),
TemplateArgs,
Init->getSourceLocation(),
New->getDeclName());
if (!BaseTInfo) {
AnyErrors = true;
break;
}
// Build the initializer.
MemInitResult NewInit = BuildBaseInitializer(BaseTInfo->getType(),
BaseTInfo, TempInit.get(),
New->getParent(),
SourceLocation());
if (NewInit.isInvalid()) {
AnyErrors = true;
break;
}
NewInits.push_back(NewInit.get());
}
continue;
}
// Instantiate the initializer.
ExprResult TempInit = SubstInitializer(Init->getInit(), TemplateArgs,
/*CXXDirectInit=*/true);
if (TempInit.isInvalid()) {
AnyErrors = true;
continue;
}
MemInitResult NewInit;
if (Init->isDelegatingInitializer() || Init->isBaseInitializer()) {
TypeSourceInfo *TInfo = SubstType(Init->getTypeSourceInfo(),
TemplateArgs,
Init->getSourceLocation(),
New->getDeclName());
if (!TInfo) {
AnyErrors = true;
New->setInvalidDecl();
continue;
}
if (Init->isBaseInitializer())
NewInit = BuildBaseInitializer(TInfo->getType(), TInfo, TempInit.get(),
New->getParent(), EllipsisLoc);
else
NewInit = BuildDelegatingInitializer(TInfo, TempInit.get(),
cast<CXXRecordDecl>(CurContext->getParent()));
} else if (Init->isMemberInitializer()) {
FieldDecl *Member = cast_or_null<FieldDecl>(FindInstantiatedDecl(
Init->getMemberLocation(),
Init->getMember(),
TemplateArgs));
if (!Member) {
AnyErrors = true;
New->setInvalidDecl();
continue;
}
NewInit = BuildMemberInitializer(Member, TempInit.get(),
Init->getSourceLocation());
} else if (Init->isIndirectMemberInitializer()) {
IndirectFieldDecl *IndirectMember =
cast_or_null<IndirectFieldDecl>(FindInstantiatedDecl(
Init->getMemberLocation(),
Init->getIndirectMember(), TemplateArgs));
if (!IndirectMember) {
AnyErrors = true;
New->setInvalidDecl();
continue;
}
NewInit = BuildMemberInitializer(IndirectMember, TempInit.get(),
Init->getSourceLocation());
}
if (NewInit.isInvalid()) {
AnyErrors = true;
New->setInvalidDecl();
} else {
NewInits.push_back(NewInit.get());
}
}
// Assign all the initializers to the new constructor.
ActOnMemInitializers(New,
/*FIXME: ColonLoc */
SourceLocation(),
NewInits,
AnyErrors);
}
// TODO: this could be templated if the various decl types used the
// same method name.
static bool isInstantiationOf(ClassTemplateDecl *Pattern,
ClassTemplateDecl *Instance) {
Pattern = Pattern->getCanonicalDecl();
do {
Instance = Instance->getCanonicalDecl();
if (Pattern == Instance) return true;
Instance = Instance->getInstantiatedFromMemberTemplate();
} while (Instance);
return false;
}
static bool isInstantiationOf(FunctionTemplateDecl *Pattern,
FunctionTemplateDecl *Instance) {
Pattern = Pattern->getCanonicalDecl();
do {
Instance = Instance->getCanonicalDecl();
if (Pattern == Instance) return true;
Instance = Instance->getInstantiatedFromMemberTemplate();
} while (Instance);
return false;
}
static bool
isInstantiationOf(ClassTemplatePartialSpecializationDecl *Pattern,
ClassTemplatePartialSpecializationDecl *Instance) {
Pattern
= cast<ClassTemplatePartialSpecializationDecl>(Pattern->getCanonicalDecl());
do {
Instance = cast<ClassTemplatePartialSpecializationDecl>(
Instance->getCanonicalDecl());
if (Pattern == Instance)
return true;
Instance = Instance->getInstantiatedFromMember();
} while (Instance);
return false;
}
static bool isInstantiationOf(CXXRecordDecl *Pattern,
CXXRecordDecl *Instance) {
Pattern = Pattern->getCanonicalDecl();
do {
Instance = Instance->getCanonicalDecl();
if (Pattern == Instance) return true;
Instance = Instance->getInstantiatedFromMemberClass();
} while (Instance);
return false;
}
static bool isInstantiationOf(FunctionDecl *Pattern,
FunctionDecl *Instance) {
Pattern = Pattern->getCanonicalDecl();
do {
Instance = Instance->getCanonicalDecl();
if (Pattern == Instance) return true;
Instance = Instance->getInstantiatedFromMemberFunction();
} while (Instance);
return false;
}
static bool isInstantiationOf(EnumDecl *Pattern,
EnumDecl *Instance) {
Pattern = Pattern->getCanonicalDecl();
do {
Instance = Instance->getCanonicalDecl();
if (Pattern == Instance) return true;
Instance = Instance->getInstantiatedFromMemberEnum();
} while (Instance);
return false;
}
static bool isInstantiationOf(UsingShadowDecl *Pattern,
UsingShadowDecl *Instance,
ASTContext &C) {
return declaresSameEntity(C.getInstantiatedFromUsingShadowDecl(Instance),
Pattern);
}
static bool isInstantiationOf(UsingDecl *Pattern, UsingDecl *Instance,
ASTContext &C) {
return declaresSameEntity(C.getInstantiatedFromUsingDecl(Instance), Pattern);
}
template<typename T>
static bool isInstantiationOfUnresolvedUsingDecl(T *Pattern, Decl *Other,
ASTContext &Ctx) {
// An unresolved using declaration can instantiate to an unresolved using
// declaration, or to a using declaration or a using declaration pack.
//
// Multiple declarations can claim to be instantiated from an unresolved
// using declaration if it's a pack expansion. We want the UsingPackDecl
// in that case, not the individual UsingDecls within the pack.
bool OtherIsPackExpansion;
NamedDecl *OtherFrom;
if (auto *OtherUUD = dyn_cast<T>(Other)) {
OtherIsPackExpansion = OtherUUD->isPackExpansion();
OtherFrom = Ctx.getInstantiatedFromUsingDecl(OtherUUD);
} else if (auto *OtherUPD = dyn_cast<UsingPackDecl>(Other)) {
OtherIsPackExpansion = true;
OtherFrom = OtherUPD->getInstantiatedFromUsingDecl();
} else if (auto *OtherUD = dyn_cast<UsingDecl>(Other)) {
OtherIsPackExpansion = false;
OtherFrom = Ctx.getInstantiatedFromUsingDecl(OtherUD);
} else {
return false;
}
return Pattern->isPackExpansion() == OtherIsPackExpansion &&
declaresSameEntity(OtherFrom, Pattern);
}
static bool isInstantiationOfStaticDataMember(VarDecl *Pattern,
VarDecl *Instance) {
assert(Instance->isStaticDataMember());
Pattern = Pattern->getCanonicalDecl();
do {
Instance = Instance->getCanonicalDecl();
if (Pattern == Instance) return true;
Instance = Instance->getInstantiatedFromStaticDataMember();
} while (Instance);
return false;
}
// Other is the prospective instantiation
// D is the prospective pattern
static bool isInstantiationOf(ASTContext &Ctx, NamedDecl *D, Decl *Other) {
if (auto *UUD = dyn_cast<UnresolvedUsingTypenameDecl>(D))
return isInstantiationOfUnresolvedUsingDecl(UUD, Other, Ctx);
if (auto *UUD = dyn_cast<UnresolvedUsingValueDecl>(D))
return isInstantiationOfUnresolvedUsingDecl(UUD, Other, Ctx);
if (D->getKind() != Other->getKind())
return false;
if (auto *Record = dyn_cast<CXXRecordDecl>(Other))
return isInstantiationOf(cast<CXXRecordDecl>(D), Record);
if (auto *Function = dyn_cast<FunctionDecl>(Other))
return isInstantiationOf(cast<FunctionDecl>(D), Function);
if (auto *Enum = dyn_cast<EnumDecl>(Other))
return isInstantiationOf(cast<EnumDecl>(D), Enum);
if (auto *Var = dyn_cast<VarDecl>(Other))
if (Var->isStaticDataMember())
return isInstantiationOfStaticDataMember(cast<VarDecl>(D), Var);
if (auto *Temp = dyn_cast<ClassTemplateDecl>(Other))
return isInstantiationOf(cast<ClassTemplateDecl>(D), Temp);
if (auto *Temp = dyn_cast<FunctionTemplateDecl>(Other))
return isInstantiationOf(cast<FunctionTemplateDecl>(D), Temp);
if (auto *PartialSpec =
dyn_cast<ClassTemplatePartialSpecializationDecl>(Other))
return isInstantiationOf(cast<ClassTemplatePartialSpecializationDecl>(D),
PartialSpec);
if (auto *Field = dyn_cast<FieldDecl>(Other)) {
if (!Field->getDeclName()) {
// This is an unnamed field.
return declaresSameEntity(Ctx.getInstantiatedFromUnnamedFieldDecl(Field),
cast<FieldDecl>(D));
}
}
if (auto *Using = dyn_cast<UsingDecl>(Other))
return isInstantiationOf(cast<UsingDecl>(D), Using, Ctx);
if (auto *Shadow = dyn_cast<UsingShadowDecl>(Other))
return isInstantiationOf(cast<UsingShadowDecl>(D), Shadow, Ctx);
return D->getDeclName() &&
D->getDeclName() == cast<NamedDecl>(Other)->getDeclName();
}
template<typename ForwardIterator>
static NamedDecl *findInstantiationOf(ASTContext &Ctx,
NamedDecl *D,
ForwardIterator first,
ForwardIterator last) {
for (; first != last; ++first)
if (isInstantiationOf(Ctx, D, *first))
return cast<NamedDecl>(*first);
return nullptr;
}
DeclContext *Sema::FindInstantiatedContext(SourceLocation Loc, DeclContext* DC,
const MultiLevelTemplateArgumentList &TemplateArgs) {
if (NamedDecl *D = dyn_cast<NamedDecl>(DC)) {
Decl* ID = FindInstantiatedDecl(Loc, D, TemplateArgs, true);
return cast_or_null<DeclContext>(ID);
} else return DC;
}
/// Determine whether the given context is dependent on template parameters at
/// level \p Level or below.
///
/// Sometimes we only substitute an inner set of template arguments and leave
/// the outer templates alone. In such cases, contexts dependent only on the
/// outer levels are not effectively dependent.
static bool isDependentContextAtLevel(DeclContext *DC, unsigned Level) {
if (!DC->isDependentContext())
return false;
if (!Level)
return true;
return cast<Decl>(DC)->getTemplateDepth() > Level;
}
NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
const MultiLevelTemplateArgumentList &TemplateArgs,
bool FindingInstantiatedContext) {
DeclContext *ParentDC = D->getDeclContext();
// Determine whether our parent context depends on any of the template
// arguments we're currently substituting.
bool ParentDependsOnArgs = isDependentContextAtLevel(
ParentDC, TemplateArgs.getNumRetainedOuterLevels());
// FIXME: Parameters of pointer to functions (y below) that are themselves
// parameters (p below) can have their ParentDC set to the translation-unit
// - thus we can not consistently check if the ParentDC of such a parameter
// is Dependent or/and a FunctionOrMethod.
// For e.g. this code, during Template argument deduction tries to
// find an instantiated decl for (T y) when the ParentDC for y is
// the translation unit.
// e.g. template <class T> void Foo(auto (*p)(T y) -> decltype(y())) {}
// float baz(float(*)()) { return 0.0; }
// Foo(baz);
// The better fix here is perhaps to ensure that a ParmVarDecl, by the time
// it gets here, always has a FunctionOrMethod as its ParentDC??
// For now:
// - as long as we have a ParmVarDecl whose parent is non-dependent and
// whose type is not instantiation dependent, do nothing to the decl
// - otherwise find its instantiated decl.
if (isa<ParmVarDecl>(D) && !ParentDependsOnArgs &&
!cast<ParmVarDecl>(D)->getType()->isInstantiationDependentType())
return D;
if (isa<ParmVarDecl>(D) || isa<NonTypeTemplateParmDecl>(D) ||
isa<TemplateTypeParmDecl>(D) || isa<TemplateTemplateParmDecl>(D) ||
(ParentDependsOnArgs && (ParentDC->isFunctionOrMethod() ||
isa<OMPDeclareReductionDecl>(ParentDC) ||
isa<OMPDeclareMapperDecl>(ParentDC))) ||
(isa<CXXRecordDecl>(D) && cast<CXXRecordDecl>(D)->isLambda() &&
cast<CXXRecordDecl>(D)->getTemplateDepth() >
TemplateArgs.getNumRetainedOuterLevels())) {
// D is a local of some kind. Look into the map of local
// declarations to their instantiations.
if (CurrentInstantiationScope) {
if (auto Found = CurrentInstantiationScope->findInstantiationOf(D)) {
if (Decl *FD = Found->dyn_cast<Decl *>()) {
if (auto *BD = dyn_cast<BindingDecl>(FD);
BD && BD->isParameterPack() && ArgPackSubstIndex) {
return BD->getBindingPackDecls()[*ArgPackSubstIndex];
}
return cast<NamedDecl>(FD);
}
assert(ArgPackSubstIndex &&
"found declaration pack but not pack expanding");
typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack;
return cast<NamedDecl>(
(*cast<DeclArgumentPack *>(*Found))[*ArgPackSubstIndex]);
}
}
// If we're performing a partial substitution during template argument
// deduction, we may not have values for template parameters yet. They
// just map to themselves.
if (isa<NonTypeTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D) ||
isa<TemplateTemplateParmDecl>(D))
return D;
if (D->isInvalidDecl())
return nullptr;
// Normally this function only searches for already instantiated declaration
// however we have to make an exclusion for local types used before
// definition as in the code:
//
// template<typename T> void f1() {
// void g1(struct x1);
// struct x1 {};
// }
//
// In this case instantiation of the type of 'g1' requires definition of
// 'x1', which is defined later. Error recovery may produce an enum used
// before definition. In these cases we need to instantiate relevant
// declarations here.
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) {
Decl *Inst = SubstDecl(D, CurContext, TemplateArgs);
CurrentInstantiationScope->InstantiatedLocal(D, Inst);
return cast<TypeDecl>(Inst);
}
// If we didn't find the decl, then we must have a label decl that hasn't
// been found yet. Lazily instantiate it and return it now.
assert(isa<LabelDecl>(D));
Decl *Inst = SubstDecl(D, CurContext, TemplateArgs);
assert(Inst && "Failed to instantiate label??");
CurrentInstantiationScope->InstantiatedLocal(D, Inst);
return cast<LabelDecl>(Inst);
}
if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) {
if (!Record->isDependentContext())
return D;
// Determine whether this record is the "templated" declaration describing
// a class template or class template specialization.
ClassTemplateDecl *ClassTemplate = Record->getDescribedClassTemplate();
if (ClassTemplate)
ClassTemplate = ClassTemplate->getCanonicalDecl();
else if (ClassTemplateSpecializationDecl *Spec =
dyn_cast<ClassTemplateSpecializationDecl>(Record))
ClassTemplate = Spec->getSpecializedTemplate()->getCanonicalDecl();
// Walk the current context to find either the record or an instantiation of
// it.
DeclContext *DC = CurContext;
while (!DC->isFileContext()) {
// If we're performing substitution while we're inside the template
// definition, we'll find our own context. We're done.
if (DC->Equals(Record))
return Record;
if (CXXRecordDecl *InstRecord = dyn_cast<CXXRecordDecl>(DC)) {
// Check whether we're in the process of instantiating a class template
// specialization of the template we're mapping.
if (ClassTemplateSpecializationDecl *InstSpec
= dyn_cast<ClassTemplateSpecializationDecl>(InstRecord)){
ClassTemplateDecl *SpecTemplate = InstSpec->getSpecializedTemplate();
if (ClassTemplate && isInstantiationOf(ClassTemplate, SpecTemplate))
return InstRecord;
}
// Check whether we're in the process of instantiating a member class.
if (isInstantiationOf(Record, InstRecord))
return InstRecord;
}
// Move to the outer template scope.
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(DC)) {
if (FD->getFriendObjectKind() &&
FD->getNonTransparentDeclContext()->isFileContext()) {
DC = FD->getLexicalDeclContext();
continue;
}
// An implicit deduction guide acts as if it's within the class template
// specialization described by its name and first N template params.
auto *Guide = dyn_cast<CXXDeductionGuideDecl>(FD);
if (Guide && Guide->isImplicit()) {
TemplateDecl *TD = Guide->getDeducedTemplate();
// Convert the arguments to an "as-written" list.
TemplateArgumentListInfo Args(Loc, Loc);
for (TemplateArgument Arg : TemplateArgs.getInnermost().take_front(
TD->getTemplateParameters()->size())) {
ArrayRef<TemplateArgument> Unpacked(Arg);
if (Arg.getKind() == TemplateArgument::Pack)
Unpacked = Arg.pack_elements();
for (TemplateArgument UnpackedArg : Unpacked)
Args.addArgument(
getTrivialTemplateArgumentLoc(UnpackedArg, QualType(), Loc));
}
QualType T = CheckTemplateIdType(TemplateName(TD), Loc, Args);
// We may get a non-null type with errors, in which case
// `getAsCXXRecordDecl` will return `nullptr`. For instance, this
// happens when one of the template arguments is an invalid
// expression. We return early to avoid triggering the assertion
// about the `CodeSynthesisContext`.
if (T.isNull() || T->containsErrors())
return nullptr;
CXXRecordDecl *SubstRecord = T->getAsCXXRecordDecl();
if (!SubstRecord) {
// T can be a dependent TemplateSpecializationType when performing a
// substitution for building a deduction guide or for template
// argument deduction in the process of rebuilding immediate
// expressions. (Because the default argument that involves a lambda
// is untransformed and thus could be dependent at this point.)
assert(SemaRef.RebuildingImmediateInvocation ||
CodeSynthesisContexts.back().Kind ==
CodeSynthesisContext::BuildingDeductionGuides);
// Return a nullptr as a sentinel value, we handle it properly in
// the TemplateInstantiator::TransformInjectedClassNameType
// override, which we transform it to a TemplateSpecializationType.
return nullptr;
}
// Check that this template-id names the primary template and not a
// partial or explicit specialization. (In the latter cases, it's
// meaningless to attempt to find an instantiation of D within the
// specialization.)
// FIXME: The standard doesn't say what should happen here.
if (FindingInstantiatedContext &&
usesPartialOrExplicitSpecialization(
Loc, cast<ClassTemplateSpecializationDecl>(SubstRecord))) {
Diag(Loc, diag::err_specialization_not_primary_template)
<< T << (SubstRecord->getTemplateSpecializationKind() ==
TSK_ExplicitSpecialization);
return nullptr;
}
DC = SubstRecord;
continue;
}
}
DC = DC->getParent();
}
// Fall through to deal with other dependent record types (e.g.,
// anonymous unions in class templates).
}
if (!ParentDependsOnArgs)
return D;
ParentDC = FindInstantiatedContext(Loc, ParentDC, TemplateArgs);
if (!ParentDC)
return nullptr;
if (ParentDC != D->getDeclContext()) {
// We performed some kind of instantiation in the parent context,
// so now we need to look into the instantiated parent context to
// find the instantiation of the declaration D.
// If our context used to be dependent, we may need to instantiate
// it before performing lookup into that context.
bool IsBeingInstantiated = false;
if (CXXRecordDecl *Spec = dyn_cast<CXXRecordDecl>(ParentDC)) {
if (!Spec->isDependentContext()) {
QualType T = Context.getTypeDeclType(Spec);
const RecordType *Tag = T->getAs<RecordType>();
assert(Tag && "type of non-dependent record is not a RecordType");
if (Tag->isBeingDefined())
IsBeingInstantiated = true;
if (!Tag->isBeingDefined() &&
RequireCompleteType(Loc, T, diag::err_incomplete_type))
return nullptr;
ParentDC = Tag->getDecl();
}
}
NamedDecl *Result = nullptr;
// FIXME: If the name is a dependent name, this lookup won't necessarily
// find it. Does that ever matter?
if (auto Name = D->getDeclName()) {
DeclarationNameInfo NameInfo(Name, D->getLocation());
DeclarationNameInfo NewNameInfo =
SubstDeclarationNameInfo(NameInfo, TemplateArgs);
Name = NewNameInfo.getName();
if (!Name)
return nullptr;
DeclContext::lookup_result Found = ParentDC->lookup(Name);
Result = findInstantiationOf(Context, D, Found.begin(), Found.end());
} else {
// Since we don't have a name for the entity we're looking for,
// our only option is to walk through all of the declarations to
// find that name. This will occur in a few cases:
//
// - anonymous struct/union within a template
// - unnamed class/struct/union/enum within a template
//
// FIXME: Find a better way to find these instantiations!
Result = findInstantiationOf(Context, D,
ParentDC->decls_begin(),
ParentDC->decls_end());
}
if (!Result) {
if (isa<UsingShadowDecl>(D)) {
// UsingShadowDecls can instantiate to nothing because of using hiding.
} else if (hasUncompilableErrorOccurred()) {
// We've already complained about some ill-formed code, so most likely
// this declaration failed to instantiate. There's no point in
// complaining further, since this is normal in invalid code.
// FIXME: Use more fine-grained 'invalid' tracking for this.
} else if (IsBeingInstantiated) {
// The class in which this member exists is currently being
// instantiated, and we haven't gotten around to instantiating this
// member yet. This can happen when the code uses forward declarations
// of member classes, and introduces ordering dependencies via
// template instantiation.
Diag(Loc, diag::err_member_not_yet_instantiated)
<< D->getDeclName()
<< Context.getTypeDeclType(cast<CXXRecordDecl>(ParentDC));
Diag(D->getLocation(), diag::note_non_instantiated_member_here);
} else if (EnumConstantDecl *ED = dyn_cast<EnumConstantDecl>(D)) {
// This enumeration constant was found when the template was defined,
// but can't be found in the instantiation. This can happen if an
// unscoped enumeration member is explicitly specialized.
EnumDecl *Enum = cast<EnumDecl>(ED->getLexicalDeclContext());
EnumDecl *Spec = cast<EnumDecl>(FindInstantiatedDecl(Loc, Enum,
TemplateArgs));
assert(Spec->getTemplateSpecializationKind() ==
TSK_ExplicitSpecialization);
Diag(Loc, diag::err_enumerator_does_not_exist)
<< D->getDeclName()
<< Context.getTypeDeclType(cast<TypeDecl>(Spec->getDeclContext()));
Diag(Spec->getLocation(), diag::note_enum_specialized_here)
<< Context.getTypeDeclType(Spec);
} else {
// We should have found something, but didn't.
llvm_unreachable("Unable to find instantiation of declaration!");
}
}
D = Result;
}
return D;
}
void Sema::PerformPendingInstantiations(bool LocalOnly, bool AtEndOfTU) {
std::deque<PendingImplicitInstantiation> DelayedImplicitInstantiations;
while (!PendingLocalImplicitInstantiations.empty() ||
(!LocalOnly && !PendingInstantiations.empty())) {
PendingImplicitInstantiation Inst;
bool LocalInstantiation = false;
if (PendingLocalImplicitInstantiations.empty()) {
Inst = PendingInstantiations.front();
PendingInstantiations.pop_front();
} else {
Inst = PendingLocalImplicitInstantiations.front();
PendingLocalImplicitInstantiations.pop_front();
LocalInstantiation = true;
}
// Instantiate function definitions
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Inst.first)) {
bool DefinitionRequired = Function->getTemplateSpecializationKind() ==
TSK_ExplicitInstantiationDefinition;
if (Function->isMultiVersion()) {
getASTContext().forEachMultiversionedFunctionVersion(
Function,
[this, Inst, DefinitionRequired, AtEndOfTU](FunctionDecl *CurFD) {
InstantiateFunctionDefinition(/*FIXME:*/ Inst.second, CurFD, true,
DefinitionRequired, AtEndOfTU);
if (CurFD->isDefined())
CurFD->setInstantiationIsPending(false);
});
} else {
InstantiateFunctionDefinition(/*FIXME:*/ Inst.second, Function, true,
DefinitionRequired, AtEndOfTU);
if (Function->isDefined())
Function->setInstantiationIsPending(false);
}
// Definition of a PCH-ed template declaration may be available only in the TU.
if (!LocalOnly && LangOpts.PCHInstantiateTemplates &&
TUKind == TU_Prefix && Function->instantiationIsPending())
DelayedImplicitInstantiations.push_back(Inst);
else if (!AtEndOfTU && Function->instantiationIsPending() &&
!LocalInstantiation)
DelayedImplicitInstantiations.push_back(Inst);
continue;
}
// Instantiate variable definitions
VarDecl *Var = cast<VarDecl>(Inst.first);
assert((Var->isStaticDataMember() ||
isa<VarTemplateSpecializationDecl>(Var)) &&
"Not a static data member, nor a variable template"
" specialization?");
// Don't try to instantiate declarations if the most recent redeclaration
// is invalid.
if (Var->getMostRecentDecl()->isInvalidDecl())
continue;
// Check if the most recent declaration has changed the specialization kind
// and removed the need for implicit instantiation.
switch (Var->getMostRecentDecl()
->getTemplateSpecializationKindForInstantiation()) {
case TSK_Undeclared:
llvm_unreachable("Cannot instantitiate an undeclared specialization.");
case TSK_ExplicitInstantiationDeclaration:
case TSK_ExplicitSpecialization:
continue; // No longer need to instantiate this type.
case TSK_ExplicitInstantiationDefinition:
// We only need an instantiation if the pending instantiation *is* the
// explicit instantiation.
if (Var != Var->getMostRecentDecl())
continue;
break;
case TSK_ImplicitInstantiation:
break;
}
PrettyDeclStackTraceEntry CrashInfo(Context, Var, SourceLocation(),
"instantiating variable definition");
bool DefinitionRequired = Var->getTemplateSpecializationKind() ==
TSK_ExplicitInstantiationDefinition;
// Instantiate static data member definitions or variable template
// specializations.
InstantiateVariableDefinition(/*FIXME:*/ Inst.second, Var, true,
DefinitionRequired, AtEndOfTU);
}
if (!DelayedImplicitInstantiations.empty())
PendingInstantiations.swap(DelayedImplicitInstantiations);
}
void Sema::PerformDependentDiagnostics(const DeclContext *Pattern,
const MultiLevelTemplateArgumentList &TemplateArgs) {
for (auto *DD : Pattern->ddiags()) {
switch (DD->getKind()) {
case DependentDiagnostic::Access:
HandleDependentAccessCheck(*DD, TemplateArgs);
break;
}
}
}