diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 20:50:49 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 20:50:49 +0000 |
commit | 2298981669bf3bd63335a4be179bc0f96823a8f4 (patch) | |
tree | 1cbe2eb27f030d2d70b80ee5ca3c86bee7326a9f /lib/Sema/SemaTemplateInstantiateDecl.cpp | |
parent | 9a83721404652cea39e9f02ae3e3b5c964602a5c (diff) |
Notes
Diffstat (limited to 'lib/Sema/SemaTemplateInstantiateDecl.cpp')
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 578 |
1 files changed, 411 insertions, 167 deletions
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index fad3c065e896f..67343d11d3330 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1,9 +1,8 @@ //===--- SemaTemplateInstantiateDecl.cpp - C++ Template Decl Instantiation ===/ // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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. @@ -24,6 +23,7 @@ #include "clang/Sema/Lookup.h" #include "clang/Sema/Template.h" #include "clang/Sema/TemplateInstCallback.h" +#include "llvm/Support/TimeProfiler.h" using namespace clang; @@ -285,7 +285,7 @@ static void instantiateOMPDeclareSimdDeclAttr( SmallVector<Expr *, 4> Uniforms, Aligneds, Alignments, Linears, Steps; SmallVector<unsigned, 4> LinModifiers; - auto &&Subst = [&](Expr *E) -> ExprResult { + 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); @@ -300,6 +300,17 @@ static void instantiateOMPDeclareSimdDeclAttr( 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); @@ -345,6 +356,74 @@ static void instantiateOMPDeclareSimdDeclAttr( 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.addAMDGPUFlatWorkGroupSizeAttr(Attr.getLocation(), New, MinExpr, MaxExpr, + Attr.getSpellingListIndex()); +} + +static ExplicitSpecifier +instantiateExplicitSpecifier(Sema &S, + const MultiLevelTemplateArgumentList &TemplateArgs, + ExplicitSpecifier ES, FunctionDecl *New) { + if (!ES.getExpr()) + return ES; + Expr *OldCond = ES.getExpr(); + Expr *Cond = nullptr; + { + EnterExpressionEvaluationContext Unevaluated( + S, Sema::ExpressionEvaluationContext::ConstantEvaluated); + ExprResult SubstResult = S.SubstExpr(OldCond, TemplateArgs); + if (SubstResult.isInvalid()) { + return ExplicitSpecifier::Invalid(); + } + Cond = SubstResult.get(); + } + ExplicitSpecifier Result(Cond, ES.getKind()); + if (!Cond->isTypeDependent()) + S.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.addAMDGPUWavesPerEUAttr(Attr.getLocation(), New, MinExpr, MaxExpr, + Attr.getSpellingListIndex()); +} + void Sema::InstantiateAttrsForDecl( const MultiLevelTemplateArgumentList &TemplateArgs, const Decl *Tmpl, Decl *New, LateInstantiatedAttrVec *LateAttrs, @@ -438,6 +517,18 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, continue; } + if (const AMDGPUFlatWorkGroupSizeAttr *AMDGPUFlatWorkGroupSize = + dyn_cast<AMDGPUFlatWorkGroupSizeAttr>(TmplAttr)) { + instantiateDependentAMDGPUFlatWorkGroupSizeAttr( + *this, TemplateArgs, *AMDGPUFlatWorkGroupSize, New); + } + + if (const AMDGPUWavesPerEUAttr *AMDGPUFlatWorkGroupSize = + dyn_cast<AMDGPUWavesPerEUAttr>(TmplAttr)) { + instantiateDependentAMDGPUWavesPerEUAttr(*this, TemplateArgs, + *AMDGPUFlatWorkGroupSize, New); + } + // Existing DLL attribute on the instantiation takes precedence. if (TmplAttr->getKind() == attr::DLLExport || TmplAttr->getKind() == attr::DLLImport) { @@ -1633,6 +1724,14 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, cast<Decl>(Owner)->isDefinedOutsideFunctionOrMethod()); LocalInstantiationScope Scope(SemaRef, MergeWithParentScope); + ExplicitSpecifier InstantiatedExplicitSpecifier; + if (auto *DGuide = dyn_cast<CXXDeductionGuideDecl>(D)) { + InstantiatedExplicitSpecifier = instantiateExplicitSpecifier( + SemaRef, TemplateArgs, DGuide->getExplicitSpecifier(), DGuide); + if (InstantiatedExplicitSpecifier.isInvalid()) + return nullptr; + } + SmallVector<ParmVarDecl *, 4> Params; TypeSourceInfo *TInfo = SubstFunctionType(D, Params); if (!TInfo) @@ -1670,8 +1769,9 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, FunctionDecl *Function; if (auto *DGuide = dyn_cast<CXXDeductionGuideDecl>(D)) { Function = CXXDeductionGuideDecl::Create( - SemaRef.Context, DC, D->getInnerLocStart(), DGuide->isExplicit(), - NameInfo, T, TInfo, D->getSourceRange().getEnd()); + SemaRef.Context, DC, D->getInnerLocStart(), + InstantiatedExplicitSpecifier, NameInfo, T, TInfo, + D->getSourceRange().getEnd()); if (DGuide->isCopyDeductionCandidate()) cast<CXXDeductionGuideDecl>(Function)->setIsCopyDeductionCandidate(); Function->setAccess(D->getAccess()); @@ -1679,7 +1779,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, Function = FunctionDecl::Create( SemaRef.Context, DC, D->getInnerLocStart(), NameInfo, T, TInfo, D->getCanonicalDecl()->getStorageClass(), D->isInlineSpecified(), - D->hasWrittenPrototype(), D->isConstexpr()); + D->hasWrittenPrototype(), D->getConstexprKind()); Function->setRangeEnd(D->getSourceRange().getEnd()); } @@ -1894,10 +1994,10 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, return Function; } -Decl * -TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, - TemplateParameterList *TemplateParams, - bool IsClassScopeSpecialization) { +Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( + CXXMethodDecl *D, TemplateParameterList *TemplateParams, + Optional<const ASTTemplateArgumentListInfo *> + ClassScopeSpecializationArgs) { FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate(); if (FunctionTemplate && !TemplateParams) { // We are creating a function template specialization from a function @@ -1939,6 +2039,12 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, } } + ExplicitSpecifier InstantiatedExplicitSpecifier = + instantiateExplicitSpecifier(SemaRef, TemplateArgs, + ExplicitSpecifier::getFromDecl(D), D); + if (InstantiatedExplicitSpecifier.isInvalid()) + return nullptr; + SmallVector<ParmVarDecl *, 4> Params; TypeSourceInfo *TInfo = SubstFunctionType(D, Params); if (!TInfo) @@ -1978,11 +2084,10 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, DeclarationNameInfo NameInfo = SemaRef.SubstDeclarationNameInfo(D->getNameInfo(), TemplateArgs); if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) { - Method = CXXConstructorDecl::Create(SemaRef.Context, Record, - StartLoc, NameInfo, T, TInfo, - Constructor->isExplicit(), - Constructor->isInlineSpecified(), - false, Constructor->isConstexpr()); + Method = CXXConstructorDecl::Create( + SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo, + InstantiatedExplicitSpecifier, Constructor->isInlineSpecified(), false, + Constructor->getConstexprKind()); Method->setRangeEnd(Constructor->getEndLoc()); } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) { Method = CXXDestructorDecl::Create(SemaRef.Context, Record, @@ -1993,13 +2098,13 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, } else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) { Method = CXXConversionDecl::Create( SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo, - Conversion->isInlineSpecified(), Conversion->isExplicit(), - Conversion->isConstexpr(), Conversion->getEndLoc()); + Conversion->isInlineSpecified(), InstantiatedExplicitSpecifier, + Conversion->getConstexprKind(), Conversion->getEndLoc()); } else { StorageClass SC = D->isStatic() ? SC_Static : SC_None; Method = CXXMethodDecl::Create(SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo, SC, D->isInlineSpecified(), - D->isConstexpr(), D->getEndLoc()); + D->getConstexprKind(), D->getEndLoc()); } if (D->isInlined()) @@ -2101,7 +2206,8 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, IsExplicitSpecialization = true; } else if (const ASTTemplateArgumentListInfo *Info = - D->getTemplateSpecializationArgsAsWritten()) { + ClassScopeSpecializationArgs.getValueOr( + D->getTemplateSpecializationArgsAsWritten())) { SemaRef.LookupQualifiedName(Previous, DC); TemplateArgumentListInfo ExplicitArgs(Info->getLAngleLoc(), @@ -2116,6 +2222,14 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, Method->setInvalidDecl(); IsExplicitSpecialization = true; + } else if (ClassScopeSpecializationArgs) { + // Class-scope explicit specialization written without explicit template + // arguments. + SemaRef.LookupQualifiedName(Previous, DC); + if (SemaRef.CheckFunctionTemplateSpecialization(Method, nullptr, Previous)) + Method->setInvalidDecl(); + + IsExplicitSpecialization = true; } else if (!FunctionTemplate || TemplateParams || isFriend) { SemaRef.LookupQualifiedName(Previous, Record); @@ -2127,9 +2241,8 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, Previous.clear(); } - if (!IsClassScopeSpecialization) - SemaRef.CheckFunctionDeclaration(nullptr, Method, Previous, - IsExplicitSpecialization); + SemaRef.CheckFunctionDeclaration(nullptr, Method, Previous, + IsExplicitSpecialization); if (D->isPure()) SemaRef.CheckPureMethod(Method, SourceRange()); @@ -2152,6 +2265,12 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, if (D->isDeletedAsWritten()) SemaRef.SetDeclDeleted(Method, Method->getLocation()); + // 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 there's a function template, let our caller handle it. if (FunctionTemplate) { // do nothing @@ -2172,10 +2291,24 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, // 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 if (!IsClassScopeSpecialization) { + } 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; } @@ -2768,38 +2901,8 @@ Decl *TemplateDeclInstantiator::VisitUsingPackDecl(UsingPackDecl *D) { Decl *TemplateDeclInstantiator::VisitClassScopeFunctionSpecializationDecl( ClassScopeFunctionSpecializationDecl *Decl) { CXXMethodDecl *OldFD = Decl->getSpecialization(); - CXXMethodDecl *NewFD = - cast_or_null<CXXMethodDecl>(VisitCXXMethodDecl(OldFD, nullptr, true)); - if (!NewFD) - return nullptr; - - TemplateArgumentListInfo ExplicitTemplateArgs; - TemplateArgumentListInfo *ExplicitTemplateArgsPtr = nullptr; - if (Decl->hasExplicitTemplateArgs()) { - if (SemaRef.Subst(Decl->templateArgs().getArgumentArray(), - Decl->templateArgs().size(), ExplicitTemplateArgs, - TemplateArgs)) - return nullptr; - ExplicitTemplateArgsPtr = &ExplicitTemplateArgs; - } - - LookupResult Previous(SemaRef, NewFD->getNameInfo(), Sema::LookupOrdinaryName, - Sema::ForExternalRedeclaration); - SemaRef.LookupQualifiedName(Previous, SemaRef.CurContext); - if (SemaRef.CheckFunctionTemplateSpecialization( - NewFD, ExplicitTemplateArgsPtr, Previous)) { - NewFD->setInvalidDecl(); - return NewFD; - } - - // Associate the specialization with the pattern. - FunctionDecl *Specialization = cast<FunctionDecl>(Previous.getFoundDecl()); - assert(Specialization && "Class scope Specialization is null"); - SemaRef.Context.setClassScopeSpecializationPattern(Specialization, OldFD); - - // FIXME: If this is a definition, check for redefinition errors! - - return NewFD; + return cast_or_null<CXXMethodDecl>( + VisitCXXMethodDecl(OldFD, nullptr, Decl->getTemplateArgsAsWritten())); } Decl *TemplateDeclInstantiator::VisitOMPThreadPrivateDecl( @@ -2820,6 +2923,32 @@ Decl *TemplateDeclInstantiator::VisitOMPThreadPrivateDecl( return TD; } +Decl *TemplateDeclInstantiator::VisitOMPAllocateDecl(OMPAllocateDecl *D) { + SmallVector<Expr *, 5> Vars; + for (auto *I : D->varlists()) { + 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()) { + auto *AC = cast<OMPAllocatorClause>(C); + ExprResult NewE = SemaRef.SubstExpr(AC->getAllocator(), TemplateArgs); + if (!NewE.isUsable()) + continue; + OMPClause *IC = SemaRef.ActOnOpenMPAllocatorClause( + NewE.get(), AC->getBeginLoc(), AC->getLParenLoc(), AC->getEndLoc()); + Clauses.push_back(IC); + } + + Sema::DeclGroupPtrTy Res = SemaRef.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"); @@ -2925,6 +3054,95 @@ Decl *TemplateDeclInstantiator::VisitOMPDeclareReductionDecl( 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.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>( + SemaRef.CurrentInstantiationScope->findInstantiationOf(PrevDeclInScope) + ->get<Decl *>()); + } + OMPDeclareMapperDecl *NewDMD = SemaRef.ActOnOpenMPDeclareMapperDirectiveStart( + /*S=*/nullptr, Owner, D->getDeclName(), SubstMapperTy, D->getLocation(), + VN, D->getAccess(), PrevDeclInScope); + SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, NewDMD); + SmallVector<OMPClause *, 6> Clauses; + bool IsCorrect = true; + if (!RequiresInstantiation) { + // Copy the mapper variable. + NewDMD->setMapperVarRef(D->getMapperVarRef()); + // Copy map clauses from the original mapper. + for (OMPClause *C : D->clauselists()) + Clauses.push_back(C); + } else { + // Instantiate the mapper variable. + DeclarationNameInfo DirName; + SemaRef.StartOpenMPDSABlock(OMPD_declare_mapper, DirName, /*S=*/nullptr, + (*D->clauselist_begin())->getBeginLoc()); + SemaRef.ActOnOpenMPDeclareMapperDirectiveVarDecl( + NewDMD, /*S=*/nullptr, SubstMapperTy, D->getLocation(), VN); + SemaRef.CurrentInstantiationScope->InstantiatedLocal( + cast<DeclRefExpr>(D->getMapperVarRef())->getDecl(), + cast<DeclRefExpr>(NewDMD->getMapperVarRef())->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->varlists()) { + 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.ActOnOpenMPMapClause( + OldC->getMapTypeModifiers(), OldC->getMapTypeModifiersLoc(), SS, + NewNameInfo, OldC->getMapType(), OldC->isImplicitMapType(), + OldC->getMapLoc(), OldC->getColonLoc(), NewVars, Locs); + Clauses.push_back(NewC); + } + SemaRef.EndOpenMPDSABlock(nullptr); + } + (void)SemaRef.ActOnOpenMPDeclareMapperDirectiveEnd(NewDMD, /*S=*/nullptr, + Clauses); + if (!IsCorrect) + return nullptr; + return NewDMD; +} + Decl *TemplateDeclInstantiator::VisitOMPCapturedExprDecl( OMPCapturedExprDecl * /*D*/) { llvm_unreachable("Should not be met in templates"); @@ -2962,13 +3180,10 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl( "for a member class template"); // Lookup the already-instantiated declaration in the instantiation - // of the class template. FIXME: Diagnose or assert if this fails? - DeclContext::lookup_result Found - = Owner->lookup(ClassTemplate->getDeclName()); - if (Found.empty()) - return nullptr; - ClassTemplateDecl *InstClassTemplate - = dyn_cast<ClassTemplateDecl>(Found.front()); + // of the class template. + ClassTemplateDecl *InstClassTemplate = + cast_or_null<ClassTemplateDecl>(SemaRef.FindInstantiatedDecl( + D->getLocation(), ClassTemplate, TemplateArgs)); if (!InstClassTemplate) return nullptr; @@ -3077,6 +3292,7 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl( // 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, @@ -3094,6 +3310,12 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl( 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. const TemplateArgumentListInfo &TemplateArgsInfo = D->getTemplateArgsInfo(); VarTemplateArgsInfo.setLAngleLoc(TemplateArgsInfo.getLAngleLoc()); @@ -3105,28 +3327,33 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl( // Check that the template argument list is well-formed for this template. SmallVector<TemplateArgument, 4> Converted; - if (SemaRef.CheckTemplateArgumentList( - VarTemplate, VarTemplate->getBeginLoc(), - const_cast<TemplateArgumentListInfo &>(VarTemplateArgsInfo), false, - Converted)) + if (SemaRef.CheckTemplateArgumentList(InstVarTemplate, D->getLocation(), + VarTemplateArgsInfo, false, Converted)) return nullptr; - // Find the variable template specialization declaration that - // corresponds to these arguments. + // Check whether we've already seen a declaration of this specialization. void *InsertPos = nullptr; - if (VarTemplateSpecializationDecl *VarSpec = VarTemplate->findSpecialization( - Converted, InsertPos)) - // If we already have a variable template specialization, return it. - return VarSpec; + VarTemplateSpecializationDecl *PrevDecl = + InstVarTemplate->findSpecialization(Converted, 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(VarTemplate, D, InsertPos, - VarTemplateArgsInfo, Converted); + return VisitVarTemplateSpecializationDecl( + InstVarTemplate, D, InsertPos, VarTemplateArgsInfo, Converted, PrevDecl); } Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl( VarTemplateDecl *VarTemplate, VarDecl *D, void *InsertPos, const TemplateArgumentListInfo &TemplateArgsInfo, - ArrayRef<TemplateArgument> Converted) { + ArrayRef<TemplateArgument> Converted, + VarTemplateSpecializationDecl *PrevDecl) { // Do substitution on the type of the declaration TypeSourceInfo *DI = @@ -3153,8 +3380,8 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl( if (SubstQualifier(D, Var)) return nullptr; - SemaRef.BuildVariableInstantiation(Var, D, TemplateArgs, LateAttrs, - Owner, StartingScope); + SemaRef.BuildVariableInstantiation(Var, D, TemplateArgs, LateAttrs, Owner, + StartingScope, false, PrevDecl); return Var; } @@ -3174,6 +3401,10 @@ Decl *TemplateDeclInstantiator::VisitFriendTemplateDecl(FriendTemplateDecl *D) { return nullptr; } +Decl *TemplateDeclInstantiator::VisitConceptDecl(ConceptDecl *D) { + llvm_unreachable("Concept definitions cannot reside inside a template"); +} + Decl *TemplateDeclInstantiator::VisitDecl(Decl *D) { llvm_unreachable("Unexpected decl"); } @@ -3506,7 +3737,7 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D, Qualifiers ThisTypeQuals; if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) { ThisContext = cast<CXXRecordDecl>(Owner); - ThisTypeQuals = Method->getTypeQualifiers(); + ThisTypeQuals = Method->getMethodQualifiers(); } TypeSourceInfo *NewTInfo @@ -3633,25 +3864,25 @@ static bool addInstantiatedParametersToScope(Sema &S, FunctionDecl *Function, Scope.MakeInstantiatedLocalArgPack(PatternParam); Optional<unsigned> NumArgumentsInExpansion = S.getNumArgumentsInExpansion(PatternParam->getType(), TemplateArgs); - assert(NumArgumentsInExpansion && - "should only be called when all template arguments are known"); - 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::ArgumentPackSubstitutionIndexRAII SubstIndex(S, Arg); - QualType T = S.SubstType(PatternType, TemplateArgs, - FunctionParam->getLocation(), - FunctionParam->getDeclName()); - if (T.isNull()) - return true; - FunctionParam->setType(T); - } + 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::ArgumentPackSubstitutionIndexRAII SubstIndex(S, Arg); + QualType T = S.SubstType(PatternType, TemplateArgs, + FunctionParam->getLocation(), + FunctionParam->getDeclName()); + if (T.isNull()) + return true; + FunctionParam->setType(T); + } - Scope.InstantiatedLocalPackArg(PatternParam, FunctionParam); - ++FParamIdx; + Scope.InstantiatedLocalPackArg(PatternParam, FunctionParam); + ++FParamIdx; + } } } @@ -3882,9 +4113,9 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, // Never instantiate an explicit specialization except if it is a class scope // explicit specialization. - TemplateSpecializationKind TSK = Function->getTemplateSpecializationKind(); - if (TSK == TSK_ExplicitSpecialization && - !Function->getClassScopeSpecializationPattern()) + TemplateSpecializationKind TSK = + Function->getTemplateSpecializationKindForInstantiation(); + if (TSK == TSK_ExplicitSpecialization) return; // Find the function body that we'll be substituting. @@ -3939,6 +4170,14 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, return; } + llvm::TimeTraceScope TimeScope("InstantiateFunction", [&]() { + std::string Name; + llvm::raw_string_ostream OS(Name); + Function->getNameForDiagnostic(OS, getPrintingPolicy(), + /*Qualified=*/true); + return Name; + }); + // 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. @@ -4165,7 +4404,19 @@ void Sema::BuildVariableInstantiation( const MultiLevelTemplateArgumentList &TemplateArgs, LateInstantiatedAttrVec *LateAttrs, DeclContext *Owner, LocalInstantiationScope *StartingScope, - bool InstantiatingVarTemplate) { + 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. @@ -4211,8 +4462,11 @@ void Sema::BuildVariableInstantiation( NewVar->getLocation(), OldVar->getPreviousDecl(), TemplateArgs)) Previous.addDecl(NewPrev); } else if (!isa<VarTemplateSpecializationDecl>(NewVar) && - OldVar->hasLinkage()) + OldVar->hasLinkage()) { LookupQualifiedName(Previous, NewVar->getDeclContext(), false); + } else if (PrevDeclForVarTemplateSpecialization) { + Previous.addDecl(PrevDeclForVarTemplateSpecialization); + } CheckVariableDeclaration(NewVar, Previous); if (!InstantiatingVarTemplate) { @@ -4228,23 +4482,44 @@ void Sema::BuildVariableInstantiation( // Link instantiations of static data members back to the template from // which they were instantiated. - if (NewVar->isStaticDataMember() && !InstantiatingVarTemplate) + // + // 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)); - // Delay instantiation of the initializer for variable templates or inline - // static data members until a definition of the variable is needed. We need - // it right away if the type contains 'auto'. - if ((!isa<VarTemplateSpecializationDecl>(NewVar) && - !InstantiatingVarTemplate && - !(OldVar->isInline() && OldVar->isThisDeclarationADefinition() && - !NewVar->isThisDeclarationADefinition())) || - NewVar->getType()->isUndeducedType()) + // 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. @@ -4344,15 +4619,23 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, if (Var->isInvalidDecl()) return; - VarTemplateSpecializationDecl *VarSpec = - dyn_cast<VarTemplateSpecializationDecl>(Var); - VarDecl *PatternDecl = nullptr, *Def = nullptr; + // 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 variable template specialization, make sure that it is - // non-dependent, then find its instantiation pattern. + // non-dependent. bool InstantiationDependent = false; assert(!TemplateSpecializationType::anyDependentTemplateArguments( VarSpec->getTemplateArgsInfo(), InstantiationDependent) && @@ -4360,37 +4643,6 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, "not type-dependent"); (void)InstantiationDependent; - // Find the variable initialization that we'll be substituting. If the - // pattern was instantiated from a member template, look back further to - // find the real pattern. - assert(VarSpec->getSpecializedTemplate() && - "Specialization without specialized template?"); - llvm::PointerUnion<VarTemplateDecl *, - VarTemplatePartialSpecializationDecl *> PatternPtr = - VarSpec->getSpecializedTemplateOrPartial(); - if (PatternPtr.is<VarTemplatePartialSpecializationDecl *>()) { - VarTemplatePartialSpecializationDecl *Tmpl = - PatternPtr.get<VarTemplatePartialSpecializationDecl *>(); - while (VarTemplatePartialSpecializationDecl *From = - Tmpl->getInstantiatedFromMember()) { - if (Tmpl->isMemberSpecialization()) - break; - - Tmpl = From; - } - PatternDecl = Tmpl; - } else { - VarTemplateDecl *Tmpl = PatternPtr.get<VarTemplateDecl *>(); - while (VarTemplateDecl *From = - Tmpl->getInstantiatedFromMemberTemplate()) { - if (Tmpl->isMemberSpecialization()) - break; - - Tmpl = From; - } - PatternDecl = Tmpl->getTemplatedDecl(); - } - // If this is a static data member template, there might be an // uninstantiated initializer on the declaration. If so, instantiate // it now. @@ -4434,20 +4686,12 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, Local.Exit(); GlobalInstantiations.perform(); } - - // Find actual definition - Def = PatternDecl->getDefinition(getASTContext()); } else { - // If this is a static data member, find its out-of-line definition. - assert(Var->isStaticDataMember() && "not a static data member?"); - PatternDecl = Var->getInstantiatedFromStaticDataMember(); - - assert(PatternDecl && "data member was not instantiated from a template?"); - assert(PatternDecl->isStaticDataMember() && "not a static data member?"); - Def = PatternDecl->getDefinition(); + assert(Var->isStaticDataMember() && PatternDecl->isStaticDataMember() && + "not a static data member?"); } - TemplateSpecializationKind TSK = Var->getTemplateSpecializationKind(); + 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 @@ -4469,7 +4713,6 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, } return; } - } // FIXME: We need to track the instantiation stack in order to know which @@ -4481,18 +4724,17 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, /*Complain*/DefinitionRequired)) return; - - // Never instantiate an explicit specialization. - if (TSK == TSK_ExplicitSpecialization) - 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->isUsableInConstantExpressions(getASTContext())) + !Var->mightBeUsableInConstantExpressions(getASTContext())) return; // Make sure to pass the instantiated variable to the consumer at the end. @@ -5006,7 +5248,8 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, if (isa<ParmVarDecl>(D) || isa<NonTypeTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D) || isa<TemplateTemplateParmDecl>(D) || ((ParentDC->isFunctionOrMethod() || - isa<OMPDeclareReductionDecl>(ParentDC)) && + isa<OMPDeclareReductionDecl>(ParentDC) || + isa<OMPDeclareMapperDecl>(ParentDC)) && ParentDC->isDependentContext()) || (isa<CXXRecordDecl>(D) && cast<CXXRecordDecl>(D)->isLambda())) { // D is a local of some kind. Look into the map of local @@ -5320,7 +5563,8 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) { // Check if the most recent declaration has changed the specialization kind // and removed the need for implicit instantiation. - switch (Var->getMostRecentDecl()->getTemplateSpecializationKind()) { + switch (Var->getMostRecentDecl() + ->getTemplateSpecializationKindForInstantiation()) { case TSK_Undeclared: llvm_unreachable("Cannot instantitiate an undeclared specialization."); case TSK_ExplicitInstantiationDeclaration: |