diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2016-07-23 20:44:14 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2016-07-23 20:44:14 +0000 |
commit | 2b6b257f4e5503a7a2675bdb8735693db769f75c (patch) | |
tree | e85e046ae7003fe3bcc8b5454cd0fa3f7407b470 /lib/Sema/SemaTemplate.cpp | |
parent | b4348ed0b7e90c0831b925fbee00b5f179a99796 (diff) | |
download | src-2b6b257f4e5503a7a2675bdb8735693db769f75c.tar.gz src-2b6b257f4e5503a7a2675bdb8735693db769f75c.zip |
Vendor import of clang release_39 branch r276489:vendor/clang/clang-release_39-r276489
Notes
Notes:
svn path=/vendor/clang/dist/; revision=303233
svn path=/vendor/clang/clang-release_39-r276489/; revision=303234; tag=vendor/clang/clang-release_39-r276489
Diffstat (limited to 'lib/Sema/SemaTemplate.cpp')
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 446 |
1 files changed, 365 insertions, 81 deletions
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 138cee0b9424..7fc5db82d32c 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -1,13 +1,13 @@ -//===------- 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" @@ -32,6 +32,8 @@ #include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" + +#include <iterator> using namespace clang; using namespace sema; @@ -413,9 +415,22 @@ Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS, 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 @@ -458,7 +473,6 @@ void Sema::DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl) { 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 @@ -555,7 +569,6 @@ Decl *Sema::ActOnTypeParameter(Scope *S, bool Typename, ParsedType DefaultArg) { assert(S->isTemplateParamScope() && "Template type parameter not in template parameter scope!"); - bool Invalid = false; SourceLocation Loc = ParamNameLoc; if (!ParamName) @@ -567,8 +580,6 @@ Decl *Sema::ActOnTypeParameter(Scope *S, bool Typename, KeyLoc, Loc, Depth, Position, ParamName, Typename, IsParameterPack); Param->setAccess(AS_public); - if (Invalid) - Param->setInvalidDecl(); if (ParamName) { maybeDiagnoseTemplateParameterShadow(*this, S, ParamNameLoc, ParamName); @@ -583,7 +594,7 @@ Decl *Sema::ActOnTypeParameter(Scope *S, bool Typename, // 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. @@ -790,7 +801,7 @@ Decl *Sema::ActOnTemplateTemplateParameter(Scope* S, // 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; } @@ -807,18 +818,21 @@ Decl *Sema::ActOnTemplateTemplateParameter(Scope* S, 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, ArrayRef<Decl *> Params, - SourceLocation RAngleLoc) { + SourceLocation RAngleLoc, + Expr *RequiresClause) { if (ExportLoc.isValid()) Diag(ExportLoc, diag::warn_template_export_unsupported); + // FIXME: store RequiresClause return TemplateParameterList::Create( Context, TemplateLoc, LAngleLoc, llvm::makeArrayRef((NamedDecl *const *)Params.data(), Params.size()), @@ -916,6 +930,13 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, 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 @@ -1041,12 +1062,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, // 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 @@ -1577,7 +1593,7 @@ struct DependencyChecker : RecursiveASTVisitor<DependencyChecker> { return TraverseType(T->getInjectedSpecializationType()); } }; -} +} // end anonymous namespace /// Determines whether a given type depends on the given parameter /// list. @@ -2027,7 +2043,7 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD, TemplateArgumentListInfo &TemplateArgs) { ASTContext &Context = SemaRef.getASTContext(); switch (BTD->getBuiltinTemplateKind()) { - case BTK__make_integer_seq: + case BTK__make_integer_seq: { // Specializations of __make_integer_seq<S, T, N> are treated like // S<T, 0, ..., N-1>. @@ -2069,6 +2085,29 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD, 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!"); } @@ -2119,7 +2158,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, return QualType(); TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, - Converted.data(), Converted.size()); + Converted); // Only substitute for the innermost template argument list. MultiLevelTemplateArgumentList TemplateArgLists; @@ -2150,8 +2189,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, // 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. @@ -2213,8 +2251,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, ClassTemplate->getTemplatedDecl()->getLocStart(), ClassTemplate->getLocation(), ClassTemplate, - Converted.data(), - Converted.size(), nullptr); + Converted, nullptr); ClassTemplate->AddSpecialization(Decl, InsertPos); if (ClassTemplate->isOutOfLine()) Decl->setLexicalDeclContext(ClassTemplate->getLexicalDeclContext()); @@ -2538,7 +2575,7 @@ DeclResult Sema::ActOnVarTemplateSpecialization( bool InstantiationDependent; if (!Name.isDependent() && !TemplateSpecializationType::anyDependentTemplateArguments( - TemplateArgs.getArgumentArray(), TemplateArgs.size(), + TemplateArgs.arguments(), InstantiationDependent)) { Diag(TemplateNameLoc, diag::err_partial_spec_fully_specialized) << VarTemplate->getDeclName(); @@ -2595,7 +2632,7 @@ DeclResult Sema::ActOnVarTemplateSpecialization( 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); @@ -2637,7 +2674,7 @@ DeclResult Sema::ActOnVarTemplateSpecialization( // 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) @@ -2713,7 +2750,7 @@ struct PartialSpecMatchResult { VarTemplatePartialSpecializationDecl *Partial; TemplateArgumentList *Args; }; -} +} // end anonymous namespace DeclResult Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc, @@ -2733,9 +2770,11 @@ 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 @@ -2743,7 +2782,7 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc, // 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; @@ -2776,8 +2815,9 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc, 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()); @@ -2834,8 +2874,8 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc, } // 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, @@ -2863,6 +2903,8 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc, dyn_cast<VarTemplatePartialSpecializationDecl>(InstantiationPattern)) Decl->setInstantiationOf(D, InstantiationArgs); + checkSpecializationVisibility(TemplateNameLoc, Decl); + assert(Decl && "No variable template specialization?"); return Decl; } @@ -3219,8 +3261,7 @@ SubstDefaultTemplateArgument(Sema &SemaRef, 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; @@ -3272,8 +3313,7 @@ SubstDefaultTemplateArgument(Sema &SemaRef, 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; @@ -3324,8 +3364,7 @@ SubstDefaultTemplateArgument(Sema &SemaRef, 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; @@ -3476,7 +3515,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, return true; TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, - Converted.data(), Converted.size()); + Converted); NTTPType = SubstType(NTTPType, MultiLevelTemplateArgumentList(TemplateArgs), NTTP->getLocation(), @@ -3616,8 +3655,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, 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))); @@ -3728,7 +3766,7 @@ static bool diagnoseMissingArgument(Sema &S, SourceLocation Loc, S.diagnoseMissingImport(Loc, cast<NamedDecl>(TD), D->getDefaultArgumentLoc(), Modules, Sema::MissingImportKind::DefaultArgument, - /*Recover*/ true); + /*Recover*/true); return true; } @@ -4014,7 +4052,7 @@ namespace { bool VisitTagDecl(const TagDecl *Tag); bool VisitNestedNameSpecifier(NestedNameSpecifier *NNS); }; -} +} // end anonymous namespace bool UnnamedLocalNoLinkageFinder::VisitBuiltinType(const BuiltinType*) { return false; @@ -4229,7 +4267,6 @@ bool UnnamedLocalNoLinkageFinder::VisitNestedNameSpecifier( llvm_unreachable("Invalid NestedNameSpecifier::Kind!"); } - /// \brief Check a template argument against its corresponding /// template type parameter. /// @@ -5340,10 +5377,11 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param, // 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; } @@ -6281,9 +6319,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, 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; @@ -6316,8 +6352,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, // 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())) { @@ -6348,8 +6383,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, KWLoc, TemplateNameLoc, TemplateParams, ClassTemplate, - Converted.data(), - Converted.size(), + Converted, TemplateArgs, CanonType, PrevPartial); @@ -6404,8 +6438,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, ClassTemplate->getDeclContext(), KWLoc, TemplateNameLoc, ClassTemplate, - Converted.data(), - Converted.size(), + Converted, PrevDecl); SetNestedNameSpecifier(Specialization, SS); if (TemplateParameterLists.size() > 0) { @@ -6423,7 +6456,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, "Only possible with -fms-extensions!"); TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name); CanonType = Context.getTemplateSpecializationType( - CanonTemplate, Converted.data(), Converted.size()); + CanonTemplate, Converted); } else { CanonType = Context.getTypeDeclType(Specialization); } @@ -6879,12 +6912,13 @@ bool Sema::CheckFunctionTemplateSpecialization( FunctionDecl *Specialization = nullptr; if (TemplateDeductionResult TDK = DeduceTemplateArguments( cast<FunctionTemplateDecl>(FunTmpl->getFirstDecl()), - ExplicitTemplateArgs ? &Args : nullptr, 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; } @@ -6911,6 +6945,15 @@ bool Sema::CheckFunctionTemplateSpecialization( // 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?"); @@ -6960,6 +7003,21 @@ bool Sema::CheckFunctionTemplateSpecialization( // 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); } @@ -7001,6 +7059,7 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { 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; @@ -7016,6 +7075,7 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { if (!hasExplicitCallingConv(Adjusted)) Adjusted = adjustCCAndNoReturn(Adjusted, Method->getType()); if (Context.hasSameType(Adjusted, Method->getType())) { + FoundInstantiation = *I; Instantiation = Method; InstantiatedFrom = Method->getInstantiatedFromMemberFunction(); MSInfo = Method->getMemberSpecializationInfo(); @@ -7028,6 +7088,7 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { if (Previous.isSingleResult() && (PrevVar = dyn_cast<VarDecl>(Previous.getFoundDecl()))) if (PrevVar->isStaticDataMember()) { + FoundInstantiation = Previous.getRepresentativeDecl(); Instantiation = PrevVar; InstantiatedFrom = PrevVar->getInstantiatedFromStaticDataMember(); MSInfo = PrevVar->getMemberSpecializationInfo(); @@ -7036,6 +7097,7 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { CXXRecordDecl *PrevRecord; if (Previous.isSingleResult() && (PrevRecord = dyn_cast<CXXRecordDecl>(Previous.getFoundDecl()))) { + FoundInstantiation = Previous.getRepresentativeDecl(); Instantiation = PrevRecord; InstantiatedFrom = PrevRecord->getInstantiatedFromMemberClass(); MSInfo = PrevRecord->getMemberSpecializationInfo(); @@ -7044,6 +7106,7 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { EnumDecl *PrevEnum; if (Previous.isSingleResult() && (PrevEnum = dyn_cast<EnumDecl>(Previous.getFoundDecl()))) { + FoundInstantiation = Previous.getRepresentativeDecl(); Instantiation = PrevEnum; InstantiatedFrom = PrevEnum->getInstantiatedFromMemberEnum(); MSInfo = PrevEnum->getMemberSpecializationInfo(); @@ -7072,7 +7135,7 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { } Previous.clear(); - Previous.addDecl(Instantiation); + Previous.addDecl(FoundInstantiation); return false; } @@ -7119,6 +7182,13 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { 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);
+ } } cast<FunctionDecl>(Member)->setInstantiationOfMemberFunction( @@ -7166,7 +7236,7 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { // 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; } @@ -7268,15 +7338,21 @@ Sema::ActOnExplicitInstantiation(Scope *S, 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())) { @@ -7315,6 +7391,29 @@ Sema::ActOnExplicitInstantiation(Scope *S, } } + // 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); @@ -7368,6 +7467,12 @@ Sema::ActOnExplicitInstantiation(Scope *S, Specialization->setLocation(TemplateNameLoc); PrevDecl = nullptr; } + + if (PrevDecl_TSK == TSK_ExplicitInstantiationDeclaration && + DLLImportExplicitInstantiationDef) { + // The new specialization might add a dllimport attribute. + HasNoEffect = false; + } } if (!Specialization) { @@ -7378,8 +7483,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, ClassTemplate->getDeclContext(), KWLoc, TemplateNameLoc, ClassTemplate, - Converted.data(), - Converted.size(), + Converted, PrevDecl); SetNestedNameSpecifier(Specialization, SS); @@ -7405,7 +7509,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, // Set source locations for keywords. Specialization->setExternLoc(ExternLoc); Specialization->setTemplateKeywordLoc(TemplateLoc); - Specialization->setRBraceLoc(SourceLocation()); + Specialization->setBraceRange(SourceRange()); if (Attr) ProcessDeclAttributeList(S, Specialization, Attr); @@ -7445,11 +7549,11 @@ Sema::ActOnExplicitInstantiation(Scope *S, 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); @@ -7462,7 +7566,13 @@ Sema::ActOnExplicitInstantiation(Scope *S, 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()) { @@ -7673,6 +7783,15 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, 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 @@ -7744,6 +7863,15 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, 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); @@ -7856,7 +7984,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, 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; @@ -7958,6 +8086,16 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, 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(), @@ -8294,7 +8432,7 @@ namespace { return E; } }; -} +} // end anonymous namespace /// \brief Rebuilds a type within the context of the current instantiation. /// @@ -8469,3 +8607,149 @@ bool Sema::IsInsideALocalClassWithinATemplateFunction() { } return false; } + +/// \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); + } + } +}; + +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); +} |