diff options
Diffstat (limited to 'lib/Sema/SemaTemplate.cpp')
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 609 |
1 files changed, 452 insertions, 157 deletions
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 3f9dc989103f..3212281cc34d 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -1,9 +1,8 @@ //===------- 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. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception //===----------------------------------------------------------------------===// // // This file implements semantic analysis for C++ templates. @@ -67,17 +66,20 @@ static Expr *clang::formAssociatedConstraints(TemplateParameterList *Params, /// Determine whether the declaration found is acceptable as the name /// of a template and, if so, return that template declaration. Otherwise, -/// returns NULL. -static NamedDecl *isAcceptableTemplateName(ASTContext &Context, - NamedDecl *Orig, - bool AllowFunctionTemplates) { - NamedDecl *D = Orig->getUnderlyingDecl(); +/// returns null. +/// +/// Note that this may return an UnresolvedUsingValueDecl if AllowDependent +/// is true. In all other cases it will return a TemplateDecl (or null). +NamedDecl *Sema::getAsTemplateNameDecl(NamedDecl *D, + bool AllowFunctionTemplates, + bool AllowDependent) { + D = D->getUnderlyingDecl(); if (isa<TemplateDecl>(D)) { if (!AllowFunctionTemplates && isa<FunctionTemplateDecl>(D)) return nullptr; - return Orig; + return D; } if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) { @@ -108,55 +110,35 @@ static NamedDecl *isAcceptableTemplateName(ASTContext &Context, // 'using Dependent::foo;' can resolve to a template name. // 'using typename Dependent::foo;' cannot (not even if 'foo' is an // injected-class-name). - if (isa<UnresolvedUsingValueDecl>(D)) + if (AllowDependent && isa<UnresolvedUsingValueDecl>(D)) return D; return nullptr; } void Sema::FilterAcceptableTemplateNames(LookupResult &R, - bool AllowFunctionTemplates) { - // The set of class templates we've already seen. - llvm::SmallPtrSet<ClassTemplateDecl *, 8> ClassTemplates; + bool AllowFunctionTemplates, + bool AllowDependent) { LookupResult::Filter filter = R.makeFilter(); while (filter.hasNext()) { NamedDecl *Orig = filter.next(); - NamedDecl *Repl = isAcceptableTemplateName(Context, Orig, - AllowFunctionTemplates); - if (!Repl) + if (!getAsTemplateNameDecl(Orig, AllowFunctionTemplates, AllowDependent)) filter.erase(); - else if (Repl != Orig) { - - // C++ [temp.local]p3: - // A lookup that finds an injected-class-name (10.2) can result in an - // ambiguity in certain cases (for example, if it is found in more than - // one base class). If all of the injected-class-names that are found - // refer to specializations of the same class template, and if the name - // is used as a template-name, the reference refers to the class - // template itself and not a specialization thereof, and is not - // ambiguous. - if (ClassTemplateDecl *ClassTmpl = dyn_cast<ClassTemplateDecl>(Repl)) - if (!ClassTemplates.insert(ClassTmpl).second) { - filter.erase(); - continue; - } - - // FIXME: we promote access to public here as a workaround to - // the fact that LookupResult doesn't let us remember that we - // found this template through a particular injected class name, - // which means we end up doing nasty things to the invariants. - // Pretending that access is public is *much* safer. - filter.replace(Repl, AS_public); - } } filter.done(); } bool Sema::hasAnyAcceptableTemplateNames(LookupResult &R, - bool AllowFunctionTemplates) { - for (LookupResult::iterator I = R.begin(), IEnd = R.end(); I != IEnd; ++I) - if (isAcceptableTemplateName(Context, *I, AllowFunctionTemplates)) + bool AllowFunctionTemplates, + bool AllowDependent, + bool AllowNonTemplateFunctions) { + for (LookupResult::iterator I = R.begin(), IEnd = R.end(); I != IEnd; ++I) { + if (getAsTemplateNameDecl(*I, AllowFunctionTemplates, AllowDependent)) + return true; + if (AllowNonTemplateFunctions && + isa<FunctionDecl>((*I)->getUnderlyingDecl())) return true; + } return false; } @@ -194,25 +176,64 @@ TemplateNameKind Sema::isTemplateName(Scope *S, QualType ObjectType = ObjectTypePtr.get(); + AssumedTemplateKind AssumedTemplate; LookupResult R(*this, TName, Name.getBeginLoc(), LookupOrdinaryName); if (LookupTemplateName(R, S, SS, ObjectType, EnteringContext, - MemberOfUnknownSpecialization)) + MemberOfUnknownSpecialization, SourceLocation(), + &AssumedTemplate)) return TNK_Non_template; - if (R.empty()) return TNK_Non_template; - if (R.isAmbiguous()) { - // Suppress diagnostics; we'll redo this lookup later. - R.suppressDiagnostics(); - // FIXME: we might have ambiguous templates, in which case we - // should at least parse them properly! + if (AssumedTemplate != AssumedTemplateKind::None) { + TemplateResult = TemplateTy::make(Context.getAssumedTemplateName(TName)); + // Let the parser know whether we found nothing or found functions; if we + // found nothing, we want to more carefully check whether this is actually + // a function template name versus some other kind of undeclared identifier. + return AssumedTemplate == AssumedTemplateKind::FoundNothing + ? TNK_Undeclared_template + : TNK_Function_template; + } + + if (R.empty()) return TNK_Non_template; + + NamedDecl *D = nullptr; + if (R.isAmbiguous()) { + // If we got an ambiguity involving a non-function template, treat this + // as a template name, and pick an arbitrary template for error recovery. + bool AnyFunctionTemplates = false; + for (NamedDecl *FoundD : R) { + if (NamedDecl *FoundTemplate = getAsTemplateNameDecl(FoundD)) { + if (isa<FunctionTemplateDecl>(FoundTemplate)) + AnyFunctionTemplates = true; + else { + D = FoundTemplate; + break; + } + } + } + + // If we didn't find any templates at all, this isn't a template name. + // Leave the ambiguity for a later lookup to diagnose. + if (!D && !AnyFunctionTemplates) { + R.suppressDiagnostics(); + return TNK_Non_template; + } + + // If the only templates were function templates, filter out the rest. + // We'll diagnose the ambiguity later. + if (!D) + FilterAcceptableTemplateNames(R); } + // At this point, we have either picked a single template name declaration D + // or we have a non-empty set of results R containing either one template name + // declaration or a set of function templates. + TemplateName Template; TemplateNameKind TemplateKind; unsigned ResultCount = R.end() - R.begin(); - if (ResultCount > 1) { + if (!D && ResultCount > 1) { // We assume that we'll preserve the qualifier from a function // template name in other ways. Template = Context.getOverloadedTemplateName(R.begin(), R.end()); @@ -220,12 +241,19 @@ TemplateNameKind Sema::isTemplateName(Scope *S, // We'll do this lookup again later. R.suppressDiagnostics(); - } else if (isa<UnresolvedUsingValueDecl>((*R.begin())->getUnderlyingDecl())) { - // We don't yet know whether this is a template-name or not. - MemberOfUnknownSpecialization = true; - return TNK_Non_template; } else { - TemplateDecl *TD = cast<TemplateDecl>((*R.begin())->getUnderlyingDecl()); + if (!D) { + D = getAsTemplateNameDecl(*R.begin()); + assert(D && "unambiguous result is not a template name"); + } + + if (isa<UnresolvedUsingValueDecl>(D)) { + // We don't yet know whether this is a template-name or not. + MemberOfUnknownSpecialization = true; + return TNK_Non_template; + } + + TemplateDecl *TD = cast<TemplateDecl>(D); if (SS.isSet() && !SS.isInvalid()) { NestedNameSpecifier *Qualifier = SS.getScopeRep(); @@ -243,9 +271,11 @@ TemplateNameKind Sema::isTemplateName(Scope *S, } else { assert(isa<ClassTemplateDecl>(TD) || isa<TemplateTemplateParmDecl>(TD) || isa<TypeAliasTemplateDecl>(TD) || isa<VarTemplateDecl>(TD) || - isa<BuiltinTemplateDecl>(TD)); + isa<BuiltinTemplateDecl>(TD) || isa<ConceptDecl>(TD)); TemplateKind = - isa<VarTemplateDecl>(TD) ? TNK_Var_template : TNK_Type_template; + isa<VarTemplateDecl>(TD) ? TNK_Var_template : + isa<ConceptDecl>(TD) ? TNK_Concept_template : + TNK_Type_template; } } @@ -316,7 +346,13 @@ bool Sema::LookupTemplateName(LookupResult &Found, QualType ObjectType, bool EnteringContext, bool &MemberOfUnknownSpecialization, - SourceLocation TemplateKWLoc) { + SourceLocation TemplateKWLoc, + AssumedTemplateKind *ATK) { + if (ATK) + *ATK = AssumedTemplateKind::None; + + Found.setTemplateNameLookup(true); + // Determine where to perform name lookup MemberOfUnknownSpecialization = false; DeclContext *LookupCtx = nullptr; @@ -391,24 +427,55 @@ bool Sema::LookupTemplateName(LookupResult &Found, IsDependent |= Found.wasNotFoundInCurrentInstantiation(); } + if (Found.isAmbiguous()) + return false; + + if (ATK && !SS.isSet() && ObjectType.isNull() && TemplateKWLoc.isInvalid()) { + // C++2a [temp.names]p2: + // A name is also considered to refer to a template if it is an + // unqualified-id followed by a < and name lookup finds either one or more + // functions or finds nothing. + // + // To keep our behavior consistent, we apply the "finds nothing" part in + // all language modes, and diagnose the empty lookup in ActOnCallExpr if we + // successfully form a call to an undeclared template-id. + bool AllFunctions = + getLangOpts().CPlusPlus2a && + std::all_of(Found.begin(), Found.end(), [](NamedDecl *ND) { + return isa<FunctionDecl>(ND->getUnderlyingDecl()); + }); + if (AllFunctions || (Found.empty() && !IsDependent)) { + // If lookup found any functions, or if this is a name that can only be + // used for a function, then strongly assume this is a function + // template-id. + *ATK = (Found.empty() && Found.getLookupName().isIdentifier()) + ? AssumedTemplateKind::FoundNothing + : AssumedTemplateKind::FoundFunctions; + Found.clear(); + return false; + } + } + if (Found.empty() && !IsDependent) { // If we did not find any names, attempt to correct any typos. DeclarationName Name = Found.getLookupName(); Found.clear(); // Simple filter callback that, for keywords, only accepts the C++ *_cast - auto FilterCCC = llvm::make_unique<CorrectionCandidateCallback>(); - FilterCCC->WantTypeSpecifiers = false; - FilterCCC->WantExpressionKeywords = false; - FilterCCC->WantRemainingKeywords = false; - FilterCCC->WantCXXNamedCasts = true; - if (TypoCorrection Corrected = CorrectTypo( - Found.getLookupNameInfo(), Found.getLookupKind(), S, &SS, - std::move(FilterCCC), CTK_ErrorRecovery, LookupCtx)) { - Found.setLookupName(Corrected.getCorrection()); + DefaultFilterCCC FilterCCC{}; + FilterCCC.WantTypeSpecifiers = false; + FilterCCC.WantExpressionKeywords = false; + FilterCCC.WantRemainingKeywords = false; + FilterCCC.WantCXXNamedCasts = true; + if (TypoCorrection Corrected = + CorrectTypo(Found.getLookupNameInfo(), Found.getLookupKind(), S, + &SS, FilterCCC, CTK_ErrorRecovery, LookupCtx)) { if (auto *ND = Corrected.getFoundDecl()) Found.addDecl(ND); FilterAcceptableTemplateNames(Found); - if (!Found.empty()) { + if (Found.isAmbiguous()) { + Found.clear(); + } else if (!Found.empty()) { + Found.setLookupName(Corrected.getCorrection()); if (LookupCtx) { std::string CorrectedStr(Corrected.getAsString(getLangOpts())); bool DroppedSpecifier = Corrected.WillReplaceSpecifier() && @@ -420,8 +487,6 @@ bool Sema::LookupTemplateName(LookupResult &Found, diagnoseTypo(Corrected, PDiag(diag::err_no_template_suggest) << Name); } } - } else { - Found.setLookupName(Name); } } @@ -458,14 +523,19 @@ bool Sema::LookupTemplateName(LookupResult &Found, // Note: C++11 does not perform this second lookup. LookupResult FoundOuter(*this, Found.getLookupName(), Found.getNameLoc(), LookupOrdinaryName); + FoundOuter.setTemplateNameLookup(true); LookupName(FoundOuter, S); + // FIXME: We silently accept an ambiguous lookup here, in violation of + // [basic.lookup]/1. FilterAcceptableTemplateNames(FoundOuter, /*AllowFunctionTemplates=*/false); + NamedDecl *OuterTemplate; if (FoundOuter.empty()) { // - if the name is not found, the name found in the class of the // object expression is used, otherwise - } else if (!FoundOuter.getAsSingle<ClassTemplateDecl>() || - FoundOuter.isAmbiguous()) { + } else if (FoundOuter.isAmbiguous() || !FoundOuter.isSingleResult() || + !(OuterTemplate = + getAsTemplateNameDecl(FoundOuter.getFoundDecl()))) { // - if the name is found in the context of the entire // postfix-expression and does not name a class template, the name // found in the class of the object expression is used, otherwise @@ -475,8 +545,8 @@ bool Sema::LookupTemplateName(LookupResult &Found, // entity as the one found in the class of the object expression, // otherwise the program is ill-formed. if (!Found.isSingleResult() || - Found.getFoundDecl()->getCanonicalDecl() - != FoundOuter.getFoundDecl()->getCanonicalDecl()) { + getAsTemplateNameDecl(Found.getFoundDecl())->getCanonicalDecl() != + OuterTemplate->getCanonicalDecl()) { Diag(Found.getNameLoc(), diag::ext_nested_name_member_ref_lookup_ambiguous) << Found.getLookupName() @@ -546,7 +616,8 @@ void Sema::diagnoseExprIntendedAsTemplateName(Scope *S, ExprResult TemplateName, // Try to correct the name by looking for templates and C++ named casts. struct TemplateCandidateFilter : CorrectionCandidateCallback { - TemplateCandidateFilter() { + Sema &S; + TemplateCandidateFilter(Sema &S) : S(S) { WantTypeSpecifiers = false; WantExpressionKeywords = false; WantRemainingKeywords = false; @@ -554,20 +625,22 @@ void Sema::diagnoseExprIntendedAsTemplateName(Scope *S, ExprResult TemplateName, }; bool ValidateCandidate(const TypoCorrection &Candidate) override { if (auto *ND = Candidate.getCorrectionDecl()) - return isAcceptableTemplateName(ND->getASTContext(), ND, true); + return S.getAsTemplateNameDecl(ND); return Candidate.isKeyword(); } + + std::unique_ptr<CorrectionCandidateCallback> clone() override { + return llvm::make_unique<TemplateCandidateFilter>(*this); + } }; DeclarationName Name = NameInfo.getName(); - if (TypoCorrection Corrected = - CorrectTypo(NameInfo, LookupKind, S, &SS, - llvm::make_unique<TemplateCandidateFilter>(), - CTK_ErrorRecovery, LookupCtx)) { + TemplateCandidateFilter CCC(*this); + if (TypoCorrection Corrected = CorrectTypo(NameInfo, LookupKind, S, &SS, CCC, + CTK_ErrorRecovery, LookupCtx)) { auto *ND = Corrected.getFoundDecl(); if (ND) - ND = isAcceptableTemplateName(Context, ND, - /*AllowFunctionTemplates*/ true); + ND = getAsTemplateNameDecl(ND); if (ND || Corrected.isKeyword()) { if (LookupCtx) { std::string CorrectedStr(Corrected.getAsString(getLangOpts())); @@ -1076,7 +1149,7 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, // variable or variable template or the declaration of a function or // function template. - if (DS.isConstexprSpecified()) + if (DS.hasConstexprSpecifier()) EmitDiag(DS.getConstexprSpecLoc()); // [dcl.fct.spec]p1: @@ -1085,7 +1158,7 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, if (DS.isVirtualSpecified()) EmitDiag(DS.getVirtualSpecLoc()); - if (DS.isExplicitSpecified()) + if (DS.hasExplicitSpecifier()) EmitDiag(DS.getExplicitSpecLoc()); if (DS.isNoreturnSpecified()) @@ -1110,6 +1183,8 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, Invalid = true; } + CheckFunctionOrTemplateParamDeclarator(S, D); + IdentifierInfo *ParamName = D.getIdentifier(); bool IsParameterPack = D.hasEllipsis(); NonTypeTemplateParmDecl *Param = NonTypeTemplateParmDecl::Create( @@ -1765,8 +1840,8 @@ struct ConvertConstructorToDeductionGuideTransform { return nullptr; TypeSourceInfo *NewTInfo = TLB.getTypeSourceInfo(SemaRef.Context, NewType); - return buildDeductionGuide(TemplateParams, CD->isExplicit(), NewTInfo, - CD->getBeginLoc(), CD->getLocation(), + return buildDeductionGuide(TemplateParams, CD->getExplicitSpecifier(), + NewTInfo, CD->getBeginLoc(), CD->getLocation(), CD->getEndLoc()); } @@ -1795,8 +1870,8 @@ struct ConvertConstructorToDeductionGuideTransform { Params.push_back(NewParam); } - return buildDeductionGuide(Template->getTemplateParameters(), false, TSI, - Loc, Loc, Loc); + return buildDeductionGuide(Template->getTemplateParameters(), + ExplicitSpecifier(), TSI, Loc, Loc, Loc); } private: @@ -1946,7 +2021,7 @@ private: } NamedDecl *buildDeductionGuide(TemplateParameterList *TemplateParams, - bool Explicit, TypeSourceInfo *TInfo, + ExplicitSpecifier ES, TypeSourceInfo *TInfo, SourceLocation LocStart, SourceLocation Loc, SourceLocation LocEnd) { DeclarationNameInfo Name(DeductionGuideName, Loc); @@ -1955,8 +2030,8 @@ private: // Build the implicit deduction guide template. auto *Guide = - CXXDeductionGuideDecl::Create(SemaRef.Context, DC, LocStart, Explicit, - Name, TInfo->getType(), TInfo, LocEnd); + CXXDeductionGuideDecl::Create(SemaRef.Context, DC, LocStart, ES, Name, + TInfo->getType(), TInfo, LocEnd); Guide->setImplicit(); Guide->setParams(Params); @@ -1981,6 +2056,12 @@ private: void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template, SourceLocation Loc) { + if (CXXRecordDecl *DefRecord = + cast<CXXRecordDecl>(Template->getTemplatedDecl())->getDefinition()) { + TemplateDecl *DescribedTemplate = DefRecord->getDescribedClassTemplate(); + Template = DescribedTemplate ? DescribedTemplate : Template; + } + DeclContext *DC = Template->getDeclContext(); if (DC->isDependentContext()) return; @@ -3148,7 +3229,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, TemplateDecl *Template = Name.getAsTemplateDecl(); if (!Template || isa<FunctionTemplateDecl>(Template) || - isa<VarTemplateDecl>(Template)) { + isa<VarTemplateDecl>(Template) || + isa<ConceptDecl>(Template)) { // We might have a substituted template template parameter pack. If so, // build a template specialization type for it. if (Name.getAsSubstTemplateTemplateParmPack()) @@ -3324,14 +3406,65 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, return Context.getTemplateSpecializationType(Name, TemplateArgs, CanonType); } -TypeResult -Sema::ActOnTemplateIdType(CXXScopeSpec &SS, SourceLocation TemplateKWLoc, - TemplateTy TemplateD, IdentifierInfo *TemplateII, - SourceLocation TemplateIILoc, - SourceLocation LAngleLoc, - ASTTemplateArgsPtr TemplateArgsIn, - SourceLocation RAngleLoc, - bool IsCtorOrDtorName, bool IsClassName) { +void Sema::ActOnUndeclaredTypeTemplateName(Scope *S, TemplateTy &ParsedName, + TemplateNameKind &TNK, + SourceLocation NameLoc, + IdentifierInfo *&II) { + assert(TNK == TNK_Undeclared_template && "not an undeclared template name"); + + TemplateName Name = ParsedName.get(); + auto *ATN = Name.getAsAssumedTemplateName(); + assert(ATN && "not an assumed template name"); + II = ATN->getDeclName().getAsIdentifierInfo(); + + if (!resolveAssumedTemplateNameAsType(S, Name, NameLoc, /*Diagnose*/false)) { + // Resolved to a type template name. + ParsedName = TemplateTy::make(Name); + TNK = TNK_Type_template; + } +} + +bool Sema::resolveAssumedTemplateNameAsType(Scope *S, TemplateName &Name, + SourceLocation NameLoc, + bool Diagnose) { + // We assumed this undeclared identifier to be an (ADL-only) function + // template name, but it was used in a context where a type was required. + // Try to typo-correct it now. + AssumedTemplateStorage *ATN = Name.getAsAssumedTemplateName(); + assert(ATN && "not an assumed template name"); + + LookupResult R(*this, ATN->getDeclName(), NameLoc, LookupOrdinaryName); + struct CandidateCallback : CorrectionCandidateCallback { + bool ValidateCandidate(const TypoCorrection &TC) override { + return TC.getCorrectionDecl() && + getAsTypeTemplateDecl(TC.getCorrectionDecl()); + } + std::unique_ptr<CorrectionCandidateCallback> clone() override { + return llvm::make_unique<CandidateCallback>(*this); + } + } FilterCCC; + + TypoCorrection Corrected = + CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), S, nullptr, + FilterCCC, CTK_ErrorRecovery); + if (Corrected && Corrected.getFoundDecl()) { + diagnoseTypo(Corrected, PDiag(diag::err_no_template_suggest) + << ATN->getDeclName()); + Name = TemplateName(Corrected.getCorrectionDeclAs<TemplateDecl>()); + return false; + } + + if (Diagnose) + Diag(R.getNameLoc(), diag::err_no_template) << R.getLookupName(); + return true; +} + +TypeResult Sema::ActOnTemplateIdType( + Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, + TemplateTy TemplateD, IdentifierInfo *TemplateII, + SourceLocation TemplateIILoc, SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgsIn, SourceLocation RAngleLoc, + bool IsCtorOrDtorName, bool IsClassName) { if (SS.isInvalid()) return true; @@ -3372,6 +3505,9 @@ Sema::ActOnTemplateIdType(CXXScopeSpec &SS, SourceLocation TemplateKWLoc, } TemplateName Template = TemplateD.get(); + if (Template.getAsAssumedTemplateName() && + resolveAssumedTemplateNameAsType(S, Template, TemplateIILoc)) + return true; // Translate the parser's template argument list in our AST format. TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc); @@ -3903,13 +4039,6 @@ DeclResult Sema::ActOnVarTemplateSpecialization( Specialization->setAccess(VarTemplate->getAccess()); } - // Link instantiations of static data members back to the template from - // which they were instantiated. - if (Specialization->isStaticDataMember()) - Specialization->setInstantiationOfStaticDataMember( - VarTemplate->getTemplatedDecl(), - Specialization->getSpecializationKind()); - return Specialization; } @@ -4108,6 +4237,18 @@ void Sema::diagnoseMissingTemplateArguments(TemplateName Name, } } +ExprResult +Sema::CheckConceptTemplateId(const CXXScopeSpec &SS, + const DeclarationNameInfo &NameInfo, + ConceptDecl *Template, + SourceLocation TemplateLoc, + const TemplateArgumentListInfo *TemplateArgs) { + // TODO: Do concept specialization here. + Diag(NameInfo.getBeginLoc(), diag::err_concept_not_implemented) << + "concept specialization"; + return ExprError(); +} + ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R, @@ -4124,7 +4265,6 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS, // vs template<class T, class U> void f(U); // These should be filtered out by our callers. - assert(!R.empty() && "empty lookup results when building templateid"); assert(!R.isAmbiguous() && "ambiguous lookup when building templateid"); // Non-function templates require a template argument list. @@ -4149,6 +4289,12 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS, TemplateKWLoc, TemplateArgs); } + if (R.getAsSingle<ConceptDecl>() && !AnyDependentArguments()) { + return CheckConceptTemplateId(SS, R.getLookupNameInfo(), + R.getAsSingle<ConceptDecl>(), + TemplateKWLoc, TemplateArgs); + } + // We don't want lookup warnings at this point. R.suppressDiagnostics(); @@ -4263,7 +4409,7 @@ TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S, LookupOrdinaryName); bool MOUS; if (!LookupTemplateName(R, S, SS, ObjectType.get(), EnteringContext, - MOUS, TemplateKWLoc)) + MOUS, TemplateKWLoc) && !R.isAmbiguous()) Diag(Name.getBeginLoc(), diag::err_no_member) << DNI.getName() << LookupCtx << SS.getRange(); return TNK_Non_template; @@ -4763,10 +4909,22 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted); - NTTPType = SubstType(NTTPType, - MultiLevelTemplateArgumentList(TemplateArgs), - NTTP->getLocation(), - NTTP->getDeclName()); + + // If the parameter is a pack expansion, expand this slice of the pack. + if (auto *PET = NTTPType->getAs<PackExpansionType>()) { + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(*this, + ArgumentPackIndex); + NTTPType = SubstType(PET->getPattern(), + MultiLevelTemplateArgumentList(TemplateArgs), + NTTP->getLocation(), + NTTP->getDeclName()); + } else { + NTTPType = SubstType(NTTPType, + MultiLevelTemplateArgumentList(TemplateArgs), + NTTP->getLocation(), + NTTP->getDeclName()); + } + // If that worked, check the non-type template parameter type // for validity. if (!NTTPType.isNull()) @@ -6185,12 +6343,13 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // When checking a deduced template argument, deduce from its type even if // the type is dependent, in order to check the types of non-type template // arguments line up properly in partial ordering. - Optional<unsigned> Depth; - if (CTAK != CTAK_Specified) - Depth = Param->getDepth() + 1; + Optional<unsigned> Depth = Param->getDepth() + 1; + Expr *DeductionArg = Arg; + if (auto *PE = dyn_cast<PackExpansionExpr>(DeductionArg)) + DeductionArg = PE->getPattern(); if (DeduceAutoType( Context.getTrivialTypeSourceInfo(ParamType, Param->getLocation()), - Arg, ParamType, Depth) == DAR_Failed) { + DeductionArg, ParamType, Depth) == DAR_Failed) { Diag(Arg->getExprLoc(), diag::err_non_type_template_parm_type_deduction_failure) << Param->getDeclName() << Param->getType() << Arg->getType() @@ -6242,9 +6401,24 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // If either the parameter has a dependent type or the argument is // type-dependent, there's nothing we can check now. if (ParamType->isDependentType() || Arg->isTypeDependent()) { - // FIXME: Produce a cloned, canonical expression? - Converted = TemplateArgument(Arg); - return Arg; + // Force the argument to the type of the parameter to maintain invariants. + auto *PE = dyn_cast<PackExpansionExpr>(Arg); + if (PE) + Arg = PE->getPattern(); + ExprResult E = ImpCastExprToType( + Arg, ParamType.getNonLValueExprType(Context), CK_Dependent, + ParamType->isLValueReferenceType() ? VK_LValue : + ParamType->isRValueReferenceType() ? VK_XValue : VK_RValue); + if (E.isInvalid()) + return ExprError(); + if (PE) { + // Recreate a pack expansion if we unwrapped one. + E = new (Context) + PackExpansionExpr(E.get()->getType(), E.get(), PE->getEllipsisLoc(), + PE->getNumExpansions()); + } + Converted = TemplateArgument(E.get()); + return E; } // The initialization of the parameter from the argument is @@ -6273,10 +6447,13 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // Convert the APValue to a TemplateArgument. switch (Value.getKind()) { - case APValue::Uninitialized: + case APValue::None: assert(ParamType->isNullPtrType()); Converted = TemplateArgument(CanonParamType, /*isNullPtr*/true); break; + case APValue::Indeterminate: + llvm_unreachable("result of constant evaluation should be initialized"); + break; case APValue::Int: assert(ParamType->isIntegralOrEnumerationType()); Converted = TemplateArgument(Context, Value.getInt(), CanonParamType); @@ -6307,21 +6484,22 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // -- a string literal // -- the result of a typeid expression, or // -- a predefined __func__ variable - if (auto *E = Value.getLValueBase().dyn_cast<const Expr*>()) { - if (isa<CXXUuidofExpr>(E)) { - Converted = TemplateArgument(ArgResult.get()); + APValue::LValueBase Base = Value.getLValueBase(); + auto *VD = const_cast<ValueDecl *>(Base.dyn_cast<const ValueDecl *>()); + if (Base && !VD) { + auto *E = Base.dyn_cast<const Expr *>(); + if (E && isa<CXXUuidofExpr>(E)) { + Converted = TemplateArgument(ArgResult.get()->IgnoreImpCasts()); break; } Diag(Arg->getBeginLoc(), diag::err_template_arg_not_decl_ref) << Arg->getSourceRange(); return ExprError(); } - auto *VD = const_cast<ValueDecl *>( - Value.getLValueBase().dyn_cast<const ValueDecl *>()); // -- a subobject if (Value.hasLValuePath() && Value.getLValuePath().size() == 1 && VD && VD->getType()->isArrayType() && - Value.getLValuePath()[0].ArrayIndex == 0 && + Value.getLValuePath()[0].getAsArrayIndex() == 0 && !Value.isLValueOnePastTheEnd() && ParamType->isPointerType()) { // Per defect report (no number yet): // ... other than a pointer to the first element of a complete array @@ -6342,6 +6520,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, } case APValue::AddrLabelDiff: return Diag(StartLoc, diag::err_non_type_template_arg_addr_label_diff); + case APValue::FixedPoint: case APValue::Float: case APValue::ComplexInt: case APValue::ComplexFloat: @@ -7816,7 +7995,74 @@ Decl *Sema::ActOnTemplateDeclarator(Scope *S, return NewDecl; } -/// Strips various properties off an implicit instantiation +Decl *Sema::ActOnConceptDefinition(Scope *S, + MultiTemplateParamsArg TemplateParameterLists, + IdentifierInfo *Name, SourceLocation NameLoc, + Expr *ConstraintExpr) { + DeclContext *DC = CurContext; + + if (!DC->getRedeclContext()->isFileContext()) { + Diag(NameLoc, + diag::err_concept_decls_may_only_appear_in_global_namespace_scope); + return nullptr; + } + + if (TemplateParameterLists.size() > 1) { + Diag(NameLoc, diag::err_concept_extra_headers); + return nullptr; + } + + if (TemplateParameterLists.front()->size() == 0) { + Diag(NameLoc, diag::err_concept_no_parameters); + return nullptr; + } + + ConceptDecl *NewDecl = ConceptDecl::Create(Context, DC, NameLoc, Name, + TemplateParameterLists.front(), + ConstraintExpr); + + if (!ConstraintExpr->isTypeDependent() && + ConstraintExpr->getType() != Context.BoolTy) { + // C++2a [temp.constr.atomic]p3: + // E shall be a constant expression of type bool. + // TODO: Do this check for individual atomic constraints + // and not the constraint expression. Probably should do it in + // ParseConstraintExpression. + Diag(ConstraintExpr->getSourceRange().getBegin(), + diag::err_concept_initialized_with_non_bool_type) + << ConstraintExpr->getType(); + NewDecl->setInvalidDecl(); + } + + if (NewDecl->getAssociatedConstraints()) { + // C++2a [temp.concept]p4: + // A concept shall not have associated constraints. + // TODO: Make a test once we have actual associated constraints. + Diag(NameLoc, diag::err_concept_no_associated_constraints); + NewDecl->setInvalidDecl(); + } + + // Check for conflicting previous declaration. + DeclarationNameInfo NameInfo(NewDecl->getDeclName(), NameLoc); + LookupResult Previous(*this, NameInfo, LookupOrdinaryName, + ForVisibleRedeclaration); + LookupName(Previous, S); + + FilterLookupForScope(Previous, DC, S, /*ConsiderLinkage=*/false, + /*AllowInlineNamespace*/false); + if (!Previous.empty()) { + auto *Old = Previous.getRepresentativeDecl(); + Diag(NameLoc, isa<ConceptDecl>(Old) ? diag::err_redefinition : + diag::err_redefinition_different_kind) << NewDecl->getDeclName(); + Diag(Old->getLocation(), diag::note_previous_definition); + } + + ActOnDocumentableDecl(NewDecl); + PushOnScopeChains(NewDecl, S); + return NewDecl; +} + +/// \brief Strips various properties off an implicit instantiation /// that has just been explicitly specialized. static void StripImplicitInstantiation(NamedDecl *D) { D->dropAttr<DLLImportAttr>(); @@ -8182,8 +8428,8 @@ bool Sema::CheckFunctionTemplateSpecialization( // here that have a different target. if (LangOpts.CUDA && IdentifyCUDATarget(Specialization, - /* IgnoreImplicitHDAttributes = */ true) != - IdentifyCUDATarget(FD, /* IgnoreImplicitHDAttributes = */ true)) { + /* IgnoreImplicitHDAttr = */ true) != + IdentifyCUDATarget(FD, /* IgnoreImplicitHDAttr = */ true)) { FailedCandidates.addCandidate().set( I.getPair(), FunTmpl->getTemplatedDecl(), MakeDeductionFailureInfo(Context, TDK_CUDATargetMismatch, Info)); @@ -8243,7 +8489,7 @@ bool Sema::CheckFunctionTemplateSpecialization( // FIXME: We need an update record for this AST mutation. // FIXME: What if there are multiple such prior declarations (for instance, // from different modules)? - Specialization->setConstexpr(FD->isConstexpr()); + Specialization->setConstexprKind(FD->getConstexprKind()); } // FIXME: Check if the prior specialization has a point of instantiation. @@ -8594,6 +8840,29 @@ static bool CheckExplicitInstantiationScope(Sema &S, NamedDecl *D, return false; } +/// Common checks for whether an explicit instantiation of \p D is valid. +static bool CheckExplicitInstantiation(Sema &S, NamedDecl *D, + SourceLocation InstLoc, + bool WasQualifiedName, + TemplateSpecializationKind TSK) { + // C++ [temp.explicit]p13: + // An explicit instantiation declaration shall not name a specialization of + // a template with internal linkage. + if (TSK == TSK_ExplicitInstantiationDeclaration && + D->getFormalLinkage() == InternalLinkage) { + S.Diag(InstLoc, diag::err_explicit_instantiation_internal_linkage) << D; + return true; + } + + // C++11 [temp.explicit]p3: [DR 275] + // An explicit instantiation shall appear in an enclosing namespace of its + // template. + if (CheckExplicitInstantiationScope(S, D, InstLoc, WasQualifiedName)) + return true; + + return false; +} + /// Determine whether the given scope specifier has a template-id in it. static bool ScopeSpecifierHasTemplateId(const CXXScopeSpec &SS) { if (!SS.isSet()) @@ -8684,8 +8953,10 @@ DeclResult Sema::ActOnExplicitInstantiation( ? TSK_ExplicitInstantiationDefinition : TSK_ExplicitInstantiationDeclaration; - if (TSK == TSK_ExplicitInstantiationDeclaration) { - // Check for dllexport class template instantiation declarations. + if (TSK == TSK_ExplicitInstantiationDeclaration && + !Context.getTargetInfo().getTriple().isWindowsGNUEnvironment()) { + // Check for dllexport class template instantiation declarations, + // except for MinGW mode. for (const ParsedAttr &AL : Attr) { if (AL.getKind() == ParsedAttr::AT_DLLExport) { Diag(ExternLoc, @@ -8745,13 +9016,21 @@ DeclResult Sema::ActOnExplicitInstantiation( TemplateSpecializationKind PrevDecl_TSK = PrevDecl ? PrevDecl->getTemplateSpecializationKind() : TSK_Undeclared; - // C++0x [temp.explicit]p2: - // [...] An explicit instantiation shall appear in an enclosing - // namespace of its template. [...] - // - // This is C++ DR 275. - if (CheckExplicitInstantiationScope(*this, ClassTemplate, TemplateNameLoc, - SS.isSet())) + if (TSK == TSK_ExplicitInstantiationDefinition && PrevDecl != nullptr && + Context.getTargetInfo().getTriple().isWindowsGNUEnvironment()) { + // Check for dllexport class template instantiation definitions in MinGW + // mode, if a previous declaration of the instantiation was seen. + for (const ParsedAttr &AL : Attr) { + if (AL.getKind() == ParsedAttr::AT_DLLExport) { + Diag(AL.getLoc(), + diag::warn_attribute_dllexport_explicit_instantiation_def); + break; + } + } + } + + if (CheckExplicitInstantiation(*this, ClassTemplate, TemplateNameLoc, + SS.isSet(), TSK)) return true; ClassTemplateSpecializationDecl *Specialization = nullptr; @@ -8906,6 +9185,14 @@ DeclResult Sema::ActOnExplicitInstantiation( dllExportImportClassTemplateSpecialization(*this, Def); } + // In MinGW mode, export the template instantiation if the declaration + // was marked dllexport. + if (PrevDecl_TSK == TSK_ExplicitInstantiationDeclaration && + Context.getTargetInfo().getTriple().isWindowsGNUEnvironment() && + PrevDecl->hasAttr<DLLExportAttr>()) { + dllExportImportClassTemplateSpecialization(*this, Def); + } + // Set the template specialization kind. Make sure it is set before // instantiating the members which will trigger ASTConsumer callbacks. Specialization->setTemplateSpecializationKind(TSK); @@ -8974,12 +9261,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation ExternLoc, = ExternLoc.isInvalid()? TSK_ExplicitInstantiationDefinition : TSK_ExplicitInstantiationDeclaration; - // C++0x [temp.explicit]p2: - // [...] An explicit instantiation shall appear in an enclosing - // namespace of its template. [...] - // - // This is C++ DR 275. - CheckExplicitInstantiationScope(*this, Record, NameLoc, true); + CheckExplicitInstantiation(*this, Record, NameLoc, true, TSK); // Verify that it is okay to explicitly instantiate here. CXXRecordDecl *PrevDecl @@ -9096,7 +9378,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, diag::err_explicit_instantiation_inline : diag::warn_explicit_instantiation_inline_0x) << FixItHint::CreateRemoval(D.getDeclSpec().getInlineSpecLoc()); - if (D.getDeclSpec().isConstexprSpecified() && R->isFunctionType()) + if (D.getDeclSpec().hasConstexprSpecifier() && R->isFunctionType()) // FIXME: Add a fix-it to remove the 'constexpr' and add a 'const' if one is // not already specified. Diag(D.getDeclSpec().getConstexprSpecLoc(), @@ -9137,7 +9419,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, if (!PrevTemplate) { if (!Prev || !Prev->isStaticDataMember()) { - // We expect to see a data data member here. + // We expect to see a static data member here. Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_not_known) << Name; for (LookupResult::iterator P = Previous.begin(), PEnd = Previous.end(); @@ -9210,8 +9492,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, diag::ext_explicit_instantiation_without_qualified_id) << Prev << D.getCXXScopeSpec().getRange(); - // Check the scope of this explicit instantiation. - CheckExplicitInstantiationScope(*this, Prev, D.getIdentifierLoc(), true); + CheckExplicitInstantiation(*this, Prev, D.getIdentifierLoc(), true, TSK); // Verify that it is okay to explicitly instantiate here. TemplateSpecializationKind PrevTSK = Prev->getTemplateSpecializationKind(); @@ -9306,7 +9587,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, // have a different target. if (LangOpts.CUDA && IdentifyCUDATarget(Specialization, - /* IgnoreImplicitHDAttributes = */ true) != + /* IgnoreImplicitHDAttr = */ true) != IdentifyCUDATarget(D.getDeclSpec().getAttributes())) { FailedCandidates.addCandidate().set( P.getPair(), FunTmpl->getTemplatedDecl(), @@ -9386,6 +9667,20 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, return (Decl*) nullptr; } + // HACK: libc++ has a bug where it attempts to explicitly instantiate the + // functions + // valarray<size_t>::valarray(size_t) and + // valarray<size_t>::~valarray() + // that it declared to have internal linkage with the internal_linkage + // attribute. Ignore the explicit instantiation declaration in this case. + if (Specialization->hasAttr<InternalLinkageAttr>() && + TSK == TSK_ExplicitInstantiationDeclaration) { + if (auto *RD = dyn_cast<CXXRecordDecl>(Specialization->getDeclContext())) + if (RD->getIdentifier() && RD->getIdentifier()->isStr("valarray") && + RD->isInStdNamespace()) + return (Decl*) nullptr; + } + ProcessDeclAttributeList(S, Specialization, D.getDeclSpec().getAttributes()); // In MSVC mode, dllimported explicit instantiation definitions are treated as @@ -9419,11 +9714,11 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, diag::ext_explicit_instantiation_without_qualified_id) << Specialization << D.getCXXScopeSpec().getRange(); - CheckExplicitInstantiationScope(*this, - FunTmpl? (NamedDecl *)FunTmpl - : Specialization->getInstantiatedFromMemberFunction(), - D.getIdentifierLoc(), - D.getCXXScopeSpec().isSet()); + CheckExplicitInstantiation( + *this, + FunTmpl ? (NamedDecl *)FunTmpl + : Specialization->getInstantiatedFromMemberFunction(), + D.getIdentifierLoc(), D.getCXXScopeSpec().isSet(), TSK); // FIXME: Create some kind of ExplicitInstantiationDecl here. return (Decl*) nullptr; |