summaryrefslogtreecommitdiff
path: root/lib/Sema/SemaTemplate.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaTemplate.cpp')
-rw-r--r--lib/Sema/SemaTemplate.cpp274
1 files changed, 155 insertions, 119 deletions
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 3212281cc34d2..3f2d38630c363 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -20,9 +20,11 @@
#include "clang/Basic/Builtins.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Basic/Stack.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/Lookup.h"
+#include "clang/Sema/Overload.h"
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/SemaInternal.h"
@@ -44,27 +46,7 @@ clang::getTemplateParamsRange(TemplateParameterList const * const *Ps,
return SourceRange(Ps[0]->getTemplateLoc(), Ps[N-1]->getRAngleLoc());
}
-namespace clang {
-/// [temp.constr.decl]p2: A template's associated constraints are
-/// defined as a single constraint-expression derived from the introduced
-/// constraint-expressions [ ... ].
-///
-/// \param Params The template parameter list and optional requires-clause.
-///
-/// \param FD The underlying templated function declaration for a function
-/// template.
-static Expr *formAssociatedConstraints(TemplateParameterList *Params,
- FunctionDecl *FD);
-}
-
-static Expr *clang::formAssociatedConstraints(TemplateParameterList *Params,
- FunctionDecl *FD) {
- // FIXME: Concepts: collect additional introduced constraint-expressions
- assert(!FD && "Cannot collect constraints from function declaration yet.");
- return Params->getRequiresClause();
-}
-
-/// Determine whether the declaration found is acceptable as the name
+/// \brief Determine whether the declaration found is acceptable as the name
/// of a template and, if so, return that template declaration. Otherwise,
/// returns null.
///
@@ -362,13 +344,27 @@ bool Sema::LookupTemplateName(LookupResult &Found,
// x->B::f, and we are looking into the type of the object.
assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist");
LookupCtx = computeDeclContext(ObjectType);
- IsDependent = !LookupCtx;
+ IsDependent = !LookupCtx && ObjectType->isDependentType();
assert((IsDependent || !ObjectType->isIncompleteType() ||
ObjectType->castAs<TagType>()->isBeingDefined()) &&
"Caller should have completed object type");
- // Template names cannot appear inside an Objective-C class or object type.
- if (ObjectType->isObjCObjectOrInterfaceType()) {
+ // Template names cannot appear inside an Objective-C class or object type
+ // or a vector type.
+ //
+ // FIXME: This is wrong. For example:
+ //
+ // template<typename T> using Vec = T __attribute__((ext_vector_type(4)));
+ // Vec<int> vi;
+ // vi.Vec<int>::~Vec<int>();
+ //
+ // ... should be accepted but we will not treat 'Vec' as a template name
+ // here. The right thing to do would be to check if the name is a valid
+ // vector component name, and look up a template name if not. And similarly
+ // for lookups into Objective-C class and object types, where the same
+ // problem can arise.
+ if (ObjectType->isObjCObjectOrInterfaceType() ||
+ ObjectType->isVectorType()) {
Found.clear();
return false;
}
@@ -630,7 +626,7 @@ void Sema::diagnoseExprIntendedAsTemplateName(Scope *S, ExprResult TemplateName,
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<TemplateCandidateFilter>(*this);
+ return std::make_unique<TemplateCandidateFilter>(*this);
}
};
@@ -720,9 +716,13 @@ Sema::BuildDependentDeclRefExpr(const CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *TemplateArgs) {
+ // DependentScopeDeclRefExpr::Create requires a valid QualifierLoc
+ NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context);
+ if (!QualifierLoc)
+ return ExprError();
+
return DependentScopeDeclRefExpr::Create(
- Context, SS.getWithLocInContext(Context), TemplateKWLoc, NameInfo,
- TemplateArgs);
+ Context, QualifierLoc, TemplateKWLoc, NameInfo, TemplateArgs);
}
@@ -830,15 +830,14 @@ bool Sema::DiagnoseUninstantiableTemplate(SourceLocation PointOfInstantiation,
void Sema::DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl) {
assert(PrevDecl->isTemplateParameter() && "Not a template parameter");
- // Microsoft Visual C++ permits template parameters to be shadowed.
- if (getLangOpts().MicrosoftExt)
- return;
-
// C++ [temp.local]p4:
// A template-parameter shall not be redeclared within its
// scope (including nested scopes).
- Diag(Loc, diag::err_template_param_shadow)
- << cast<NamedDecl>(PrevDecl)->getDeclName();
+ //
+ // Make this a warning when MSVC compatibility is requested.
+ unsigned DiagId = getLangOpts().MSVCCompat ? diag::ext_template_param_shadow
+ : diag::err_template_param_shadow;
+ Diag(Loc, DiagId) << cast<NamedDecl>(PrevDecl)->getDeclName();
Diag(PrevDecl->getLocation(), diag::note_template_param_here);
}
@@ -987,17 +986,16 @@ NamedDecl *Sema::ActOnTypeParameter(Scope *S, bool Typename,
assert(S->isTemplateParamScope() &&
"Template type parameter not in template parameter scope!");
- SourceLocation Loc = ParamNameLoc;
- if (!ParamName)
- Loc = KeyLoc;
-
bool IsParameterPack = EllipsisLoc.isValid();
- TemplateTypeParmDecl *Param
- = TemplateTypeParmDecl::Create(Context, Context.getTranslationUnitDecl(),
- KeyLoc, Loc, Depth, Position, ParamName,
- Typename, IsParameterPack);
+ TemplateTypeParmDecl *Param = TemplateTypeParmDecl::Create(
+ Context, Context.getTranslationUnitDecl(), KeyLoc, ParamNameLoc, Depth,
+ Position, ParamName, Typename, IsParameterPack);
Param->setAccess(AS_public);
+ if (Param->isParameterPack())
+ if (auto *LSI = getEnclosingLambda())
+ LSI->LocalPacks.push_back(Param);
+
if (ParamName) {
maybeDiagnoseTemplateParameterShadow(*this, S, ParamNameLoc, ParamName);
@@ -1022,7 +1020,7 @@ NamedDecl *Sema::ActOnTypeParameter(Scope *S, bool Typename,
assert(DefaultTInfo && "expected source information for type");
// Check for unexpanded parameter packs.
- if (DiagnoseUnexpandedParameterPack(Loc, DefaultTInfo,
+ if (DiagnoseUnexpandedParameterPack(ParamNameLoc, DefaultTInfo,
UPPC_DefaultArgument))
return Param;
@@ -1082,9 +1080,6 @@ QualType Sema::CheckNonTypeTemplateParameterType(QualType T,
T->isMemberPointerType() ||
// -- std::nullptr_t.
T->isNullPtrType() ||
- // If T is a dependent type, we can't do the check now, so we
- // assume that it is well-formed.
- T->isDependentType() ||
// Allow use of auto in template parameter declarations.
T->isUndeducedType()) {
// C++ [temp.param]p5: The top-level cv-qualifiers on the template-parameter
@@ -1097,9 +1092,18 @@ QualType Sema::CheckNonTypeTemplateParameterType(QualType T,
// A non-type template-parameter of type "array of T" or
// "function returning T" is adjusted to be of type "pointer to
// T" or "pointer to function returning T", respectively.
- else if (T->isArrayType() || T->isFunctionType())
+ if (T->isArrayType() || T->isFunctionType())
return Context.getDecayedType(T);
+ // If T is a dependent type, we can't do the check now, so we
+ // assume that it is well-formed. Note that stripping off the
+ // qualifiers here is not really correct if T turns out to be
+ // an array type, but we'll recompute the type everywhere it's
+ // used during instantiation, so that should be OK. (Using the
+ // qualified type is equally wrong.)
+ if (T->isDependentType())
+ return T.getUnqualifiedType();
+
Diag(Loc, diag::err_template_nontype_parm_bad_type)
<< T;
@@ -1196,6 +1200,10 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
if (Invalid)
Param->setInvalidDecl();
+ if (Param->isParameterPack())
+ if (auto *LSI = getEnclosingLambda())
+ LSI->LocalPacks.push_back(Param);
+
if (ParamName) {
maybeDiagnoseTemplateParameterShadow(*this, S, D.getIdentifierLoc(),
ParamName);
@@ -1259,6 +1267,10 @@ NamedDecl *Sema::ActOnTemplateTemplateParameter(Scope* S,
Name, Params);
Param->setAccess(AS_public);
+ if (Param->isParameterPack())
+ if (auto *LSI = getEnclosingLambda())
+ LSI->LocalPacks.push_back(Param);
+
// If the template template parameter has a name, then link the identifier
// into the scope and lookup mechanisms.
if (Name) {
@@ -1502,9 +1514,6 @@ DeclResult Sema::CheckClassTemplate(
}
}
- // TODO Memory management; associated constraints are not always stored.
- Expr *const CurAC = formAssociatedConstraints(TemplateParams, 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
@@ -1516,30 +1525,6 @@ DeclResult Sema::CheckClassTemplate(
TPL_TemplateMatch))
return true;
- // Check for matching associated constraints on redeclarations.
- const Expr *const PrevAC = PrevClassTemplate->getAssociatedConstraints();
- const bool RedeclACMismatch = [&] {
- if (!(CurAC || PrevAC))
- return false; // Nothing to check; no mismatch.
- if (CurAC && PrevAC) {
- llvm::FoldingSetNodeID CurACInfo, PrevACInfo;
- CurAC->Profile(CurACInfo, Context, /*Canonical=*/true);
- PrevAC->Profile(PrevACInfo, Context, /*Canonical=*/true);
- if (CurACInfo == PrevACInfo)
- return false; // All good; no mismatch.
- }
- return true;
- }();
-
- if (RedeclACMismatch) {
- Diag(CurAC ? CurAC->getBeginLoc() : NameLoc,
- diag::err_template_different_associated_constraints);
- Diag(PrevAC ? PrevAC->getBeginLoc() : PrevClassTemplate->getLocation(),
- diag::note_template_prev_declaration)
- << /*declaration*/ 0;
- return true;
- }
-
// C++ [temp.class]p4:
// In a redeclaration, partial specialization, explicit
// specialization or explicit instantiation of a class template,
@@ -1643,15 +1628,10 @@ DeclResult Sema::CheckClassTemplate(
AddMsStructLayoutForRecord(NewClass);
}
- // Attach the associated constraints when the declaration will not be part of
- // a decl chain.
- Expr *const ACtoAttach =
- PrevClassTemplate && ShouldAddRedecl ? nullptr : CurAC;
-
ClassTemplateDecl *NewTemplate
= ClassTemplateDecl::Create(Context, SemanticContext, NameLoc,
DeclarationName(Name), TemplateParams,
- NewClass, ACtoAttach);
+ NewClass);
if (ShouldAddRedecl)
NewTemplate->setPreviousDecl(PrevClassTemplate);
@@ -1690,6 +1670,7 @@ DeclResult Sema::CheckClassTemplate(
mergeDeclAttributes(NewClass, PrevClassTemplate->getTemplatedDecl());
AddPushedVisibilityAttribute(NewClass);
+ inferGslOwnerPointerAttribute(NewClass);
if (TUK != TUK_Friend) {
// Per C++ [basic.scope.temp]p2, skip the template parameter scopes.
@@ -3440,7 +3421,7 @@ bool Sema::resolveAssumedTemplateNameAsType(Scope *S, TemplateName &Name,
getAsTypeTemplateDecl(TC.getCorrectionDecl());
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<CandidateCallback>(*this);
+ return std::make_unique<CandidateCallback>(*this);
}
} FilterCCC;
@@ -4239,14 +4220,47 @@ void Sema::diagnoseMissingTemplateArguments(TemplateName Name,
ExprResult
Sema::CheckConceptTemplateId(const CXXScopeSpec &SS,
- const DeclarationNameInfo &NameInfo,
- ConceptDecl *Template,
- SourceLocation TemplateLoc,
+ SourceLocation TemplateKWLoc,
+ SourceLocation ConceptNameLoc,
+ NamedDecl *FoundDecl,
+ ConceptDecl *NamedConcept,
const TemplateArgumentListInfo *TemplateArgs) {
- // TODO: Do concept specialization here.
- Diag(NameInfo.getBeginLoc(), diag::err_concept_not_implemented) <<
- "concept specialization";
- return ExprError();
+ assert(NamedConcept && "A concept template id without a template?");
+
+ llvm::SmallVector<TemplateArgument, 4> Converted;
+ if (CheckTemplateArgumentList(NamedConcept, ConceptNameLoc,
+ const_cast<TemplateArgumentListInfo&>(*TemplateArgs),
+ /*PartialTemplateArgs=*/false, Converted,
+ /*UpdateArgsWithConversion=*/false))
+ return ExprError();
+
+ Optional<bool> IsSatisfied;
+ bool AreArgsDependent = false;
+ for (TemplateArgument &Arg : Converted) {
+ if (Arg.isDependent()) {
+ AreArgsDependent = true;
+ break;
+ }
+ }
+ if (!AreArgsDependent) {
+ InstantiatingTemplate Inst(*this, ConceptNameLoc,
+ InstantiatingTemplate::ConstraintsCheck{}, NamedConcept, Converted,
+ SourceRange(SS.isSet() ? SS.getBeginLoc() : ConceptNameLoc,
+ TemplateArgs->getRAngleLoc()));
+ MultiLevelTemplateArgumentList MLTAL;
+ MLTAL.addOuterTemplateArguments(Converted);
+ bool Satisfied;
+ if (CalculateConstraintSatisfaction(NamedConcept, MLTAL,
+ NamedConcept->getConstraintExpr(),
+ Satisfied))
+ return ExprError();
+ IsSatisfied = Satisfied;
+ }
+ return ConceptSpecializationExpr::Create(Context,
+ SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc{},
+ TemplateKWLoc, ConceptNameLoc, FoundDecl, NamedConcept,
+ ASTTemplateArgumentListInfo::Create(Context, *TemplateArgs), Converted,
+ IsSatisfied);
}
ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
@@ -4289,10 +4303,11 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
TemplateKWLoc, TemplateArgs);
}
- if (R.getAsSingle<ConceptDecl>() && !AnyDependentArguments()) {
- return CheckConceptTemplateId(SS, R.getLookupNameInfo(),
- R.getAsSingle<ConceptDecl>(),
- TemplateKWLoc, TemplateArgs);
+ if (R.getAsSingle<ConceptDecl>()) {
+ return CheckConceptTemplateId(SS, TemplateKWLoc,
+ R.getLookupNameInfo().getBeginLoc(),
+ R.getFoundDecl(),
+ R.getAsSingle<ConceptDecl>(), TemplateArgs);
}
// We don't want lookup warnings at this point.
@@ -4678,6 +4693,7 @@ SubstDefaultTemplateArgument(Sema &SemaRef,
for (unsigned i = 0, e = Param->getDepth(); i != e; ++i)
TemplateArgLists.addOuterTemplateArguments(None);
+ Sema::ContextRAII SavedContext(SemaRef, Template->getDeclContext());
EnterExpressionEvaluationContext ConstantEvaluated(
SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated);
return SemaRef.SubstExpr(Param->getDefaultArgument(), TemplateArgLists);
@@ -4895,9 +4911,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
if (NTTP->isParameterPack() && NTTP->isExpandedParameterPack())
NTTPType = NTTP->getExpansionType(ArgumentPackIndex);
- // FIXME: Do we need to substitute into parameters here if they're
- // instantiation-dependent but not dependent?
- if (NTTPType->isDependentType() &&
+ if (NTTPType->isInstantiationDependentType() &&
!isa<TemplateTemplateParmDecl>(Template) &&
!Template->getDeclContext()->isDependentContext()) {
// Do substitution on the type of the non-type template parameter.
@@ -5471,7 +5485,7 @@ namespace {
bool Visit##Class##Type(const Class##Type *) { return false; }
#define NON_CANONICAL_TYPE(Class, Parent) \
bool Visit##Class##Type(const Class##Type *) { return false; }
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
bool VisitTagDecl(const TagDecl *Tag);
bool VisitNestedNameSpecifier(NestedNameSpecifier *NNS);
@@ -5847,7 +5861,7 @@ static bool CheckTemplateArgumentIsCompatibleWithParameter(
Expr *Arg, QualType ArgType) {
bool ObjCLifetimeConversion;
if (ParamType->isPointerType() &&
- !ParamType->getAs<PointerType>()->getPointeeType()->isFunctionType() &&
+ !ParamType->castAs<PointerType>()->getPointeeType()->isFunctionType() &&
S.IsQualificationConversion(ArgType, ParamType, false,
ObjCLifetimeConversion)) {
// For pointer-to-object types, qualification conversions are
@@ -6399,8 +6413,11 @@ 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()) {
+ // type-dependent, there's nothing we can check now. The argument only
+ // contains an unexpanded pack during partial ordering, and there's
+ // nothing more we can check in that case.
+ if (ParamType->isDependentType() || Arg->isTypeDependent() ||
+ Arg->containsUnexpandedParameterPack()) {
// Force the argument to the type of the parameter to maintain invariants.
auto *PE = dyn_cast<PackExpansionExpr>(Arg);
if (PE)
@@ -6720,20 +6737,20 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// overloaded functions (or a pointer to such), the matching
// function is selected from the set (13.4).
(ParamType->isPointerType() &&
- ParamType->getAs<PointerType>()->getPointeeType()->isFunctionType()) ||
+ ParamType->castAs<PointerType>()->getPointeeType()->isFunctionType()) ||
// -- For a non-type template-parameter of type reference to
// function, no conversions apply. If the template-argument
// represents a set of overloaded functions, the matching
// function is selected from the set (13.4).
(ParamType->isReferenceType() &&
- ParamType->getAs<ReferenceType>()->getPointeeType()->isFunctionType()) ||
+ ParamType->castAs<ReferenceType>()->getPointeeType()->isFunctionType()) ||
// -- For a non-type template-parameter of type pointer to
// member function, no conversions apply. If the
// template-argument represents a set of overloaded member
// functions, the matching member function is selected from
// the set (13.4).
(ParamType->isMemberPointerType() &&
- ParamType->getAs<MemberPointerType>()->getPointeeType()
+ ParamType->castAs<MemberPointerType>()->getPointeeType()
->isFunctionType())) {
if (Arg->getType() == Context.OverloadTy) {
@@ -7198,6 +7215,9 @@ static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old,
TemplateArgLoc);
}
+ // TODO: Concepts: Match immediately-introduced-constraint for type
+ // constraints
+
return true;
}
@@ -7223,6 +7243,15 @@ void DiagnoseTemplateParameterListArityMismatch(Sema &S,
<< SourceRange(Old->getTemplateLoc(), Old->getRAngleLoc());
}
+static void
+DiagnoseTemplateParameterListRequiresClauseMismatch(Sema &S,
+ TemplateParameterList *New,
+ TemplateParameterList *Old){
+ S.Diag(New->getTemplateLoc(), diag::err_template_different_requires_clause);
+ S.Diag(Old->getTemplateLoc(), diag::note_template_prev_declaration)
+ << /*declaration*/0;
+}
+
/// Determine whether the given template parameter lists are
/// equivalent.
///
@@ -7312,6 +7341,27 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
return false;
}
+ if (Kind != TPL_TemplateTemplateArgumentMatch) {
+ const Expr *NewRC = New->getRequiresClause();
+ const Expr *OldRC = Old->getRequiresClause();
+ if (!NewRC != !OldRC) {
+ if (Complain)
+ DiagnoseTemplateParameterListRequiresClauseMismatch(*this, New, Old);
+ return false;
+ }
+
+ if (NewRC) {
+ llvm::FoldingSetNodeID OldRCID, NewRCID;
+ OldRC->Profile(OldRCID, Context, /*Canonical=*/true);
+ NewRC->Profile(NewRCID, Context, /*Canonical=*/true);
+ if (OldRCID != NewRCID) {
+ if (Complain)
+ DiagnoseTemplateParameterListRequiresClauseMismatch(*this, New, Old);
+ return false;
+ }
+ }
+ }
+
return true;
}
@@ -8020,24 +8070,10 @@ Decl *Sema::ActOnConceptDefinition(Scope *S,
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()) {
+
+ if (NewDecl->hasAssociatedConstraints()) {
// 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();
}
@@ -8453,7 +8489,7 @@ bool Sema::CheckFunctionTemplateSpecialization(
// candidates at once, to get proper sorting and limiting.
for (auto *OldND : Previous) {
if (auto *OldFD = dyn_cast<FunctionDecl>(OldND->getUnderlyingDecl()))
- NoteOverloadCandidate(OldND, OldFD, FD->getType(), false);
+ NoteOverloadCandidate(OldND, OldFD, CRK_None, FD->getType(), false);
}
FailedCandidates.NoteCandidates(*this, FD->getLocation());
return true;
@@ -10282,7 +10318,7 @@ void Sema::MarkAsLateParsedTemplate(FunctionDecl *FD, Decl *FnD,
if (!FD)
return;
- auto LPT = llvm::make_unique<LateParsedTemplate>();
+ auto LPT = std::make_unique<LateParsedTemplate>();
// Take tokens to avoid allocations
LPT->Toks.swap(Toks);