[Concept] Associated Constraints Infrastructure

Add code to correctly calculate the associated constraints of a template (no enforcement yet).
D41284 on Phabricator.

llvm-svn: 374938
This commit is contained in:
Saar Raz 2019-10-15 18:44:06 +00:00
parent 5836c356fa
commit 0330fba6e1
18 changed files with 293 additions and 210 deletions

View File

@ -237,6 +237,9 @@ public:
for (const auto &TP : *TPL) for (const auto &TP : *TPL)
Visit(TP); Visit(TP);
if (const Expr *RC = TPL->getRequiresClause())
Visit(RC);
} }
void void

View File

@ -168,6 +168,16 @@ public:
return HasRequiresClause ? *getTrailingObjects<Expr *>() : nullptr; return HasRequiresClause ? *getTrailingObjects<Expr *>() : nullptr;
} }
/// \brief All associated constraints derived from this template parameter
/// list, including the requires clause and any constraints derived from
/// constrained-parameters.
///
/// The constraints in the resulting list are to be treated as if in a
/// conjunction ("and").
void getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const;
bool hasAssociatedConstraints() const;
SourceLocation getTemplateLoc() const { return TemplateLoc; } SourceLocation getTemplateLoc() const { return TemplateLoc; }
SourceLocation getLAngleLoc() const { return LAngleLoc; } SourceLocation getLAngleLoc() const { return LAngleLoc; }
SourceLocation getRAngleLoc() const { return RAngleLoc; } SourceLocation getRAngleLoc() const { return RAngleLoc; }
@ -369,33 +379,7 @@ public:
// Kinds of Templates // Kinds of Templates
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
/// Stores the template parameter list and associated constraints for /// \brief The base class of all kinds of template declarations (e.g.,
/// \c TemplateDecl objects that track associated constraints.
class ConstrainedTemplateDeclInfo {
friend TemplateDecl;
public:
ConstrainedTemplateDeclInfo() = default;
TemplateParameterList *getTemplateParameters() const {
return TemplateParams;
}
Expr *getAssociatedConstraints() const { return AssociatedConstraints; }
protected:
void setTemplateParameters(TemplateParameterList *TParams) {
TemplateParams = TParams;
}
void setAssociatedConstraints(Expr *AC) { AssociatedConstraints = AC; }
TemplateParameterList *TemplateParams = nullptr;
Expr *AssociatedConstraints = nullptr;
};
/// The base class of all kinds of template declarations (e.g.,
/// class, function, etc.). /// class, function, etc.).
/// ///
/// The TemplateDecl class stores the list of template parameters and a /// The TemplateDecl class stores the list of template parameters and a
@ -404,54 +388,32 @@ class TemplateDecl : public NamedDecl {
void anchor() override; void anchor() override;
protected: protected:
// Construct a template decl with name, parameters, and templated element.
TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name,
TemplateParameterList *Params, NamedDecl *Decl);
// Construct a template decl with the given name and parameters. // Construct a template decl with the given name and parameters.
// Used when there is no templated element (e.g., for tt-params). // Used when there is no templated element (e.g., for tt-params).
TemplateDecl(ConstrainedTemplateDeclInfo *CTDI, Kind DK, DeclContext *DC,
SourceLocation L, DeclarationName Name,
TemplateParameterList *Params)
: NamedDecl(DK, DC, L, Name), TemplatedDecl(nullptr),
TemplateParams(CTDI) {
this->setTemplateParameters(Params);
}
TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name, TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name,
TemplateParameterList *Params) TemplateParameterList *Params)
: TemplateDecl(nullptr, DK, DC, L, Name, Params) {} : TemplateDecl(DK, DC, L, Name, Params, nullptr) {}
// Construct a template decl with name, parameters, and templated element.
TemplateDecl(ConstrainedTemplateDeclInfo *CTDI, Kind DK, DeclContext *DC,
SourceLocation L, DeclarationName Name,
TemplateParameterList *Params, NamedDecl *Decl)
: NamedDecl(DK, DC, L, Name), TemplatedDecl(Decl),
TemplateParams(CTDI) {
this->setTemplateParameters(Params);
}
TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name,
TemplateParameterList *Params, NamedDecl *Decl)
: TemplateDecl(nullptr, DK, DC, L, Name, Params, Decl) {}
public: public:
friend class ASTDeclReader;
friend class ASTDeclWriter;
/// Get the list of template parameters /// Get the list of template parameters
TemplateParameterList *getTemplateParameters() const { TemplateParameterList *getTemplateParameters() const {
const auto *const CTDI = return TemplateParams;
TemplateParams.dyn_cast<ConstrainedTemplateDeclInfo *>();
return CTDI ? CTDI->getTemplateParameters()
: TemplateParams.get<TemplateParameterList *>();
} }
/// Get the constraint-expression from the associated requires-clause (if any) /// \brief Get the total constraint-expression associated with this template,
const Expr *getRequiresClause() const { /// including constraint-expressions derived from the requires-clause,
const TemplateParameterList *const TP = getTemplateParameters(); /// trailing requires-clause (for functions and methods) and constrained
return TP ? TP->getRequiresClause() : nullptr; /// template parameters.
} void getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const;
Expr *getAssociatedConstraints() const { bool hasAssociatedConstraints() const;
const auto *const C = cast<TemplateDecl>(getCanonicalDecl());
const auto *const CTDI =
C->TemplateParams.dyn_cast<ConstrainedTemplateDeclInfo *>();
return CTDI ? CTDI->getAssociatedConstraints() : nullptr;
}
/// Get the underlying, templated declaration. /// Get the underlying, templated declaration.
NamedDecl *getTemplatedDecl() const { return TemplatedDecl; } NamedDecl *getTemplatedDecl() const { return TemplatedDecl; }
@ -470,30 +432,11 @@ public:
protected: protected:
NamedDecl *TemplatedDecl; NamedDecl *TemplatedDecl;
TemplateParameterList *TemplateParams;
/// The template parameter list and optional requires-clause
/// associated with this declaration; alternatively, a
/// \c ConstrainedTemplateDeclInfo if the associated constraints of the
/// template are being tracked by this particular declaration.
llvm::PointerUnion<TemplateParameterList *,
ConstrainedTemplateDeclInfo *>
TemplateParams;
void setTemplateParameters(TemplateParameterList *TParams) { void setTemplateParameters(TemplateParameterList *TParams) {
if (auto *const CTDI =
TemplateParams.dyn_cast<ConstrainedTemplateDeclInfo *>()) {
CTDI->setTemplateParameters(TParams);
} else {
TemplateParams = TParams; TemplateParams = TParams;
} }
}
void setAssociatedConstraints(Expr *AC) {
assert(isCanonicalDecl() &&
"Attaching associated constraints to non-canonical Decl");
TemplateParams.get<ConstrainedTemplateDeclInfo *>()
->setAssociatedConstraints(AC);
}
public: public:
/// Initialize the underlying templated declaration and /// Initialize the underlying templated declaration and
@ -889,17 +832,10 @@ protected:
virtual CommonBase *newCommon(ASTContext &C) const = 0; virtual CommonBase *newCommon(ASTContext &C) const = 0;
// Construct a template decl with name, parameters, and templated element. // Construct a template decl with name, parameters, and templated element.
RedeclarableTemplateDecl(ConstrainedTemplateDeclInfo *CTDI, Kind DK,
ASTContext &C, DeclContext *DC, SourceLocation L,
DeclarationName Name, TemplateParameterList *Params,
NamedDecl *Decl)
: TemplateDecl(CTDI, DK, DC, L, Name, Params, Decl), redeclarable_base(C)
{}
RedeclarableTemplateDecl(Kind DK, ASTContext &C, DeclContext *DC, RedeclarableTemplateDecl(Kind DK, ASTContext &C, DeclContext *DC,
SourceLocation L, DeclarationName Name, SourceLocation L, DeclarationName Name,
TemplateParameterList *Params, NamedDecl *Decl) TemplateParameterList *Params, NamedDecl *Decl)
: RedeclarableTemplateDecl(nullptr, DK, C, DC, L, Name, Params, Decl) {} : TemplateDecl(DK, DC, L, Name, Params, Decl), redeclarable_base(C) {}
public: public:
friend class ASTDeclReader; friend class ASTDeclReader;
@ -2026,6 +1962,20 @@ public:
return TemplateParams; return TemplateParams;
} }
/// \brief All associated constraints of this partial specialization,
/// including the requires clause and any constraints derived from
/// constrained-parameters.
///
/// The constraints in the resulting list are to be treated as if in a
/// conjunction ("and").
void getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const {
TemplateParams->getAssociatedConstraints(AC);
}
bool hasAssociatedConstraints() const {
return TemplateParams->hasAssociatedConstraints();
}
/// Get the template arguments as written. /// Get the template arguments as written.
const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const { const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
return ArgsAsWritten; return ArgsAsWritten;
@ -2145,16 +2095,10 @@ protected:
llvm::FoldingSetVector<ClassTemplatePartialSpecializationDecl> & llvm::FoldingSetVector<ClassTemplatePartialSpecializationDecl> &
getPartialSpecializations(); getPartialSpecializations();
ClassTemplateDecl(ConstrainedTemplateDeclInfo *CTDI, ASTContext &C,
DeclContext *DC, SourceLocation L, DeclarationName Name,
TemplateParameterList *Params, NamedDecl *Decl)
: RedeclarableTemplateDecl(CTDI, ClassTemplate, C, DC, L, Name, Params,
Decl) {}
ClassTemplateDecl(ASTContext &C, DeclContext *DC, SourceLocation L, ClassTemplateDecl(ASTContext &C, DeclContext *DC, SourceLocation L,
DeclarationName Name, TemplateParameterList *Params, DeclarationName Name, TemplateParameterList *Params,
NamedDecl *Decl) NamedDecl *Decl)
: ClassTemplateDecl(nullptr, C, DC, L, Name, Params, Decl) {} : RedeclarableTemplateDecl(ClassTemplate, C, DC, L, Name, Params, Decl) {}
CommonBase *newCommon(ASTContext &C) const override; CommonBase *newCommon(ASTContext &C) const override;
@ -2180,14 +2124,12 @@ public:
return getTemplatedDecl()->isThisDeclarationADefinition(); return getTemplatedDecl()->isThisDeclarationADefinition();
} }
// FIXME: remove default argument for AssociatedConstraints /// \brief Create a class template node.
/// Create a class template node.
static ClassTemplateDecl *Create(ASTContext &C, DeclContext *DC, static ClassTemplateDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L, SourceLocation L,
DeclarationName Name, DeclarationName Name,
TemplateParameterList *Params, TemplateParameterList *Params,
NamedDecl *Decl, NamedDecl *Decl);
Expr *AssociatedConstraints = nullptr);
/// Create an empty class template node. /// Create an empty class template node.
static ClassTemplateDecl *CreateDeserialized(ASTContext &C, unsigned ID); static ClassTemplateDecl *CreateDeserialized(ASTContext &C, unsigned ID);
@ -2862,7 +2804,21 @@ public:
return ArgsAsWritten; return ArgsAsWritten;
} }
/// Retrieve the member variable template partial specialization from /// \brief All associated constraints of this partial specialization,
/// including the requires clause and any constraints derived from
/// constrained-parameters.
///
/// The constraints in the resulting list are to be treated as if in a
/// conjunction ("and").
void getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const {
TemplateParams->getAssociatedConstraints(AC);
}
bool hasAssociatedConstraints() const {
return TemplateParams->hasAssociatedConstraints();
}
/// \brief Retrieve the member variable template partial specialization from
/// which this particular variable template partial specialization was /// which this particular variable template partial specialization was
/// instantiated. /// instantiated.
/// ///
@ -3091,11 +3047,9 @@ class ConceptDecl : public TemplateDecl, public Mergeable<ConceptDecl> {
protected: protected:
Expr *ConstraintExpr; Expr *ConstraintExpr;
ConceptDecl(DeclContext *DC, ConceptDecl(DeclContext *DC, SourceLocation L, DeclarationName Name,
SourceLocation L, DeclarationName Name, TemplateParameterList *Params, Expr *ConstraintExpr)
TemplateParameterList *Params, : TemplateDecl(Concept, DC, L, Name, Params),
Expr *ConstraintExpr)
: TemplateDecl(nullptr, Concept, DC, L, Name, Params),
ConstraintExpr(ConstraintExpr) {}; ConstraintExpr(ConstraintExpr) {};
public: public:
static ConceptDecl *Create(ASTContext &C, DeclContext *DC, static ConceptDecl *Create(ASTContext &C, DeclContext *DC,

View File

@ -1633,9 +1633,11 @@ template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseTemplateParameterListHelper( bool RecursiveASTVisitor<Derived>::TraverseTemplateParameterListHelper(
TemplateParameterList *TPL) { TemplateParameterList *TPL) {
if (TPL) { if (TPL) {
for (TemplateParameterList::iterator I = TPL->begin(), E = TPL->end(); for (NamedDecl *D : *TPL) {
I != E; ++I) { TRY_TO(TraverseDecl(D));
TRY_TO(TraverseDecl(*I)); }
if (Expr *RequiresClause = TPL->getRequiresClause()) {
TRY_TO(TraverseStmt(RequiresClause));
} }
} }
return true; return true;

View File

@ -2543,8 +2543,8 @@ def err_non_constant_constraint_expression : Error<
def err_non_bool_atomic_constraint : Error< def err_non_bool_atomic_constraint : Error<
"atomic constraint must be of type 'bool' (found %0)">; "atomic constraint must be of type 'bool' (found %0)">;
def err_template_different_associated_constraints : Error< def err_template_different_requires_clause : Error<
"associated constraints differ in template redeclaration">; "requires clause differs in template redeclaration">;
// C++11 char16_t/char32_t // C++11 char16_t/char32_t
def warn_cxx98_compat_unicode_type : Warning< def warn_cxx98_compat_unicode_type : Warning<

View File

@ -6058,6 +6058,12 @@ public:
Expr *ConstraintExpr, Expr *ConstraintExpr,
bool &IsSatisfied); bool &IsSatisfied);
/// Check that the associated constraints of a template declaration match the
/// associated constraints of an older declaration of which it is a
/// redeclaration.
bool CheckRedeclarationConstraintMatch(TemplateParameterList *Old,
TemplateParameterList *New);
// ParseObjCStringLiteral - Parse Objective-C string literals. // ParseObjCStringLiteral - Parse Objective-C string literals.
ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs, ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs,
ArrayRef<Expr *> Strings); ArrayRef<Expr *> Strings);

View File

@ -738,7 +738,7 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
cast<TemplateTemplateParmDecl>(*P))); cast<TemplateTemplateParmDecl>(*P)));
} }
assert(!TTP->getRequiresClause() && assert(!TTP->getTemplateParameters()->getRequiresClause() &&
"Unexpected requires-clause on template template-parameter"); "Unexpected requires-clause on template template-parameter");
Expr *const CanonRequiresClause = nullptr; Expr *const CanonRequiresClause = nullptr;

View File

@ -70,6 +70,8 @@ TemplateParameterList::TemplateParameterList(SourceLocation TemplateLoc,
} }
if (RequiresClause) { if (RequiresClause) {
*getTrailingObjects<Expr *>() = RequiresClause; *getTrailingObjects<Expr *>() = RequiresClause;
if (RequiresClause->containsUnexpandedParameterPack())
ContainsUnexpandedParameterPack = true;
} }
} }
@ -136,6 +138,18 @@ static void AdoptTemplateParameterList(TemplateParameterList *Params,
} }
} }
void TemplateParameterList::
getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const {
// TODO: Concepts: Collect immediately-introduced constraints.
if (HasRequiresClause)
AC.push_back(getRequiresClause());
}
bool TemplateParameterList::hasAssociatedConstraints() const {
// TODO: Concepts: Regard immediately-introduced constraints.
return HasRequiresClause;
}
namespace clang { namespace clang {
void *allocateDefaultArgStorageChain(const ASTContext &C) { void *allocateDefaultArgStorageChain(const ASTContext &C) {
@ -144,6 +158,28 @@ void *allocateDefaultArgStorageChain(const ASTContext &C) {
} // namespace clang } // namespace clang
//===----------------------------------------------------------------------===//
// TemplateDecl Implementation
//===----------------------------------------------------------------------===//
TemplateDecl::TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L,
DeclarationName Name, TemplateParameterList *Params,
NamedDecl *Decl)
: NamedDecl(DK, DC, L, Name), TemplatedDecl(Decl), TemplateParams(Params) {}
void TemplateDecl::anchor() {}
void TemplateDecl::
getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const {
// TODO: Concepts: Append function trailing requires clause.
TemplateParams->getAssociatedConstraints(AC);
}
bool TemplateDecl::hasAssociatedConstraints() const {
// TODO: Concepts: Regard function trailing requires clause.
return TemplateParams->hasAssociatedConstraints();
}
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// RedeclarableTemplateDecl Implementation // RedeclarableTemplateDecl Implementation
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@ -344,19 +380,10 @@ ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C,
SourceLocation L, SourceLocation L,
DeclarationName Name, DeclarationName Name,
TemplateParameterList *Params, TemplateParameterList *Params,
NamedDecl *Decl, NamedDecl *Decl) {
Expr *AssociatedConstraints) {
AdoptTemplateParameterList(Params, cast<DeclContext>(Decl)); AdoptTemplateParameterList(Params, cast<DeclContext>(Decl));
if (!AssociatedConstraints) {
return new (C, DC) ClassTemplateDecl(C, DC, L, Name, Params, Decl); return new (C, DC) ClassTemplateDecl(C, DC, L, Name, Params, Decl);
}
auto *const CTDI = new (C) ConstrainedTemplateDeclInfo;
auto *const New =
new (C, DC) ClassTemplateDecl(CTDI, C, DC, L, Name, Params, Decl);
New->setAssociatedConstraints(AssociatedConstraints);
return New;
} }
ClassTemplateDecl *ClassTemplateDecl::CreateDeserialized(ASTContext &C, ClassTemplateDecl *ClassTemplateDecl::CreateDeserialized(ASTContext &C,
@ -707,12 +734,6 @@ FunctionTemplateSpecializationInfo *FunctionTemplateSpecializationInfo::Create(
FD, Template, TSK, TemplateArgs, ArgsAsWritten, POI, MSInfo); FD, Template, TSK, TemplateArgs, ArgsAsWritten, POI, MSInfo);
} }
//===----------------------------------------------------------------------===//
// TemplateDecl Implementation
//===----------------------------------------------------------------------===//
void TemplateDecl::anchor() {}
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// ClassTemplateSpecializationDecl Implementation // ClassTemplateSpecializationDecl Implementation
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//

View File

@ -45,27 +45,7 @@ clang::getTemplateParamsRange(TemplateParameterList const * const *Ps,
return SourceRange(Ps[0]->getTemplateLoc(), Ps[N-1]->getRAngleLoc()); return SourceRange(Ps[0]->getTemplateLoc(), Ps[N-1]->getRAngleLoc());
} }
namespace clang { /// \brief Determine whether the declaration found is acceptable as the name
/// [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
/// of a template and, if so, return that template declaration. Otherwise, /// of a template and, if so, return that template declaration. Otherwise,
/// returns null. /// returns null.
/// ///
@ -1533,9 +1513,6 @@ DeclResult Sema::CheckClassTemplate(
} }
} }
// TODO Memory management; associated constraints are not always stored.
Expr *const CurAC = formAssociatedConstraints(TemplateParams, nullptr);
if (PrevClassTemplate) { if (PrevClassTemplate) {
// Ensure that the template parameter lists are compatible. Skip this check // Ensure that the template parameter lists are compatible. Skip this check
// for a friend in a dependent context: the template parameter list itself // for a friend in a dependent context: the template parameter list itself
@ -1547,30 +1524,6 @@ DeclResult Sema::CheckClassTemplate(
TPL_TemplateMatch)) TPL_TemplateMatch))
return true; 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: // C++ [temp.class]p4:
// In a redeclaration, partial specialization, explicit // In a redeclaration, partial specialization, explicit
// specialization or explicit instantiation of a class template, // specialization or explicit instantiation of a class template,
@ -1674,15 +1627,10 @@ DeclResult Sema::CheckClassTemplate(
AddMsStructLayoutForRecord(NewClass); 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 *NewTemplate
= ClassTemplateDecl::Create(Context, SemanticContext, NameLoc, = ClassTemplateDecl::Create(Context, SemanticContext, NameLoc,
DeclarationName(Name), TemplateParams, DeclarationName(Name), TemplateParams,
NewClass, ACtoAttach); NewClass);
if (ShouldAddRedecl) if (ShouldAddRedecl)
NewTemplate->setPreviousDecl(PrevClassTemplate); NewTemplate->setPreviousDecl(PrevClassTemplate);
@ -7266,6 +7214,9 @@ static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old,
TemplateArgLoc); TemplateArgLoc);
} }
// TODO: Concepts: Match immediately-introduced-constraint for type
// constraints
return true; return true;
} }
@ -7291,6 +7242,15 @@ void DiagnoseTemplateParameterListArityMismatch(Sema &S,
<< SourceRange(Old->getTemplateLoc(), Old->getRAngleLoc()); << 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 /// Determine whether the given template parameter lists are
/// equivalent. /// equivalent.
/// ///
@ -7380,6 +7340,27 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
return false; 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; return true;
} }
@ -8089,10 +8070,9 @@ Decl *Sema::ActOnConceptDefinition(Scope *S,
TemplateParameterLists.front(), TemplateParameterLists.front(),
ConstraintExpr); ConstraintExpr);
if (NewDecl->getAssociatedConstraints()) { if (NewDecl->hasAssociatedConstraints()) {
// C++2a [temp.concept]p4: // C++2a [temp.concept]p4:
// A concept shall not have associated constraints. // 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); Diag(NameLoc, diag::err_concept_no_associated_constraints);
NewDecl->setInvalidDecl(); NewDecl->setInvalidDecl();
} }

View File

@ -3515,14 +3515,21 @@ TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) {
if (Invalid) if (Invalid)
return nullptr; return nullptr;
// Note: we substitute into associated constraints later // FIXME: Concepts: Substitution into requires clause should only happen when
Expr *const UninstantiatedRequiresClause = L->getRequiresClause(); // checking satisfaction.
Expr *InstRequiresClause = nullptr;
if (Expr *E = L->getRequiresClause()) {
ExprResult Res = SemaRef.SubstExpr(E, TemplateArgs);
if (Res.isInvalid() || !Res.isUsable()) {
return nullptr;
}
InstRequiresClause = Res.get();
}
TemplateParameterList *InstL TemplateParameterList *InstL
= TemplateParameterList::Create(SemaRef.Context, L->getTemplateLoc(), = TemplateParameterList::Create(SemaRef.Context, L->getTemplateLoc(),
L->getLAngleLoc(), Params, L->getLAngleLoc(), Params,
L->getRAngleLoc(), L->getRAngleLoc(), InstRequiresClause);
UninstantiatedRequiresClause);
return InstL; return InstL;
} }

View File

@ -9345,9 +9345,11 @@ ASTReader::ReadTemplateParameterList(ModuleFile &F,
while (NumParams--) while (NumParams--)
Params.push_back(ReadDeclAs<NamedDecl>(F, Record, Idx)); Params.push_back(ReadDeclAs<NamedDecl>(F, Record, Idx));
// TODO: Concepts bool HasRequiresClause = Record[Idx++];
Expr *RequiresClause = HasRequiresClause ? ReadExpr(F) : nullptr;
TemplateParameterList *TemplateParams = TemplateParameterList::Create( TemplateParameterList *TemplateParams = TemplateParameterList::Create(
getContext(), TemplateLoc, LAngleLoc, Params, RAngleLoc, nullptr); getContext(), TemplateLoc, LAngleLoc, Params, RAngleLoc, RequiresClause);
return TemplateParams; return TemplateParams;
} }

View File

@ -2000,7 +2000,6 @@ DeclID ASTDeclReader::VisitTemplateDecl(TemplateDecl *D) {
DeclID PatternID = ReadDeclID(); DeclID PatternID = ReadDeclID();
auto *TemplatedDecl = cast_or_null<NamedDecl>(Reader.GetDecl(PatternID)); auto *TemplatedDecl = cast_or_null<NamedDecl>(Reader.GetDecl(PatternID));
TemplateParameterList *TemplateParams = Record.readTemplateParameterList(); TemplateParameterList *TemplateParams = Record.readTemplateParameterList();
// FIXME handle associated constraints
D->init(TemplatedDecl, TemplateParams); D->init(TemplatedDecl, TemplateParams);
return PatternID; return PatternID;
@ -2166,7 +2165,8 @@ void ASTDeclReader::VisitClassTemplatePartialSpecializationDecl(
ClassTemplatePartialSpecializationDecl *D) { ClassTemplatePartialSpecializationDecl *D) {
RedeclarableResult Redecl = VisitClassTemplateSpecializationDeclImpl(D); RedeclarableResult Redecl = VisitClassTemplateSpecializationDeclImpl(D);
D->TemplateParams = Record.readTemplateParameterList(); TemplateParameterList *Params = Record.readTemplateParameterList();
D->TemplateParams = Params;
D->ArgsAsWritten = Record.readASTTemplateArgumentListInfo(); D->ArgsAsWritten = Record.readASTTemplateArgumentListInfo();
// These are read/set from/to the first declaration. // These are read/set from/to the first declaration.
@ -2268,7 +2268,8 @@ void ASTDeclReader::VisitVarTemplatePartialSpecializationDecl(
VarTemplatePartialSpecializationDecl *D) { VarTemplatePartialSpecializationDecl *D) {
RedeclarableResult Redecl = VisitVarTemplateSpecializationDeclImpl(D); RedeclarableResult Redecl = VisitVarTemplateSpecializationDeclImpl(D);
D->TemplateParams = Record.readTemplateParameterList(); TemplateParameterList *Params = Record.readTemplateParameterList();
D->TemplateParams = Params;
D->ArgsAsWritten = Record.readASTTemplateArgumentListInfo(); D->ArgsAsWritten = Record.readASTTemplateArgumentListInfo();
// These are read/set from/to the first declaration. // These are read/set from/to the first declaration.
@ -2284,6 +2285,7 @@ void ASTDeclReader::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
D->setDeclaredWithTypename(Record.readInt()); D->setDeclaredWithTypename(Record.readInt());
// TODO: Concepts: Immediately introduced constraint
if (Record.readInt()) if (Record.readInt())
D->setDefaultArgument(GetTypeSourceInfo()); D->setDefaultArgument(GetTypeSourceInfo());
} }

View File

@ -6070,10 +6070,16 @@ void ASTRecordWriter::AddTemplateParameterList(
AddSourceLocation(TemplateParams->getTemplateLoc()); AddSourceLocation(TemplateParams->getTemplateLoc());
AddSourceLocation(TemplateParams->getLAngleLoc()); AddSourceLocation(TemplateParams->getLAngleLoc());
AddSourceLocation(TemplateParams->getRAngleLoc()); AddSourceLocation(TemplateParams->getRAngleLoc());
// TODO: Concepts
Record->push_back(TemplateParams->size()); Record->push_back(TemplateParams->size());
for (const auto &P : *TemplateParams) for (const auto &P : *TemplateParams)
AddDeclRef(P); AddDeclRef(P);
if (const Expr *RequiresClause = TemplateParams->getRequiresClause()) {
Record->push_back(true);
AddStmt(const_cast<Expr*>(RequiresClause));
} else {
Record->push_back(false);
}
} }
/// Emit a template argument list. /// Emit a template argument list.

View File

@ -1608,7 +1608,7 @@ void ASTDeclWriter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
VisitTypeDecl(D); VisitTypeDecl(D);
Record.push_back(D->wasDeclaredWithTypename()); Record.push_back(D->wasDeclaredWithTypename());
// TODO: Concepts - constrained parameters.
bool OwnsDefaultArg = D->hasDefaultArgument() && bool OwnsDefaultArg = D->hasDefaultArgument() &&
!D->defaultArgumentWasInherited(); !D->defaultArgumentWasInherited();
Record.push_back(OwnsDefaultArg); Record.push_back(OwnsDefaultArg);
@ -1638,6 +1638,7 @@ void ASTDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
Code = serialization::DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK; Code = serialization::DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK;
} else { } else {
// TODO: Concepts - constrained parameters.
// Rest of NonTypeTemplateParmDecl. // Rest of NonTypeTemplateParmDecl.
Record.push_back(D->isParameterPack()); Record.push_back(D->isParameterPack());
bool OwnsDefaultArg = D->hasDefaultArgument() && bool OwnsDefaultArg = D->hasDefaultArgument() &&
@ -1667,6 +1668,7 @@ void ASTDeclWriter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
Record.AddTemplateParameterList(D->getExpansionTemplateParameters(I)); Record.AddTemplateParameterList(D->getExpansionTemplateParameters(I));
Code = serialization::DECL_EXPANDED_TEMPLATE_TEMPLATE_PARM_PACK; Code = serialization::DECL_EXPANDED_TEMPLATE_TEMPLATE_PARM_PACK;
} else { } else {
// TODO: Concepts - constrained parameters.
// Rest of TemplateTemplateParmDecl. // Rest of TemplateTemplateParmDecl.
Record.push_back(D->isParameterPack()); Record.push_back(D->isParameterPack());
bool OwnsDefaultArg = D->hasDefaultArgument() && bool OwnsDefaultArg = D->hasDefaultArgument() &&

View File

@ -0,0 +1,6 @@
// RUN: %clang_cc1 -std=c++2a -verify %s
template<typename T> requires true
concept C = true; // expected-error{{concept cannot have associated constraints}}
// TODO: Add test for other kinds of associated constraints once we have them.

View File

@ -1,4 +1,4 @@
// RUN: %clang_cc1 -std=c++14 -fconcepts-ts -x c++ -verify %s // RUN: %clang_cc1 -std=c++2a -x c++ -verify %s
namespace nodiag { namespace nodiag {
@ -13,15 +13,15 @@ namespace diag {
template <typename T> requires true // expected-note{{previous template declaration is here}} template <typename T> requires true // expected-note{{previous template declaration is here}}
struct A; struct A;
template <typename T> struct A; // expected-error{{associated constraints differ in template redeclaration}} template <typename T> struct A; // expected-error{{requires clause differs in template redeclaration}}
template <typename T> struct B; // expected-note{{previous template declaration is here}} template <typename T> struct B; // expected-note{{previous template declaration is here}}
template <typename T> requires true // expected-error{{associated constraints differ in template redeclaration}} template <typename T> requires true // expected-error{{requires clause differs in template redeclaration}}
struct B; struct B;
template <typename T> requires true // expected-note{{previous template declaration is here}} template <typename T> requires true // expected-note{{previous template declaration is here}}
struct C; struct C;
template <typename T> requires !0 // expected-error{{associated constraints differ in template redeclaration}} template <typename T> requires !0 // expected-error{{requires clause differs in template redeclaration}}
struct C; struct C;
} // end namespace diag } // end namespace diag
@ -33,7 +33,7 @@ struct AA {
struct A; struct A;
}; };
template <typename T> requires someFunc(T()) template <typename U> requires someFunc(U())
struct AA::A { }; struct AA::A { };
struct AAF { struct AAF {
@ -47,18 +47,26 @@ namespace diag {
template <unsigned N> template <unsigned N>
struct TA { struct TA {
template <template <unsigned> class TT> requires TT<N>::happy // expected-note 2{{previous template declaration is here}} template <template <unsigned> class TT> requires TT<N>::happy // expected-note {{previous template declaration is here}}
struct A; struct A;
template <template <unsigned> class TT> requires TT<N>::happy // expected-note {{previous template declaration is here}}
struct B;
struct AF; struct AF;
}; };
template <unsigned N> template <unsigned N>
template <template <unsigned> class TT> struct TA<N>::A { }; // expected-error{{associated constraints differ in template redeclaration}} template <template <unsigned> class TT> struct TA<N>::A { }; // expected-error{{requires clause differs in template redeclaration}}
template <unsigned N>
template <template <unsigned> class TT> requires TT<N + 1>::happy struct TA<N>::B { }; // expected-error{{requires clause differs in template redeclaration}}
template <unsigned N> template <unsigned N>
struct TA<N>::AF { struct TA<N>::AF {
template <template <unsigned> class TT> requires TT<N + 0>::happy // expected-error{{associated constraints differ in template redeclaration}} // we do not expect a diagnostic here because the template parameter list is dependent.
template <template <unsigned> class TT> requires TT<N + 0>::happy
friend struct TA::A; friend struct TA::A;
}; };

View File

@ -0,0 +1,59 @@
// RUN: %clang_cc1 -std=c++2a -x c++ -verify %s
namespace nodiag {
template <typename T> requires bool(T())
int A();
template <typename U> requires bool(U())
int A();
} // end namespace nodiag
namespace diag {
namespace orig {
template <typename T> requires true
int A();
template <typename T>
int B();
template <typename T> requires true
int C();
}
template <typename T>
int orig::A();
// expected-error@-1{{out-of-line declaration of 'A' does not match any declaration in namespace 'diag::orig'}}
template <typename T> requires true
int orig::B();
// expected-error@-1{{out-of-line declaration of 'B' does not match any declaration in namespace 'diag::orig'}}
template <typename T> requires !0
int orig::C();
// expected-error@-1{{out-of-line declaration of 'C' does not match any declaration in namespace 'diag::orig'}}
} // end namespace diag
namespace nodiag {
struct AA {
template <typename T> requires someFunc(T())
int A();
};
template <typename T> requires someFunc(T())
int AA::A() { return sizeof(T); }
} // end namespace nodiag
namespace diag {
template <unsigned N>
struct TA {
template <template <unsigned> class TT> requires TT<N>::happy
int A();
};
template <unsigned N>
template <template <unsigned> class TT> int TA<N>::A() { return sizeof(TT<N>); }
// expected-error@-1{{out-of-line definition of 'A' does not match any declaration in 'TA<N>'}}
} // end namespace diag

View File

@ -0,0 +1,25 @@
// RUN: %clang_cc1 -std=c++2a -x c++ -verify %s
namespace nodiag {
struct B {
template <typename T> requires bool(T())
static int A;
};
template <typename U> requires bool(U())
int B::A = int(U());
} // end namespace nodiag
namespace diag {
struct B {
template <typename T> requires bool(T()) // expected-note{{previous template declaration is here}}
static int A;
};
template <typename U> requires !bool(U()) // expected-error{{requires clause differs in template redeclaration}}
int B::A = int(U());
} // end namespace diag