-//===------- SemaTemplate.cpp - Semantic Analysis for C++ Templates -------===/
+//===------- SemaTemplate.cpp - Semantic Analysis for C++ Templates -------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
-//===----------------------------------------------------------------------===/
+//===----------------------------------------------------------------------===//
//
// This file implements semantic analysis for C++ templates.
-//===----------------------------------------------------------------------===/
+//===----------------------------------------------------------------------===//
#include "TreeTransform.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/TypeVisitor.h"
+#include "clang/Basic/Builtins.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/SmallBitVector.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
+
+#include <iterator>
using namespace clang;
using namespace sema;
R.suppressDiagnostics();
} else {
assert(isa<ClassTemplateDecl>(TD) || isa<TemplateTemplateParmDecl>(TD) ||
- isa<TypeAliasTemplateDecl>(TD) || isa<VarTemplateDecl>(TD));
+ isa<TypeAliasTemplateDecl>(TD) || isa<VarTemplateDecl>(TD) ||
+ isa<BuiltinTemplateDecl>(TD));
TemplateKind =
isa<VarTemplateDecl>(TD) ? TNK_Var_template : TNK_Type_template;
}
Found.getLookupNameInfo(), Found.getLookupKind(), S, &SS,
std::move(FilterCCC), CTK_ErrorRecovery, LookupCtx)) {
Found.setLookupName(Corrected.getCorrection());
- if (Corrected.getCorrectionDecl())
- Found.addDecl(Corrected.getCorrectionDecl());
+ if (auto *ND = Corrected.getFoundDecl())
+ Found.addDecl(ND);
FilterAcceptableTemplateNames(Found);
if (!Found.empty()) {
if (LookupCtx) {
const TemplateArgumentListInfo *TemplateArgs) {
DeclContext *DC = getFunctionLevelDeclContext();
- if (!isAddressOfOperand &&
- isa<CXXMethodDecl>(DC) &&
- cast<CXXMethodDecl>(DC)->isInstance()) {
+ // C++11 [expr.prim.general]p12:
+ // An id-expression that denotes a non-static data member or non-static
+ // member function of a class can only be used:
+ // (...)
+ // - if that id-expression denotes a non-static data member and it
+ // appears in an unevaluated operand.
+ //
+ // If this might be the case, form a DependentScopeDeclRefExpr instead of a
+ // CXXDependentScopeMemberExpr. The former can instantiate to either
+ // DeclRefExpr or MemberExpr depending on lookup results, while the latter is
+ // always a MemberExpr.
+ bool MightBeCxx11UnevalField =
+ getLangOpts().CPlusPlus11 && isUnevaluatedContext();
+
+ if (!MightBeCxx11UnevalField && !isAddressOfOperand &&
+ isa<CXXMethodDecl>(DC) && cast<CXXMethodDecl>(DC)->isInstance()) {
QualType ThisType = cast<CXXMethodDecl>(DC)->getThisType(Context);
// Since the 'this' expression is synthesized, we don't need to
TemplateArgs);
}
+
+/// Determine whether we would be unable to instantiate this template (because
+/// it either has no definition, or is in the process of being instantiated).
+bool Sema::DiagnoseUninstantiableTemplate(SourceLocation PointOfInstantiation,
+ NamedDecl *Instantiation,
+ bool InstantiatedFromMember,
+ const NamedDecl *Pattern,
+ const NamedDecl *PatternDef,
+ TemplateSpecializationKind TSK,
+ bool Complain /*= true*/) {
+ assert(isa<TagDecl>(Instantiation) || isa<FunctionDecl>(Instantiation));
+
+ if (PatternDef && (isa<FunctionDecl>(PatternDef)
+ || !cast<TagDecl>(PatternDef)->isBeingDefined())) {
+ NamedDecl *SuggestedDef = nullptr;
+ if (!hasVisibleDefinition(const_cast<NamedDecl*>(PatternDef), &SuggestedDef,
+ /*OnlyNeedComplete*/false)) {
+ // If we're allowed to diagnose this and recover, do so.
+ bool Recover = Complain && !isSFINAEContext();
+ if (Complain)
+ diagnoseMissingImport(PointOfInstantiation, SuggestedDef,
+ Sema::MissingImportKind::Definition, Recover);
+ return !Recover;
+ }
+ return false;
+ }
+
+
+ QualType InstantiationTy;
+ if (TagDecl *TD = dyn_cast<TagDecl>(Instantiation))
+ InstantiationTy = Context.getTypeDeclType(TD);
+ else
+ InstantiationTy = cast<FunctionDecl>(Instantiation)->getType();
+ if (!Complain || (PatternDef && PatternDef->isInvalidDecl())) {
+ // Say nothing
+ } else if (PatternDef) {
+ Diag(PointOfInstantiation,
+ diag::err_template_instantiate_within_definition)
+ << (TSK != TSK_ImplicitInstantiation)
+ << InstantiationTy;
+ // Not much point in noting the template declaration here, since
+ // we're lexically inside it.
+ Instantiation->setInvalidDecl();
+ } else if (InstantiatedFromMember) {
+ Diag(PointOfInstantiation,
+ diag::err_implicit_instantiate_member_undefined)
+ << InstantiationTy;
+ Diag(Pattern->getLocation(), diag::note_member_declared_at);
+ } else {
+ Diag(PointOfInstantiation, diag::err_template_instantiate_undefined)
+ << (TSK != TSK_ImplicitInstantiation)
+ << InstantiationTy;
+ Diag(Pattern->getLocation(), diag::note_template_decl_here);
+ }
+
+ // In general, Instantiation isn't marked invalid to get more than one
+ // error for multiple undefined instantiations. But the code that does
+ // explicit declaration -> explicit definition conversion can't handle
+ // invalid declarations, so mark as invalid in that case.
+ if (TSK == TSK_ExplicitInstantiationDeclaration)
+ Instantiation->setInvalidDecl();
+ return true;
+}
+
/// DiagnoseTemplateParameterShadow - Produce a diagnostic complaining
/// that the template parameter 'PrevDecl' is being shadowed by a new
/// declaration at location Loc. Returns true to indicate that this is
Diag(Loc, diag::err_template_param_shadow)
<< cast<NamedDecl>(PrevDecl)->getDeclName();
Diag(PrevDecl->getLocation(), diag::note_template_param_here);
- return;
}
/// AdjustDeclIfTemplate - If the given decl happens to be a template, reset
ParsedType DefaultArg) {
assert(S->isTemplateParamScope() &&
"Template type parameter not in template parameter scope!");
- bool Invalid = false;
SourceLocation Loc = ParamNameLoc;
if (!ParamName)
KeyLoc, Loc, Depth, Position, ParamName,
Typename, IsParameterPack);
Param->setAccess(AS_public);
- if (Invalid)
- Param->setInvalidDecl();
if (ParamName) {
maybeDiagnoseTemplateParameterShadow(*this, S, ParamNameLoc, ParamName);
// template-parameter that is not a template parameter pack.
if (DefaultArg && IsParameterPack) {
Diag(EqualLoc, diag::err_template_param_pack_default_arg);
- DefaultArg = ParsedType();
+ DefaultArg = nullptr;
}
// Handle the default argument, if provided.
return Param;
}
- Param->setDefaultArgument(DefaultTInfo, false);
+ Param->setDefaultArgument(DefaultTInfo);
}
return Param;
}
Default = DefaultRes.get();
- Param->setDefaultArgument(Default, false);
+ Param->setDefaultArgument(Default);
}
return Param;
// However, it isn't worth doing.
TemplateArgumentLoc DefaultArg = translateTemplateArgument(*this, Default);
if (DefaultArg.getArgument().getAsTemplate().isNull()) {
- Diag(DefaultArg.getLocation(), diag::err_template_arg_not_class_template)
+ Diag(DefaultArg.getLocation(), diag::err_template_arg_not_valid_template)
<< DefaultArg.getSourceRange();
return Param;
}
UPPC_DefaultArgument))
return Param;
- Param->setDefaultArgument(DefaultArg, false);
+ Param->setDefaultArgument(Context, DefaultArg);
}
return Param;
}
-/// ActOnTemplateParameterList - Builds a TemplateParameterList that
-/// contains the template parameters in Params/NumParams.
+/// ActOnTemplateParameterList - Builds a TemplateParameterList, optionally
+/// constrained by RequiresClause, that contains the template parameters in
+/// Params.
TemplateParameterList *
Sema::ActOnTemplateParameterList(unsigned Depth,
SourceLocation ExportLoc,
SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
- Decl **Params, unsigned NumParams,
- SourceLocation RAngleLoc) {
+ ArrayRef<Decl *> Params,
+ SourceLocation RAngleLoc,
+ Expr *RequiresClause) {
if (ExportLoc.isValid())
Diag(ExportLoc, diag::warn_template_export_unsupported);
- return TemplateParameterList::Create(Context, TemplateLoc, LAngleLoc,
- (NamedDecl**)Params, NumParams,
- RAngleLoc);
+ return TemplateParameterList::Create(
+ Context, TemplateLoc, LAngleLoc,
+ llvm::makeArrayRef((NamedDecl *const *)Params.data(), Params.size()),
+ RAngleLoc, RequiresClause);
}
static void SetNestedNameSpecifier(TagDecl *T, const CXXScopeSpec &SS) {
AccessSpecifier AS, SourceLocation ModulePrivateLoc,
SourceLocation FriendLoc,
unsigned NumOuterTemplateParamLists,
- TemplateParameterList** OuterTemplateParamLists) {
+ TemplateParameterList** OuterTemplateParamLists,
+ SkipBodyInfo *SkipBody) {
assert(TemplateParams && TemplateParams->size() > 0 &&
"No template parameters");
assert(TUK != TUK_Reference && "Can only declare or define class templates");
LookupQualifiedName(Previous, SemanticContext);
} else {
SemanticContext = CurContext;
+
+ // C++14 [class.mem]p14:
+ // If T is the name of a class, then each of the following shall have a
+ // name different from T:
+ // -- every member template of class T
+ if (TUK != TUK_Friend &&
+ DiagnoseClassNameShadow(SemanticContext,
+ DeclarationNameInfo(Name, NameLoc)))
+ return true;
+
LookupName(Previous, S);
}
if (Previous.begin() != Previous.end())
PrevDecl = (*Previous.begin())->getUnderlyingDecl();
+ if (PrevDecl && PrevDecl->isTemplateParameter()) {
+ // Maybe we will complain about the shadowed template parameter.
+ DiagnoseTemplateParameterShadow(NameLoc, PrevDecl);
+ // Just pretend that we didn't see the previous declaration.
+ PrevDecl = nullptr;
+ }
+
// If there is a previous declaration with the same name, check
// whether this is a valid redeclaration.
ClassTemplateDecl *PrevClassTemplate
// Check that the chosen semantic context doesn't already contain a
// declaration of this name as a non-tag type.
- LookupResult Previous(*this, Name, NameLoc, LookupOrdinaryName,
- ForRedeclaration);
+ Previous.clear(LookupOrdinaryName);
DeclContext *LookupContext = SemanticContext;
while (LookupContext->isTransparentContext())
LookupContext = LookupContext->getLookupParent();
}
}
} else if (PrevDecl &&
- !isDeclInScope(PrevDecl, SemanticContext, S, SS.isValid()))
+ !isDeclInScope(Previous.getRepresentativeDecl(), SemanticContext,
+ S, SS.isValid()))
PrevDecl = PrevClassTemplate = nullptr;
+ if (auto *Shadow = dyn_cast_or_null<UsingShadowDecl>(
+ PrevDecl ? Previous.getRepresentativeDecl() : nullptr)) {
+ if (SS.isEmpty() &&
+ !(PrevClassTemplate &&
+ PrevClassTemplate->getDeclContext()->getRedeclContext()->Equals(
+ SemanticContext->getRedeclContext()))) {
+ Diag(KWLoc, diag::err_using_decl_conflict_reverse);
+ Diag(Shadow->getTargetDecl()->getLocation(),
+ diag::note_using_decl_target);
+ Diag(Shadow->getUsingDecl()->getLocation(), diag::note_using_decl) << 0;
+ // Recover by ignoring the old declaration.
+ PrevDecl = PrevClassTemplate = nullptr;
+ }
+ }
+
if (PrevClassTemplate) {
// Ensure that the template parameter lists are compatible. Skip this check
// for a friend in a dependent context: the template parameter list itself
// template declaration (7.1.5.3).
RecordDecl *PrevRecordDecl = PrevClassTemplate->getTemplatedDecl();
if (!isAcceptableTagRedeclaration(PrevRecordDecl, Kind,
- TUK == TUK_Definition, KWLoc, *Name)) {
+ TUK == TUK_Definition, KWLoc, Name)) {
Diag(KWLoc, diag::err_use_with_wrong_tag)
<< Name
<< FixItHint::CreateReplacement(KWLoc, PrevRecordDecl->getKindName());
// Check for redefinition of this class template.
if (TUK == TUK_Definition) {
if (TagDecl *Def = PrevRecordDecl->getDefinition()) {
+ // If we have a prior definition that is not visible, treat this as
+ // simply making that previous definition visible.
+ NamedDecl *Hidden = nullptr;
+ if (SkipBody && !hasVisibleDefinition(Def, &Hidden)) {
+ SkipBody->ShouldSkip = true;
+ auto *Tmpl = cast<CXXRecordDecl>(Hidden)->getDescribedClassTemplate();
+ assert(Tmpl && "original definition of a class template is not a "
+ "class template?");
+ makeMergedDefinitionVisible(Hidden, KWLoc);
+ makeMergedDefinitionVisible(Tmpl, KWLoc);
+ return Def;
+ }
+
Diag(NameLoc, diag::err_redefinition) << Name;
Diag(Def->getLocation(), diag::note_previous_definition);
// FIXME: Would it make sense to try to "forget" the previous
// definition, as part of error recovery?
return true;
}
- }
- } else if (PrevDecl && PrevDecl->isTemplateParameter()) {
- // Maybe we will complain about the shadowed template parameter.
- DiagnoseTemplateParameterShadow(NameLoc, PrevDecl);
- // Just pretend that we didn't see the previous declaration.
- PrevDecl = nullptr;
+ }
} else if (PrevDecl) {
// C++ [temp]p5:
// A class template shall not have the same name as any other
/*DelayTypeCreation=*/true);
SetNestedNameSpecifier(NewClass, SS);
if (NumOuterTemplateParamLists > 0)
- NewClass->setTemplateParameterListsInfo(Context,
- NumOuterTemplateParamLists,
- OuterTemplateParamLists);
+ NewClass->setTemplateParameterListsInfo(
+ Context, llvm::makeArrayRef(OuterTemplateParamLists,
+ NumOuterTemplateParamLists));
// Add alignment attributes if necessary; these attributes are checked when
// the ASTContext lays out the structure.
// Merge default arguments for template type parameters.
TemplateTypeParmDecl *OldTypeParm
= OldParams? cast<TemplateTypeParmDecl>(*OldParam) : nullptr;
-
if (NewTypeParm->isParameterPack()) {
assert(!NewTypeParm->hasDefaultArgument() &&
"Parameter packs can't have a default argument!");
SawParameterPack = true;
- } else if (OldTypeParm && OldTypeParm->hasDefaultArgument() &&
+ } else if (OldTypeParm && hasVisibleDefaultArgument(OldTypeParm) &&
NewTypeParm->hasDefaultArgument()) {
OldDefaultLoc = OldTypeParm->getDefaultArgumentLoc();
NewDefaultLoc = NewTypeParm->getDefaultArgumentLoc();
} else if (OldTypeParm && OldTypeParm->hasDefaultArgument()) {
// Merge the default argument from the old declaration to the
// new declaration.
- NewTypeParm->setDefaultArgument(OldTypeParm->getDefaultArgumentInfo(),
- true);
+ NewTypeParm->setInheritedDefaultArgument(Context, OldTypeParm);
PreviousDefaultArgLoc = OldTypeParm->getDefaultArgumentLoc();
} else if (NewTypeParm->hasDefaultArgument()) {
SawDefaultArgument = true;
"Parameter packs can't have a default argument!");
if (!NewNonTypeParm->isPackExpansion())
SawParameterPack = true;
- } else if (OldNonTypeParm && OldNonTypeParm->hasDefaultArgument() &&
+ } else if (OldNonTypeParm && hasVisibleDefaultArgument(OldNonTypeParm) &&
NewNonTypeParm->hasDefaultArgument()) {
OldDefaultLoc = OldNonTypeParm->getDefaultArgumentLoc();
NewDefaultLoc = NewNonTypeParm->getDefaultArgumentLoc();
} else if (OldNonTypeParm && OldNonTypeParm->hasDefaultArgument()) {
// Merge the default argument from the old declaration to the
// new declaration.
- // FIXME: We need to create a new kind of "default argument"
- // expression that points to a previous non-type template
- // parameter.
- NewNonTypeParm->setDefaultArgument(
- OldNonTypeParm->getDefaultArgument(),
- /*Inherited=*/ true);
+ NewNonTypeParm->setInheritedDefaultArgument(Context, OldNonTypeParm);
PreviousDefaultArgLoc = OldNonTypeParm->getDefaultArgumentLoc();
} else if (NewNonTypeParm->hasDefaultArgument()) {
SawDefaultArgument = true;
"Parameter packs can't have a default argument!");
if (!NewTemplateParm->isPackExpansion())
SawParameterPack = true;
- } else if (OldTemplateParm && OldTemplateParm->hasDefaultArgument() &&
- NewTemplateParm->hasDefaultArgument()) {
+ } else if (OldTemplateParm &&
+ hasVisibleDefaultArgument(OldTemplateParm) &&
+ NewTemplateParm->hasDefaultArgument()) {
OldDefaultLoc = OldTemplateParm->getDefaultArgument().getLocation();
NewDefaultLoc = NewTemplateParm->getDefaultArgument().getLocation();
SawDefaultArgument = true;
} else if (OldTemplateParm && OldTemplateParm->hasDefaultArgument()) {
// Merge the default argument from the old declaration to the
// new declaration.
- // FIXME: We need to create a new kind of "default argument" expression
- // that points to a previous template template parameter.
- NewTemplateParm->setDefaultArgument(
- OldTemplateParm->getDefaultArgument(),
- /*Inherited=*/ true);
+ NewTemplateParm->setInheritedDefaultArgument(Context, OldTemplateParm);
PreviousDefaultArgLoc
= OldTemplateParm->getDefaultArgument().getLocation();
} else if (NewTemplateParm->hasDefaultArgument()) {
return TraverseType(T->getInjectedSpecializationType());
}
};
-}
+} // end anonymous namespace
/// Determines whether a given type depends on the given parameter
/// list.
}
} else if (const TemplateSpecializationType *TST
= T->getAs<TemplateSpecializationType>()) {
- if (TemplateDecl *Template = TST->getTemplateName().getAsTemplateDecl()) {
+ if (TemplateDecl *Template = TST->getTemplateName().getAsTemplateDecl()) {
ExpectedTemplateParams = Template->getTemplateParameters();
NeedNonemptyTemplateHeader = true;
}
// Fabricate an empty template parameter list for the invented header.
return TemplateParameterList::Create(Context, SourceLocation(),
- SourceLocation(), nullptr, 0,
- SourceLocation());
+ SourceLocation(), None,
+ SourceLocation(), nullptr);
}
return nullptr;
}
}
+static QualType
+checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
+ const SmallVectorImpl<TemplateArgument> &Converted,
+ SourceLocation TemplateLoc,
+ TemplateArgumentListInfo &TemplateArgs) {
+ ASTContext &Context = SemaRef.getASTContext();
+ switch (BTD->getBuiltinTemplateKind()) {
+ case BTK__make_integer_seq: {
+ // Specializations of __make_integer_seq<S, T, N> are treated like
+ // S<T, 0, ..., N-1>.
+
+ // C++14 [inteseq.intseq]p1:
+ // T shall be an integer type.
+ if (!Converted[1].getAsType()->isIntegralType(Context)) {
+ SemaRef.Diag(TemplateArgs[1].getLocation(),
+ diag::err_integer_sequence_integral_element_type);
+ return QualType();
+ }
+
+ // C++14 [inteseq.make]p1:
+ // If N is negative the program is ill-formed.
+ TemplateArgument NumArgsArg = Converted[2];
+ llvm::APSInt NumArgs = NumArgsArg.getAsIntegral();
+ if (NumArgs < 0) {
+ SemaRef.Diag(TemplateArgs[2].getLocation(),
+ diag::err_integer_sequence_negative_length);
+ return QualType();
+ }
+
+ QualType ArgTy = NumArgsArg.getIntegralType();
+ TemplateArgumentListInfo SyntheticTemplateArgs;
+ // The type argument gets reused as the first template argument in the
+ // synthetic template argument list.
+ SyntheticTemplateArgs.addArgument(TemplateArgs[1]);
+ // Expand N into 0 ... N-1.
+ for (llvm::APSInt I(NumArgs.getBitWidth(), NumArgs.isUnsigned());
+ I < NumArgs; ++I) {
+ TemplateArgument TA(Context, I, ArgTy);
+ SyntheticTemplateArgs.addArgument(SemaRef.getTrivialTemplateArgumentLoc(
+ TA, ArgTy, TemplateArgs[2].getLocation()));
+ }
+ // The first template argument will be reused as the template decl that
+ // our synthetic template arguments will be applied to.
+ return SemaRef.CheckTemplateIdType(Converted[0].getAsTemplate(),
+ TemplateLoc, SyntheticTemplateArgs);
+ }
+
+ case BTK__type_pack_element:
+ // Specializations of
+ // __type_pack_element<Index, T_1, ..., T_N>
+ // are treated like T_Index.
+ assert(Converted.size() == 2 &&
+ "__type_pack_element should be given an index and a parameter pack");
+
+ // If the Index is out of bounds, the program is ill-formed.
+ TemplateArgument IndexArg = Converted[0], Ts = Converted[1];
+ llvm::APSInt Index = IndexArg.getAsIntegral();
+ assert(Index >= 0 && "the index used with __type_pack_element should be of "
+ "type std::size_t, and hence be non-negative");
+ if (Index >= Ts.pack_size()) {
+ SemaRef.Diag(TemplateArgs[0].getLocation(),
+ diag::err_type_pack_element_out_of_bounds);
+ return QualType();
+ }
+
+ // We simply return the type at index `Index`.
+ auto Nth = std::next(Ts.pack_begin(), Index.getExtValue());
+ return Nth->getAsType();
+ }
+ llvm_unreachable("unexpected BuiltinTemplateDecl!");
+}
+
QualType Sema::CheckTemplateIdType(TemplateName Name,
SourceLocation TemplateLoc,
TemplateArgumentListInfo &TemplateArgs) {
return QualType();
TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
- Converted.data(), Converted.size());
+ Converted);
// Only substitute for the innermost template argument list.
MultiLevelTemplateArgumentList TemplateArgLists;
// template<typename T, typename U = T> struct A;
TemplateName CanonName = Context.getCanonicalTemplateName(Name);
CanonType = Context.getTemplateSpecializationType(CanonName,
- Converted.data(),
- Converted.size());
+ Converted);
// FIXME: CanonType is not actually the canonical type, and unfortunately
// it is a TemplateSpecializationType that we will never use again.
ClassTemplate->getTemplatedDecl()->getLocStart(),
ClassTemplate->getLocation(),
ClassTemplate,
- Converted.data(),
- Converted.size(), nullptr);
+ Converted, nullptr);
ClassTemplate->AddSpecialization(Decl, InsertPos);
if (ClassTemplate->isOutOfLine())
Decl->setLexicalDeclContext(ClassTemplate->getLexicalDeclContext());
CanonType = Context.getTypeDeclType(Decl);
assert(isa<RecordType>(CanonType) &&
"type of non-dependent specialization is not a RecordType");
+ } else if (auto *BTD = dyn_cast<BuiltinTemplateDecl>(Template)) {
+ CanonType = checkBuiltinTemplateIdType(*this, BTD, Converted, TemplateLoc,
+ TemplateArgs);
}
// Build the fully-sugared type for this class template
assert(Id && "templated class must have an identifier");
if (!isAcceptableTagRedeclaration(D, TagKind, TUK == TUK_Definition,
- TagLoc, *Id)) {
+ TagLoc, Id)) {
Diag(TagLoc, diag::err_use_with_wrong_tag)
<< Result
<< FixItHint::CreateReplacement(SourceRange(TagLoc), D->getKindName());
false, Converted))
return true;
- // Check that the type of this variable template specialization
- // matches the expected type.
- TypeSourceInfo *ExpectedDI;
- {
- // Do substitution on the type of the declaration
- TemplateArgumentList TemplateArgList(TemplateArgumentList::OnStack,
- Converted.data(), Converted.size());
- InstantiatingTemplate Inst(*this, TemplateKWLoc, VarTemplate);
- if (Inst.isInvalid())
- return true;
- VarDecl *Templated = VarTemplate->getTemplatedDecl();
- ExpectedDI =
- SubstType(Templated->getTypeSourceInfo(),
- MultiLevelTemplateArgumentList(TemplateArgList),
- Templated->getTypeSpecStartLoc(), Templated->getDeclName());
- }
- if (!ExpectedDI)
- return true;
-
// Find the variable template (partial) specialization declaration that
// corresponds to these arguments.
if (IsPartialSpecialization) {
bool InstantiationDependent;
if (!Name.isDependent() &&
!TemplateSpecializationType::anyDependentTemplateArguments(
- TemplateArgs.getArgumentArray(), TemplateArgs.size(),
+ TemplateArgs.arguments(),
InstantiationDependent)) {
Diag(TemplateNameLoc, diag::err_partial_spec_fully_specialized)
<< VarTemplate->getDeclName();
VarTemplatePartialSpecializationDecl::Create(
Context, VarTemplate->getDeclContext(), TemplateKWLoc,
TemplateNameLoc, TemplateParams, VarTemplate, DI->getType(), DI, SC,
- Converted.data(), Converted.size(), TemplateArgs);
+ Converted, TemplateArgs);
if (!PrevPartial)
VarTemplate->AddPartialSpecialization(Partial, InsertPos);
// this explicit specialization or friend declaration.
Specialization = VarTemplateSpecializationDecl::Create(
Context, VarTemplate->getDeclContext(), TemplateKWLoc, TemplateNameLoc,
- VarTemplate, DI->getType(), DI, SC, Converted.data(), Converted.size());
+ VarTemplate, DI->getType(), DI, SC, Converted);
Specialization->setTemplateArgsInfo(TemplateArgs);
if (!PrevDecl)
VarTemplatePartialSpecializationDecl *Partial;
TemplateArgumentList *Args;
};
-}
+} // end anonymous namespace
DeclResult
Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
// corresponds to these arguments.
void *InsertPos = nullptr;
if (VarTemplateSpecializationDecl *Spec = Template->findSpecialization(
- Converted, InsertPos))
+ Converted, InsertPos)) {
+ checkSpecializationVisibility(TemplateNameLoc, Spec);
// If we already have a variable template specialization, return it.
return Spec;
+ }
// This is the first time we have referenced this variable template
// specialization. Create the canonical declaration and add it to
// that it represents. That is,
VarDecl *InstantiationPattern = Template->getTemplatedDecl();
TemplateArgumentList TemplateArgList(TemplateArgumentList::OnStack,
- Converted.data(), Converted.size());
+ Converted);
TemplateArgumentList *InstantiationArgs = &TemplateArgList;
bool AmbiguousPartialSpec = false;
typedef PartialSpecMatchResult MatchResult;
SmallVector<MatchResult, 4> Matched;
SourceLocation PointOfInstantiation = TemplateNameLoc;
- TemplateSpecCandidateSet FailedCandidates(PointOfInstantiation);
+ TemplateSpecCandidateSet FailedCandidates(PointOfInstantiation,
+ /*ForTakingAddress=*/false);
// 1. Attempt to find the closest partial specialization that this
// specializes, if any.
DeduceTemplateArguments(Partial, TemplateArgList, Info)) {
// Store the failed-deduction information for use in diagnostics, later.
// TODO: Actually use the failed-deduction info?
- FailedCandidates.addCandidate()
- .set(Partial, MakeDeductionFailureInfo(Context, Result, Info));
+ FailedCandidates.addCandidate().set(
+ DeclAccessPair::make(Template, AS_public), Partial,
+ MakeDeductionFailureInfo(Context, Result, Info));
(void)Result;
} else {
Matched.push_back(PartialSpecMatchResult());
}
// 2. Create the canonical declaration.
- // Note that we do not instantiate the variable just yet, since
- // instantiation is handled in DoMarkVarDeclReferenced().
+ // Note that we do not instantiate a definition until we see an odr-use
+ // in DoMarkVarDeclReferenced().
// FIXME: LateAttrs et al.?
VarTemplateSpecializationDecl *Decl = BuildVarTemplateInstantiation(
Template, InstantiationPattern, *InstantiationArgs, TemplateArgs,
dyn_cast<VarTemplatePartialSpecializationDecl>(InstantiationPattern))
Decl->setInstantiationOf(D, InstantiationArgs);
+ checkSpecializationVisibility(TemplateNameLoc, Decl);
+
assert(Decl && "No variable template specialization?");
return Decl;
}
if (Inst.isInvalid())
return nullptr;
- TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
- Converted.data(), Converted.size());
+ TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted);
// Only substitute for the innermost template argument list.
MultiLevelTemplateArgumentList TemplateArgLists;
if (Inst.isInvalid())
return ExprError();
- TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
- Converted.data(), Converted.size());
+ TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted);
// Only substitute for the innermost template argument list.
MultiLevelTemplateArgumentList TemplateArgLists;
for (unsigned i = 0, e = Param->getDepth(); i != e; ++i)
TemplateArgLists.addOuterTemplateArguments(None);
- Sema::ContextRAII SavedContext(SemaRef, Template->getDeclContext());
- EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
+ EnterExpressionEvaluationContext ConstantEvaluated(SemaRef,
+ Sema::ConstantEvaluated);
return SemaRef.SubstExpr(Param->getDefaultArgument(), TemplateArgLists);
}
if (Inst.isInvalid())
return TemplateName();
- TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
- Converted.data(), Converted.size());
+ TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted);
// Only substitute for the innermost template argument list.
MultiLevelTemplateArgumentList TemplateArgLists;
HasDefaultArg = false;
if (TemplateTypeParmDecl *TypeParm = dyn_cast<TemplateTypeParmDecl>(Param)) {
- if (!TypeParm->hasDefaultArgument())
+ if (!hasVisibleDefaultArgument(TypeParm))
return TemplateArgumentLoc();
HasDefaultArg = true;
if (NonTypeTemplateParmDecl *NonTypeParm
= dyn_cast<NonTypeTemplateParmDecl>(Param)) {
- if (!NonTypeParm->hasDefaultArgument())
+ if (!hasVisibleDefaultArgument(NonTypeParm))
return TemplateArgumentLoc();
HasDefaultArg = true;
TemplateTemplateParmDecl *TempTempParm
= cast<TemplateTemplateParmDecl>(Param);
- if (!TempTempParm->hasDefaultArgument())
+ if (!hasVisibleDefaultArgument(TempTempParm))
return TemplateArgumentLoc();
HasDefaultArg = true;
return true;
TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
- Converted.data(), Converted.size());
+ Converted);
NTTPType = SubstType(NTTPType,
MultiLevelTemplateArgumentList(TemplateArgs),
NTTP->getLocation(),
if (Inst.isInvalid())
return true;
- TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
- Converted.data(), Converted.size());
+ TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted);
TempParm = cast_or_null<TemplateTemplateParmDecl>(
SubstDecl(TempParm, CurContext,
MultiLevelTemplateArgumentList(TemplateArgs)));
return None;
}
+/// Diagnose a missing template argument.
+template<typename TemplateParmDecl>
+static bool diagnoseMissingArgument(Sema &S, SourceLocation Loc,
+ TemplateDecl *TD,
+ const TemplateParmDecl *D,
+ TemplateArgumentListInfo &Args) {
+ // Dig out the most recent declaration of the template parameter; there may be
+ // declarations of the template that are more recent than TD.
+ D = cast<TemplateParmDecl>(cast<TemplateDecl>(TD->getMostRecentDecl())
+ ->getTemplateParameters()
+ ->getParam(D->getIndex()));
+
+ // If there's a default argument that's not visible, diagnose that we're
+ // missing a module import.
+ llvm::SmallVector<Module*, 8> Modules;
+ if (D->hasDefaultArgument() && !S.hasVisibleDefaultArgument(D, &Modules)) {
+ S.diagnoseMissingImport(Loc, cast<NamedDecl>(TD),
+ D->getDefaultArgumentLoc(), Modules,
+ Sema::MissingImportKind::DefaultArgument,
+ /*Recover*/true);
+ return true;
+ }
+
+ // FIXME: If there's a more recent default argument that *is* visible,
+ // diagnose that it was declared too late.
+
+ return diagnoseArityMismatch(S, TD, Loc, Args);
+}
+
/// \brief Check that the given template argument list is well-formed
/// for specializing the given template.
bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
// We're done with this parameter pack. Pack up its arguments and add
// them to the list.
Converted.push_back(
- TemplateArgument::CreatePackCopy(Context,
- ArgumentPack.data(),
- ArgumentPack.size()));
+ TemplateArgument::CreatePackCopy(Context, ArgumentPack));
ArgumentPack.clear();
// This argument is assigned to the next parameter.
// If we're checking a partial template argument list, we're done.
if (PartialTemplateArgs) {
if ((*Param)->isTemplateParameterPack() && !ArgumentPack.empty())
- Converted.push_back(TemplateArgument::CreatePackCopy(Context,
- ArgumentPack.data(),
- ArgumentPack.size()));
-
+ Converted.push_back(
+ TemplateArgument::CreatePackCopy(Context, ArgumentPack));
+
return false;
}
if (Param + 1 != ParamEnd)
return true;
- Converted.push_back(TemplateArgument::CreatePackCopy(Context,
- ArgumentPack.data(),
- ArgumentPack.size()));
+ Converted.push_back(
+ TemplateArgument::CreatePackCopy(Context, ArgumentPack));
ArgumentPack.clear();
++Param;
// (when the template parameter was part of a nested template) into
// the default argument.
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
- if (!TTP->hasDefaultArgument())
- return diagnoseArityMismatch(*this, Template, TemplateLoc, NewArgs);
+ if (!hasVisibleDefaultArgument(TTP))
+ return diagnoseMissingArgument(*this, TemplateLoc, Template, TTP,
+ NewArgs);
TypeSourceInfo *ArgType = SubstDefaultTemplateArgument(*this,
Template,
ArgType);
} else if (NonTypeTemplateParmDecl *NTTP
= dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
- if (!NTTP->hasDefaultArgument())
- return diagnoseArityMismatch(*this, Template, TemplateLoc, NewArgs);
+ if (!hasVisibleDefaultArgument(NTTP))
+ return diagnoseMissingArgument(*this, TemplateLoc, Template, NTTP,
+ NewArgs);
ExprResult E = SubstDefaultTemplateArgument(*this, Template,
TemplateLoc,
TemplateTemplateParmDecl *TempParm
= cast<TemplateTemplateParmDecl>(*Param);
- if (!TempParm->hasDefaultArgument())
- return diagnoseArityMismatch(*this, Template, TemplateLoc, NewArgs);
+ if (!hasVisibleDefaultArgument(TempParm))
+ return diagnoseMissingArgument(*this, TemplateLoc, Template, TempParm,
+ NewArgs);
NestedNameSpecifierLoc QualifierLoc;
TemplateName Name = SubstDefaultTemplateArgument(*this, Template,
// No problems found with the new argument list, propagate changes back
// to caller.
- TemplateArgs = NewArgs;
+ TemplateArgs = std::move(NewArgs);
return false;
}
bool VisitTagDecl(const TagDecl *Tag);
bool VisitNestedNameSpecifier(NestedNameSpecifier *NNS);
};
-}
+} // end anonymous namespace
bool UnnamedLocalNoLinkageFinder::VisitBuiltinType(const BuiltinType*) {
return false;
return Visit(T->getValueType());
}
+bool UnnamedLocalNoLinkageFinder::VisitPipeType(const PipeType* T) {
+ return false;
+}
+
bool UnnamedLocalNoLinkageFinder::VisitTagDecl(const TagDecl *Tag) {
if (Tag->getDeclContext()->isFunctionOrMethod()) {
S.Diag(SR.getBegin(),
llvm_unreachable("Invalid NestedNameSpecifier::Kind!");
}
-
/// \brief Check a template argument against its corresponding
/// template type parameter.
///
QualType ParamType, Expr *Arg) {
if (Arg->isValueDependent() || Arg->isTypeDependent())
return NPV_NotNullPointer;
-
+
+ if (!S.isCompleteType(Arg->getExprLoc(), ParamType))
+ llvm_unreachable(
+ "Incomplete parameter type in isNullPointerValueTemplateArgument!");
+
if (!S.getLangOpts().CPlusPlus11)
return NPV_NotNullPointer;
S.Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null);
Converted = TemplateArgument(S.Context.getCanonicalType(ParamType),
/*isNullPtr*/true);
- if (S.Context.getTargetInfo().getCXXABI().isMicrosoft())
- S.RequireCompleteType(Arg->getExprLoc(), ParamType, 0);
return false;
case NPV_NotNullPointer:
break;
// partial specializations.
if (!isa<ClassTemplateDecl>(Template) &&
!isa<TemplateTemplateParmDecl>(Template) &&
- !isa<TypeAliasTemplateDecl>(Template)) {
+ !isa<TypeAliasTemplateDecl>(Template) &&
+ !isa<BuiltinTemplateDecl>(Template)) {
assert(isa<FunctionTemplateDecl>(Template) &&
"Only function templates are possible here");
- Diag(Arg.getLocation(), diag::err_template_arg_not_class_template);
+ Diag(Arg.getLocation(), diag::err_template_arg_not_valid_template);
Diag(Template->getLocation(), diag::note_template_arg_refers_here_func)
<< Template;
}
Expr *E;
if (T->isAnyCharacterType()) {
+ // This does not need to handle u8 character literals because those are
+ // of type char, and so can also be covered by an ASCII character literal.
CharacterLiteral::CharacterKind Kind;
if (T->isWideCharType())
Kind = CharacterLiteral::Wide;
if (isa<TranslationUnitDecl>(SpecializedContext))
S.Diag(Loc, diag::err_template_spec_redecl_global_scope)
<< EntityKind << Specialized;
- else if (isa<NamespaceDecl>(SpecializedContext))
- S.Diag(Loc, diag::err_template_spec_redecl_out_of_scope)
- << EntityKind << Specialized
- << cast<NamedDecl>(SpecializedContext);
- else
+ else if (isa<NamespaceDecl>(SpecializedContext)) {
+ int Diag = diag::err_template_spec_redecl_out_of_scope;
+ if (S.getLangOpts().MicrosoftExt)
+ Diag = diag::ext_ms_template_spec_redecl_out_of_scope;
+ S.Diag(Loc, Diag) << EntityKind << Specialized
+ << cast<NamedDecl>(SpecializedContext);
+ } else
llvm_unreachable("unexpected namespace context for specialization");
S.Diag(Specialized->getLocation(), diag::note_specialized_entity);
SourceLocation ModulePrivateLoc,
TemplateIdAnnotation &TemplateId,
AttributeList *Attr,
- MultiTemplateParamsArg TemplateParameterLists) {
+ MultiTemplateParamsArg
+ TemplateParameterLists,
+ SkipBodyInfo *SkipBody) {
assert(TUK != TUK_Reference && "References are not specializations");
CXXScopeSpec &SS = TemplateId.SS;
assert(Kind != TTK_Enum && "Invalid enum tag in class template spec!");
if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(),
Kind, TUK == TUK_Definition, KWLoc,
- *ClassTemplate->getIdentifier())) {
+ ClassTemplate->getIdentifier())) {
Diag(KWLoc, diag::err_use_with_wrong_tag)
<< ClassTemplate
<< FixItHint::CreateReplacement(KWLoc,
bool InstantiationDependent;
if (!Name.isDependent() &&
!TemplateSpecializationType::anyDependentTemplateArguments(
- TemplateArgs.getArgumentArray(),
- TemplateArgs.size(),
- InstantiationDependent)) {
+ TemplateArgs.arguments(), InstantiationDependent)) {
Diag(TemplateNameLoc, diag::err_partial_spec_fully_specialized)
<< ClassTemplate->getDeclName();
isPartialSpecialization = false;
// arguments of the class template partial specialization.
TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name);
CanonType = Context.getTemplateSpecializationType(CanonTemplate,
- Converted.data(),
- Converted.size());
+ Converted);
if (Context.hasSameType(CanonType,
ClassTemplate->getInjectedClassNameSpecialization())) {
KWLoc, TemplateNameLoc,
TemplateParams,
ClassTemplate,
- Converted.data(),
- Converted.size(),
+ Converted,
TemplateArgs,
CanonType,
PrevPartial);
SetNestedNameSpecifier(Partial, SS);
if (TemplateParameterLists.size() > 1 && SS.isSet()) {
- Partial->setTemplateParameterListsInfo(Context,
- TemplateParameterLists.size() - 1,
- TemplateParameterLists.data());
+ Partial->setTemplateParameterListsInfo(
+ Context, TemplateParameterLists.drop_back(1));
}
if (!PrevPartial)
ClassTemplate->getDeclContext(),
KWLoc, TemplateNameLoc,
ClassTemplate,
- Converted.data(),
- Converted.size(),
+ Converted,
PrevDecl);
SetNestedNameSpecifier(Specialization, SS);
if (TemplateParameterLists.size() > 0) {
Specialization->setTemplateParameterListsInfo(Context,
- TemplateParameterLists.size(),
- TemplateParameterLists.data());
+ TemplateParameterLists);
}
if (!PrevDecl)
ClassTemplate->AddSpecialization(Specialization, InsertPos);
- CanonType = Context.getTypeDeclType(Specialization);
+ if (CurContext->isDependentContext()) {
+ // -fms-extensions permits specialization of nested classes without
+ // fully specializing the outer class(es).
+ assert(getLangOpts().MicrosoftExt &&
+ "Only possible with -fms-extensions!");
+ TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name);
+ CanonType = Context.getTemplateSpecializationType(
+ CanonTemplate, Converted);
+ } else {
+ CanonType = Context.getTypeDeclType(Specialization);
+ }
}
// C++ [temp.expl.spec]p6:
// Check that this isn't a redefinition of this specialization.
if (TUK == TUK_Definition) {
- if (RecordDecl *Def = Specialization->getDefinition()) {
+ RecordDecl *Def = Specialization->getDefinition();
+ NamedDecl *Hidden = nullptr;
+ if (Def && SkipBody && !hasVisibleDefinition(Def, &Hidden)) {
+ SkipBody->ShouldSkip = true;
+ makeMergedDefinitionVisible(Hidden, KWLoc);
+ // From here on out, treat this as just a redeclaration.
+ TUK = TUK_Declaration;
+ } else if (Def) {
SourceRange Range(TemplateNameLoc, RAngleLoc);
Diag(TemplateNameLoc, diag::err_redefinition)
<< Context.getTypeDeclType(Specialization) << Range;
return NewDecl;
}
-Decl *Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope,
- MultiTemplateParamsArg TemplateParameterLists,
- Declarator &D) {
- assert(getCurFunctionDecl() == nullptr && "Function parsing confused");
- DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo();
-
- if (FTI.hasPrototype) {
- // FIXME: Diagnose arguments without names in C.
- }
-
- Scope *ParentScope = FnBodyScope->getParent();
-
- D.setFunctionDefinitionKind(FDK_Definition);
- Decl *DP = HandleDeclarator(ParentScope, D,
- TemplateParameterLists);
- return ActOnStartOfFunctionDef(FnBodyScope, DP);
-}
-
/// \brief Strips various properties off an implicit instantiation
/// that has just been explicitly specialized.
static void StripImplicitInstantiation(NamedDecl *D) {
// The set of function template specializations that could match this
// explicit function template specialization.
UnresolvedSet<8> Candidates;
- TemplateSpecCandidateSet FailedCandidates(FD->getLocation());
+ TemplateSpecCandidateSet FailedCandidates(FD->getLocation(),
+ /*ForTakingAddress=*/false);
+
+ llvm::SmallDenseMap<FunctionDecl *, TemplateArgumentListInfo, 8>
+ ConvertedTemplateArgs;
DeclContext *FDLookupContext = FD->getDeclContext()->getRedeclContext();
for (LookupResult::iterator I = Previous.begin(), E = Previous.end();
}
}
+ TemplateArgumentListInfo Args;
+ if (ExplicitTemplateArgs)
+ Args = *ExplicitTemplateArgs;
+
// C++ [temp.expl.spec]p11:
// A trailing template-argument can be left unspecified in the
// template-id naming an explicit function template specialization
FunctionDecl *Specialization = nullptr;
if (TemplateDeductionResult TDK = DeduceTemplateArguments(
cast<FunctionTemplateDecl>(FunTmpl->getFirstDecl()),
- ExplicitTemplateArgs, FT, Specialization, Info)) {
+ ExplicitTemplateArgs ? &Args : nullptr, FT, Specialization,
+ Info)) {
// Template argument deduction failed; record why it failed, so
// that we can provide nifty diagnostics.
- FailedCandidates.addCandidate()
- .set(FunTmpl->getTemplatedDecl(),
- MakeDeductionFailureInfo(Context, TDK, Info));
+ FailedCandidates.addCandidate().set(
+ I.getPair(), FunTmpl->getTemplatedDecl(),
+ MakeDeductionFailureInfo(Context, TDK, Info));
(void)TDK;
continue;
}
// Record this candidate.
+ if (ExplicitTemplateArgs)
+ ConvertedTemplateArgs[Specialization] = std::move(Args);
Candidates.addDecl(Specialization, I.getAccess());
}
}
// Ignore access information; it doesn't figure into redeclaration checking.
FunctionDecl *Specialization = cast<FunctionDecl>(*Result);
+ // C++ Concepts TS [dcl.spec.concept]p7: A program shall not declare [...]
+ // an explicit specialization (14.8.3) [...] of a concept definition.
+ if (Specialization->getPrimaryTemplate()->isConcept()) {
+ Diag(FD->getLocation(), diag::err_concept_specialized)
+ << 0 /*function*/ << 1 /*explicitly specialized*/;
+ Diag(Specialization->getLocation(), diag::note_previous_declaration);
+ return true;
+ }
+
FunctionTemplateSpecializationInfo *SpecInfo
= Specialization->getTemplateSpecializationInfo();
assert(SpecInfo && "Function template specialization info missing?");
// Mark the prior declaration as an explicit specialization, so that later
// clients know that this is an explicit specialization.
if (!isFriend) {
+ // Since explicit specializations do not inherit '=delete' from their
+ // primary function template - check if the 'specialization' that was
+ // implicitly generated (during template argument deduction for partial
+ // ordering) from the most specialized of all the function templates that
+ // 'FD' could have been specializing, has a 'deleted' definition. If so,
+ // first check that it was implicitly generated during template argument
+ // deduction by making sure it wasn't referenced, and then reset the deleted
+ // flag to not-deleted, so that we can inherit that information from 'FD'.
+ if (Specialization->isDeleted() && !SpecInfo->isExplicitSpecialization() &&
+ !Specialization->getCanonicalDecl()->isReferenced()) {
+ assert(
+ Specialization->getCanonicalDecl() == Specialization &&
+ "This must be the only existing declaration of this specialization");
+ Specialization->setDeletedAsWritten(false);
+ }
SpecInfo->setTemplateSpecializationKind(TSK_ExplicitSpecialization);
MarkUnusedFileScopedDecl(Specialization);
}
// Take copies of (semantic and syntactic) template argument lists.
const TemplateArgumentList* TemplArgs = new (Context)
TemplateArgumentList(Specialization->getTemplateSpecializationArgs());
- FD->setFunctionTemplateSpecialization(Specialization->getPrimaryTemplate(),
- TemplArgs, /*InsertPos=*/nullptr,
- SpecInfo->getTemplateSpecializationKind(),
- ExplicitTemplateArgs);
+ FD->setFunctionTemplateSpecialization(
+ Specialization->getPrimaryTemplate(), TemplArgs, /*InsertPos=*/nullptr,
+ SpecInfo->getTemplateSpecializationKind(),
+ ExplicitTemplateArgs ? &ConvertedTemplateArgs[Specialization] : nullptr);
// The "previous declaration" for this function template specialization is
// the prior function template specialization.
assert(!isa<TemplateDecl>(Member) && "Only for non-template members");
// Try to find the member we are instantiating.
+ NamedDecl *FoundInstantiation = nullptr;
NamedDecl *Instantiation = nullptr;
NamedDecl *InstantiatedFrom = nullptr;
MemberSpecializationInfo *MSInfo = nullptr;
if (!hasExplicitCallingConv(Adjusted))
Adjusted = adjustCCAndNoReturn(Adjusted, Method->getType());
if (Context.hasSameType(Adjusted, Method->getType())) {
+ FoundInstantiation = *I;
Instantiation = Method;
InstantiatedFrom = Method->getInstantiatedFromMemberFunction();
MSInfo = Method->getMemberSpecializationInfo();
if (Previous.isSingleResult() &&
(PrevVar = dyn_cast<VarDecl>(Previous.getFoundDecl())))
if (PrevVar->isStaticDataMember()) {
+ FoundInstantiation = Previous.getRepresentativeDecl();
Instantiation = PrevVar;
InstantiatedFrom = PrevVar->getInstantiatedFromStaticDataMember();
MSInfo = PrevVar->getMemberSpecializationInfo();
CXXRecordDecl *PrevRecord;
if (Previous.isSingleResult() &&
(PrevRecord = dyn_cast<CXXRecordDecl>(Previous.getFoundDecl()))) {
+ FoundInstantiation = Previous.getRepresentativeDecl();
Instantiation = PrevRecord;
InstantiatedFrom = PrevRecord->getInstantiatedFromMemberClass();
MSInfo = PrevRecord->getMemberSpecializationInfo();
EnumDecl *PrevEnum;
if (Previous.isSingleResult() &&
(PrevEnum = dyn_cast<EnumDecl>(Previous.getFoundDecl()))) {
+ FoundInstantiation = Previous.getRepresentativeDecl();
Instantiation = PrevEnum;
InstantiatedFrom = PrevEnum->getInstantiatedFromMemberEnum();
MSInfo = PrevEnum->getMemberSpecializationInfo();
}
Previous.clear();
- Previous.addDecl(Instantiation);
+ Previous.addDecl(FoundInstantiation);
return false;
}
InstantiationFunction->setTemplateSpecializationKind(
TSK_ExplicitSpecialization);
InstantiationFunction->setLocation(Member->getLocation());
+ // Explicit specializations of member functions of class templates do not
+ // inherit '=delete' from the member function they are specializing.
+ if (InstantiationFunction->isDeleted()) {
+ assert(InstantiationFunction->getCanonicalDecl() ==
+ InstantiationFunction);
+ InstantiationFunction->setDeletedAsWritten(false);\r
+ }
}
cast<FunctionDecl>(Member)->setInstantiationOfMemberFunction(
// Save the caller the trouble of having to figure out which declaration
// this specialization matches.
Previous.clear();
- Previous.addDecl(Instantiation);
+ Previous.addDecl(FoundInstantiation);
return false;
}
assert(Kind != TTK_Enum &&
"Invalid enum tag in class template explicit instantiation!");
- if (isa<TypeAliasTemplateDecl>(TD)) {
- Diag(KWLoc, diag::err_tag_reference_non_tag) << Kind;
- Diag(TD->getTemplatedDecl()->getLocation(),
- diag::note_previous_use);
+ ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(TD);
+
+ if (!ClassTemplate) {
+ unsigned ErrorKind = 0;
+ if (isa<TypeAliasTemplateDecl>(TD)) {
+ ErrorKind = 4;
+ } else if (isa<TemplateTemplateParmDecl>(TD)) {
+ ErrorKind = 5;
+ }
+
+ Diag(TemplateNameLoc, diag::err_tag_reference_non_tag) << ErrorKind;
+ Diag(TD->getLocation(), diag::note_previous_use);
return true;
}
- ClassTemplateDecl *ClassTemplate = cast<ClassTemplateDecl>(TD);
-
if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(),
Kind, /*isDefinition*/false, KWLoc,
- *ClassTemplate->getIdentifier())) {
+ ClassTemplate->getIdentifier())) {
Diag(KWLoc, diag::err_use_with_wrong_tag)
<< ClassTemplate
<< FixItHint::CreateReplacement(KWLoc,
}
}
+ // In MSVC mode, dllimported explicit instantiation definitions are treated as
+ // instantiation declarations for most purposes.
+ bool DLLImportExplicitInstantiationDef = false;
+ if (TSK == TSK_ExplicitInstantiationDefinition &&
+ Context.getTargetInfo().getCXXABI().isMicrosoft()) {
+ // Check for dllimport class template instantiation definitions.
+ bool DLLImport =
+ ClassTemplate->getTemplatedDecl()->getAttr<DLLImportAttr>();
+ for (AttributeList *A = Attr; A; A = A->getNext()) {
+ if (A->getKind() == AttributeList::AT_DLLImport)
+ DLLImport = true;
+ if (A->getKind() == AttributeList::AT_DLLExport) {
+ // dllexport trumps dllimport here.
+ DLLImport = false;
+ break;
+ }
+ }
+ if (DLLImport) {
+ TSK = TSK_ExplicitInstantiationDeclaration;
+ DLLImportExplicitInstantiationDef = true;
+ }
+ }
+
// Translate the parser's template argument list in our AST format.
TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc);
translateTemplateArguments(TemplateArgsIn, TemplateArgs);
Specialization->setLocation(TemplateNameLoc);
PrevDecl = nullptr;
}
+
+ if (PrevDecl_TSK == TSK_ExplicitInstantiationDeclaration &&
+ DLLImportExplicitInstantiationDef) {
+ // The new specialization might add a dllimport attribute.
+ HasNoEffect = false;
+ }
}
if (!Specialization) {
ClassTemplate->getDeclContext(),
KWLoc, TemplateNameLoc,
ClassTemplate,
- Converted.data(),
- Converted.size(),
+ Converted,
PrevDecl);
SetNestedNameSpecifier(Specialization, SS);
// Set source locations for keywords.
Specialization->setExternLoc(ExternLoc);
Specialization->setTemplateKeywordLoc(TemplateLoc);
- Specialization->setRBraceLoc(SourceLocation());
+ Specialization->setBraceRange(SourceRange());
if (Attr)
ProcessDeclAttributeList(S, Specialization, Attr);
Specialization->getDefinition());
if (Def) {
TemplateSpecializationKind Old_TSK = Def->getTemplateSpecializationKind();
-
// Fix a TSK_ExplicitInstantiationDeclaration followed by a
// TSK_ExplicitInstantiationDefinition
if (Old_TSK == TSK_ExplicitInstantiationDeclaration &&
- TSK == TSK_ExplicitInstantiationDefinition)
+ (TSK == TSK_ExplicitInstantiationDefinition ||
+ DLLImportExplicitInstantiationDef)) {
// FIXME: Need to notify the ASTMutationListener that we did this.
Def->setTemplateSpecializationKind(TSK);
+ if (!getDLLAttr(Def) && getDLLAttr(Specialization) &&
+ Context.getTargetInfo().getCXXABI().isMicrosoft()) {
+ // In the MS ABI, an explicit instantiation definition can add a dll
+ // attribute to a template with a previous instantiation declaration.
+ // MinGW doesn't allow this.
+ auto *A = cast<InheritableAttr>(
+ getDLLAttr(Specialization)->clone(getASTContext()));
+ A->setInherited(true);
+ Def->addAttr(A);
+
+ // We reject explicit instantiations in class scope, so there should
+ // never be any delayed exported classes to worry about.
+ assert(DelayedDllExportClasses.empty() &&
+ "delayed exports present at explicit instantiation");
+ checkClassLevelDLLAttribute(Def);
+ referenceDLLExportedClassMethods();
+
+ // Propagate attribute to base class templates.
+ for (auto &B : Def->bases()) {
+ if (auto *BT = dyn_cast_or_null<ClassTemplateSpecializationDecl>(
+ B.getType()->getAsCXXRecordDecl()))
+ propagateDLLAttrToBaseClassTemplate(Def, A, BT, B.getLocStart());
+ }
+ }
+ }
+
+ // Set the template specialization kind. Make sure it is set before
+ // instantiating the members which will trigger ASTConsumer callbacks.
+ Specialization->setTemplateSpecializationKind(TSK);
InstantiateClassTemplateSpecializationMembers(TemplateNameLoc, Def, TSK);
+ } else {
+
+ // Set the template specialization kind.
+ Specialization->setTemplateSpecializationKind(TSK);
}
- // Set the template specialization kind.
- Specialization->setTemplateSpecializationKind(TSK);
return Specialization;
}
Diag(D.getDeclSpec().getConstexprSpecLoc(),
diag::err_explicit_instantiation_constexpr);
+ // C++ Concepts TS [dcl.spec.concept]p1: The concept specifier shall be
+ // applied only to the definition of a function template or variable template,
+ // declared in namespace scope.
+ if (D.getDeclSpec().isConceptSpecified()) {
+ Diag(D.getDeclSpec().getConceptSpecLoc(),
+ diag::err_concept_specified_specialization) << 0;
+ return true;
+ }
+
// C++0x [temp.explicit]p2:
// There are two forms of explicit instantiation: an explicit instantiation
// definition and an explicit instantiation declaration. An explicit
return true;
}
+ // C++ Concepts TS [dcl.spec.concept]p7: A program shall not declare an
+ // explicit instantiation (14.8.2) [...] of a concept definition.
+ if (PrevTemplate->isConcept()) {
+ Diag(D.getIdentifierLoc(), diag::err_concept_specialized)
+ << 1 /*variable*/ << 0 /*explicitly instantiated*/;
+ Diag(PrevTemplate->getLocation(), diag::note_previous_declaration);
+ return true;
+ }
+
// Translate the parser's template argument list into our AST format.
TemplateArgumentListInfo TemplateArgs =
makeTemplateArgumentListInfo(*this, *D.getName().TemplateId);
R, Specialization, Info)) {
// Keep track of almost-matches.
FailedCandidates.addCandidate()
- .set(FunTmpl->getTemplatedDecl(),
+ .set(P.getPair(), FunTmpl->getTemplatedDecl(),
MakeDeductionFailureInfo(Context, TDK, Info));
(void)TDK;
continue;
diag::ext_explicit_instantiation_without_qualified_id)
<< Specialization << D.getCXXScopeSpec().getRange();
+ // C++ Concepts TS [dcl.spec.concept]p7: A program shall not declare an
+ // explicit instantiation (14.8.2) [...] of a concept definition.
+ if (FunTmpl && FunTmpl->isConcept() &&
+ !D.getDeclSpec().isConceptSpecified()) {
+ Diag(D.getIdentifierLoc(), diag::err_concept_specialized)
+ << 0 /*function*/ << 0 /*explicitly instantiated*/;
+ Diag(FunTmpl->getLocation(), diag::note_previous_declaration);
+ return true;
+ }
+
CheckExplicitInstantiationScope(*this,
FunTmpl? (NamedDecl *)FunTmpl
: Specialization->getInstantiatedFromMemberFunction(),
return E;
}
};
-}
+} // end anonymous namespace
/// \brief Rebuilds a type within the context of the current instantiation.
///
// Take tokens to avoid allocations
LPT->Toks.swap(Toks);
LPT->D = FnD;
- LateParsedTemplateMap[FD] = LPT;
+ LateParsedTemplateMap.insert(std::make_pair(FD, LPT));
FD->setLateTemplateParsed(true);
}
}
return false;
}
+
+namespace {
+/// \brief Walk the path from which a declaration was instantiated, and check
+/// that every explicit specialization along that path is visible. This enforces
+/// C++ [temp.expl.spec]/6:
+///
+/// If a template, a member template or a member of a class template is
+/// explicitly specialized then that specialization shall be declared before
+/// the first use of that specialization that would cause an implicit
+/// instantiation to take place, in every translation unit in which such a
+/// use occurs; no diagnostic is required.
+///
+/// and also C++ [temp.class.spec]/1:
+///
+/// A partial specialization shall be declared before the first use of a
+/// class template specialization that would make use of the partial
+/// specialization as the result of an implicit or explicit instantiation
+/// in every translation unit in which such a use occurs; no diagnostic is
+/// required.
+class ExplicitSpecializationVisibilityChecker {
+ Sema &S;
+ SourceLocation Loc;
+ llvm::SmallVector<Module *, 8> Modules;
+
+public:
+ ExplicitSpecializationVisibilityChecker(Sema &S, SourceLocation Loc)
+ : S(S), Loc(Loc) {}
+
+ void check(NamedDecl *ND) {
+ if (auto *FD = dyn_cast<FunctionDecl>(ND))
+ return checkImpl(FD);
+ if (auto *RD = dyn_cast<CXXRecordDecl>(ND))
+ return checkImpl(RD);
+ if (auto *VD = dyn_cast<VarDecl>(ND))
+ return checkImpl(VD);
+ if (auto *ED = dyn_cast<EnumDecl>(ND))
+ return checkImpl(ED);
+ }
+
+private:
+ void diagnose(NamedDecl *D, bool IsPartialSpec) {
+ auto Kind = IsPartialSpec ? Sema::MissingImportKind::PartialSpecialization
+ : Sema::MissingImportKind::ExplicitSpecialization;
+ const bool Recover = true;
+
+ // If we got a custom set of modules (because only a subset of the
+ // declarations are interesting), use them, otherwise let
+ // diagnoseMissingImport intelligently pick some.
+ if (Modules.empty())
+ S.diagnoseMissingImport(Loc, D, Kind, Recover);
+ else
+ S.diagnoseMissingImport(Loc, D, D->getLocation(), Modules, Kind, Recover);
+ }
+
+ // Check a specific declaration. There are three problematic cases:
+ //
+ // 1) The declaration is an explicit specialization of a template
+ // specialization.
+ // 2) The declaration is an explicit specialization of a member of an
+ // templated class.
+ // 3) The declaration is an instantiation of a template, and that template
+ // is an explicit specialization of a member of a templated class.
+ //
+ // We don't need to go any deeper than that, as the instantiation of the
+ // surrounding class / etc is not triggered by whatever triggered this
+ // instantiation, and thus should be checked elsewhere.
+ template<typename SpecDecl>
+ void checkImpl(SpecDecl *Spec) {
+ bool IsHiddenExplicitSpecialization = false;
+ if (Spec->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) {
+ IsHiddenExplicitSpecialization =
+ Spec->getMemberSpecializationInfo()
+ ? !S.hasVisibleMemberSpecialization(Spec, &Modules)
+ : !S.hasVisibleDeclaration(Spec);
+ } else {
+ checkInstantiated(Spec);
+ }
+
+ if (IsHiddenExplicitSpecialization)
+ diagnose(Spec->getMostRecentDecl(), false);
+ }
+
+ void checkInstantiated(FunctionDecl *FD) {
+ if (auto *TD = FD->getPrimaryTemplate())
+ checkTemplate(TD);
+ }
+
+ void checkInstantiated(CXXRecordDecl *RD) {
+ auto *SD = dyn_cast<ClassTemplateSpecializationDecl>(RD);
+ if (!SD)
+ return;
+
+ auto From = SD->getSpecializedTemplateOrPartial();
+ if (auto *TD = From.dyn_cast<ClassTemplateDecl *>())
+ checkTemplate(TD);
+ else if (auto *TD =
+ From.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) {
+ if (!S.hasVisibleDeclaration(TD))
+ diagnose(TD, true);
+ checkTemplate(TD);
+ }
+ }
+
+ void checkInstantiated(VarDecl *RD) {
+ auto *SD = dyn_cast<VarTemplateSpecializationDecl>(RD);
+ if (!SD)
+ return;
+
+ auto From = SD->getSpecializedTemplateOrPartial();
+ if (auto *TD = From.dyn_cast<VarTemplateDecl *>())
+ checkTemplate(TD);
+ else if (auto *TD =
+ From.dyn_cast<VarTemplatePartialSpecializationDecl *>()) {
+ if (!S.hasVisibleDeclaration(TD))
+ diagnose(TD, true);
+ checkTemplate(TD);
+ }
+ }
+
+ void checkInstantiated(EnumDecl *FD) {}
+
+ template<typename TemplDecl>
+ void checkTemplate(TemplDecl *TD) {
+ if (TD->isMemberSpecialization()) {
+ if (!S.hasVisibleMemberSpecialization(TD, &Modules))
+ diagnose(TD->getMostRecentDecl(), false);
+ }
+ }
+};
+} // end anonymous namespace
+
+void Sema::checkSpecializationVisibility(SourceLocation Loc, NamedDecl *Spec) {
+ if (!getLangOpts().Modules)
+ return;
+
+ ExplicitSpecializationVisibilityChecker(*this, Loc).check(Spec);
+}
+
+/// \brief Check whether a template partial specialization that we've discovered
+/// is hidden, and produce suitable diagnostics if so.
+void Sema::checkPartialSpecializationVisibility(SourceLocation Loc,
+ NamedDecl *Spec) {
+ llvm::SmallVector<Module *, 8> Modules;
+ if (!hasVisibleDeclaration(Spec, &Modules))
+ diagnoseMissingImport(Loc, Spec, Spec->getLocation(), Modules,
+ MissingImportKind::PartialSpecialization,
+ /*Recover*/true);
+}