summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSaar Raz <saar@raz.email>2019-10-15 18:44:06 +0000
committerSaar Raz <saar@raz.email>2019-10-15 18:44:06 +0000
commitcf4a18c6aa180512c2f9b2a88450492b9c89c3c8 (patch)
treea8f878dad9ce11e042bd5a9388610e90425997f9
parentea4934045aa895f450dae600d12b7f5582915598 (diff)
downloadclang-cf4a18c6aa180512c2f9b2a88450492b9c89c3c8.tar.gz
[Concept] Associated Constraints Infrastructure
Add code to correctly calculate the associated constraints of a template (no enforcement yet). D41284 on Phabricator. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@374938 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/ASTNodeTraverser.h3
-rw-r--r--include/clang/AST/DeclTemplate.h174
-rw-r--r--include/clang/AST/RecursiveASTVisitor.h8
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td4
-rw-r--r--include/clang/Sema/Sema.h8
-rw-r--r--lib/AST/ASTContext.cpp2
-rw-r--r--lib/AST/DeclTemplate.cpp55
-rw-r--r--lib/Sema/SemaConcept.cpp2
-rw-r--r--lib/Sema/SemaTemplate.cpp92
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp15
-rw-r--r--lib/Serialization/ASTReader.cpp6
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp8
-rw-r--r--lib/Serialization/ASTWriter.cpp8
-rw-r--r--lib/Serialization/ASTWriterDecl.cpp4
-rw-r--r--test/CXX/temp/concept/p4.cpp6
-rw-r--r--test/CXX/temp/temp.constr/temp.constr.decl/class-template-decl.cpp24
-rw-r--r--test/CXX/temp/temp.constr/temp.constr.decl/func-template-decl.cpp59
-rw-r--r--test/CXX/temp/temp.constr/temp.constr.decl/var-template-decl.cpp25
18 files changed, 293 insertions, 210 deletions
diff --git a/include/clang/AST/ASTNodeTraverser.h b/include/clang/AST/ASTNodeTraverser.h
index e43eacef86..0bb2aad553 100644
--- a/include/clang/AST/ASTNodeTraverser.h
+++ b/include/clang/AST/ASTNodeTraverser.h
@@ -237,6 +237,9 @@ public:
for (const auto &TP : *TPL)
Visit(TP);
+
+ if (const Expr *RC = TPL->getRequiresClause())
+ Visit(RC);
}
void
diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h
index cb04e78b3d..ec14adc7de 100644
--- a/include/clang/AST/DeclTemplate.h
+++ b/include/clang/AST/DeclTemplate.h
@@ -168,6 +168,16 @@ public:
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 getLAngleLoc() const { return LAngleLoc; }
SourceLocation getRAngleLoc() const { return RAngleLoc; }
@@ -369,33 +379,7 @@ public:
// Kinds of Templates
//===----------------------------------------------------------------------===//
-/// Stores the template parameter list and associated constraints for
-/// \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.,
+/// \brief The base class of all kinds of template declarations (e.g.,
/// class, function, etc.).
///
/// The TemplateDecl class stores the list of template parameters and a
@@ -404,54 +388,32 @@ class TemplateDecl : public NamedDecl {
void anchor() override;
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.
// 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,
TemplateParameterList *Params)
- : TemplateDecl(nullptr, DK, DC, L, Name, Params) {}
-
- // 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) {}
+ : TemplateDecl(DK, DC, L, Name, Params, nullptr) {}
public:
+ friend class ASTDeclReader;
+ friend class ASTDeclWriter;
+
/// Get the list of template parameters
TemplateParameterList *getTemplateParameters() const {
- const auto *const CTDI =
- TemplateParams.dyn_cast<ConstrainedTemplateDeclInfo *>();
- return CTDI ? CTDI->getTemplateParameters()
- : TemplateParams.get<TemplateParameterList *>();
+ return TemplateParams;
}
- /// Get the constraint-expression from the associated requires-clause (if any)
- const Expr *getRequiresClause() const {
- const TemplateParameterList *const TP = getTemplateParameters();
- return TP ? TP->getRequiresClause() : nullptr;
- }
+ /// \brief Get the total constraint-expression associated with this template,
+ /// including constraint-expressions derived from the requires-clause,
+ /// trailing requires-clause (for functions and methods) and constrained
+ /// template parameters.
+ void getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const;
- Expr *getAssociatedConstraints() const {
- const auto *const C = cast<TemplateDecl>(getCanonicalDecl());
- const auto *const CTDI =
- C->TemplateParams.dyn_cast<ConstrainedTemplateDeclInfo *>();
- return CTDI ? CTDI->getAssociatedConstraints() : nullptr;
- }
+ bool hasAssociatedConstraints() const;
/// Get the underlying, templated declaration.
NamedDecl *getTemplatedDecl() const { return TemplatedDecl; }
@@ -470,29 +432,10 @@ public:
protected:
NamedDecl *TemplatedDecl;
-
- /// 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;
+ TemplateParameterList *TemplateParams;
void setTemplateParameters(TemplateParameterList *TParams) {
- if (auto *const CTDI =
- TemplateParams.dyn_cast<ConstrainedTemplateDeclInfo *>()) {
- CTDI->setTemplateParameters(TParams);
- } else {
- TemplateParams = TParams;
- }
- }
-
- void setAssociatedConstraints(Expr *AC) {
- assert(isCanonicalDecl() &&
- "Attaching associated constraints to non-canonical Decl");
- TemplateParams.get<ConstrainedTemplateDeclInfo *>()
- ->setAssociatedConstraints(AC);
+ TemplateParams = TParams;
}
public:
@@ -889,17 +832,10 @@ protected:
virtual CommonBase *newCommon(ASTContext &C) const = 0;
// 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,
SourceLocation L, DeclarationName Name,
TemplateParameterList *Params, NamedDecl *Decl)
- : RedeclarableTemplateDecl(nullptr, DK, C, DC, L, Name, Params, Decl) {}
+ : TemplateDecl(DK, DC, L, Name, Params, Decl), redeclarable_base(C) {}
public:
friend class ASTDeclReader;
@@ -2026,6 +1962,20 @@ public:
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.
const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
return ArgsAsWritten;
@@ -2145,16 +2095,10 @@ protected:
llvm::FoldingSetVector<ClassTemplatePartialSpecializationDecl> &
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,
DeclarationName Name, TemplateParameterList *Params,
NamedDecl *Decl)
- : ClassTemplateDecl(nullptr, C, DC, L, Name, Params, Decl) {}
+ : RedeclarableTemplateDecl(ClassTemplate, C, DC, L, Name, Params, Decl) {}
CommonBase *newCommon(ASTContext &C) const override;
@@ -2180,14 +2124,12 @@ public:
return getTemplatedDecl()->isThisDeclarationADefinition();
}
- // FIXME: remove default argument for AssociatedConstraints
- /// Create a class template node.
+ /// \brief Create a class template node.
static ClassTemplateDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
DeclarationName Name,
TemplateParameterList *Params,
- NamedDecl *Decl,
- Expr *AssociatedConstraints = nullptr);
+ NamedDecl *Decl);
/// Create an empty class template node.
static ClassTemplateDecl *CreateDeserialized(ASTContext &C, unsigned ID);
@@ -2862,7 +2804,21 @@ public:
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
/// instantiated.
///
@@ -3091,11 +3047,9 @@ class ConceptDecl : public TemplateDecl, public Mergeable<ConceptDecl> {
protected:
Expr *ConstraintExpr;
- ConceptDecl(DeclContext *DC,
- SourceLocation L, DeclarationName Name,
- TemplateParameterList *Params,
- Expr *ConstraintExpr)
- : TemplateDecl(nullptr, Concept, DC, L, Name, Params),
+ ConceptDecl(DeclContext *DC, SourceLocation L, DeclarationName Name,
+ TemplateParameterList *Params, Expr *ConstraintExpr)
+ : TemplateDecl(Concept, DC, L, Name, Params),
ConstraintExpr(ConstraintExpr) {};
public:
static ConceptDecl *Create(ASTContext &C, DeclContext *DC,
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index 998cf9238c..3a21034057 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -1633,9 +1633,11 @@ template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseTemplateParameterListHelper(
TemplateParameterList *TPL) {
if (TPL) {
- for (TemplateParameterList::iterator I = TPL->begin(), E = TPL->end();
- I != E; ++I) {
- TRY_TO(TraverseDecl(*I));
+ for (NamedDecl *D : *TPL) {
+ TRY_TO(TraverseDecl(D));
+ }
+ if (Expr *RequiresClause = TPL->getRequiresClause()) {
+ TRY_TO(TraverseStmt(RequiresClause));
}
}
return true;
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 968c2dbd56..755fac842d 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2543,8 +2543,8 @@ def err_non_constant_constraint_expression : Error<
def err_non_bool_atomic_constraint : Error<
"atomic constraint must be of type 'bool' (found %0)">;
-def err_template_different_associated_constraints : Error<
- "associated constraints differ in template redeclaration">;
+def err_template_different_requires_clause : Error<
+ "requires clause differs in template redeclaration">;
// C++11 char16_t/char32_t
def warn_cxx98_compat_unicode_type : Warning<
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 7c93d40952..d2798eaf65 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -6058,7 +6058,13 @@ public:
Expr *ConstraintExpr,
bool &IsSatisfied);
- // ParseObjCStringLiteral - Parse Objective-C string literals.
+ /// 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.
ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs,
ArrayRef<Expr *> Strings);
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index cd6ea7f1f9..1a3bde00ee 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -738,7 +738,7 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
cast<TemplateTemplateParmDecl>(*P)));
}
- assert(!TTP->getRequiresClause() &&
+ assert(!TTP->getTemplateParameters()->getRequiresClause() &&
"Unexpected requires-clause on template template-parameter");
Expr *const CanonRequiresClause = nullptr;
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index ccfc292e4c..7e013c6c54 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -70,6 +70,8 @@ TemplateParameterList::TemplateParameterList(SourceLocation TemplateLoc,
}
if (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 {
void *allocateDefaultArgStorageChain(const ASTContext &C) {
@@ -145,6 +159,28 @@ void *allocateDefaultArgStorageChain(const ASTContext &C) {
} // 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
//===----------------------------------------------------------------------===//
@@ -344,19 +380,10 @@ ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C,
SourceLocation L,
DeclarationName Name,
TemplateParameterList *Params,
- NamedDecl *Decl,
- Expr *AssociatedConstraints) {
+ NamedDecl *Decl) {
AdoptTemplateParameterList(Params, cast<DeclContext>(Decl));
- if (!AssociatedConstraints) {
- 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;
+ return new (C, DC) ClassTemplateDecl(C, DC, L, Name, Params, Decl);
}
ClassTemplateDecl *ClassTemplateDecl::CreateDeserialized(ASTContext &C,
@@ -708,12 +735,6 @@ FunctionTemplateSpecializationInfo *FunctionTemplateSpecializationInfo::Create(
}
//===----------------------------------------------------------------------===//
-// TemplateDecl Implementation
-//===----------------------------------------------------------------------===//
-
-void TemplateDecl::anchor() {}
-
-//===----------------------------------------------------------------------===//
// ClassTemplateSpecializationDecl Implementation
//===----------------------------------------------------------------------===//
diff --git a/lib/Sema/SemaConcept.cpp b/lib/Sema/SemaConcept.cpp
index 3131609390..848ccf5434 100644
--- a/lib/Sema/SemaConcept.cpp
+++ b/lib/Sema/SemaConcept.cpp
@@ -122,4 +122,4 @@ Sema::CalculateConstraintSatisfaction(ConceptDecl *NamedConcept,
IsSatisfied = EvalResult.Val.getInt().getBoolValue();
return false;
-}
+} \ No newline at end of file
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index cb756eb30f..2871511466 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -45,27 +45,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.
///
@@ -1533,9 +1513,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
@@ -1547,30 +1524,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,
@@ -1674,15 +1627,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);
@@ -7266,6 +7214,9 @@ static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old,
TemplateArgLoc);
}
+ // TODO: Concepts: Match immediately-introduced-constraint for type
+ // constraints
+
return true;
}
@@ -7291,6 +7242,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.
///
@@ -7380,6 +7340,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;
}
@@ -8089,10 +8070,9 @@ Decl *Sema::ActOnConceptDefinition(Scope *S,
TemplateParameterLists.front(),
ConstraintExpr);
- 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();
}
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 818548cb62..d1ad304e62 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -3515,14 +3515,21 @@ TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) {
if (Invalid)
return nullptr;
- // Note: we substitute into associated constraints later
- Expr *const UninstantiatedRequiresClause = L->getRequiresClause();
+ // FIXME: Concepts: Substitution into requires clause should only happen when
+ // 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::Create(SemaRef.Context, L->getTemplateLoc(),
L->getLAngleLoc(), Params,
- L->getRAngleLoc(),
- UninstantiatedRequiresClause);
+ L->getRAngleLoc(), InstRequiresClause);
return InstL;
}
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index 20c6cbec57..d8790768cb 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -9345,9 +9345,11 @@ ASTReader::ReadTemplateParameterList(ModuleFile &F,
while (NumParams--)
Params.push_back(ReadDeclAs<NamedDecl>(F, Record, Idx));
- // TODO: Concepts
+ bool HasRequiresClause = Record[Idx++];
+ Expr *RequiresClause = HasRequiresClause ? ReadExpr(F) : nullptr;
+
TemplateParameterList *TemplateParams = TemplateParameterList::Create(
- getContext(), TemplateLoc, LAngleLoc, Params, RAngleLoc, nullptr);
+ getContext(), TemplateLoc, LAngleLoc, Params, RAngleLoc, RequiresClause);
return TemplateParams;
}
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index d906286db5..65d62524e2 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -2000,7 +2000,6 @@ DeclID ASTDeclReader::VisitTemplateDecl(TemplateDecl *D) {
DeclID PatternID = ReadDeclID();
auto *TemplatedDecl = cast_or_null<NamedDecl>(Reader.GetDecl(PatternID));
TemplateParameterList *TemplateParams = Record.readTemplateParameterList();
- // FIXME handle associated constraints
D->init(TemplatedDecl, TemplateParams);
return PatternID;
@@ -2166,7 +2165,8 @@ void ASTDeclReader::VisitClassTemplatePartialSpecializationDecl(
ClassTemplatePartialSpecializationDecl *D) {
RedeclarableResult Redecl = VisitClassTemplateSpecializationDeclImpl(D);
- D->TemplateParams = Record.readTemplateParameterList();
+ TemplateParameterList *Params = Record.readTemplateParameterList();
+ D->TemplateParams = Params;
D->ArgsAsWritten = Record.readASTTemplateArgumentListInfo();
// These are read/set from/to the first declaration.
@@ -2268,7 +2268,8 @@ void ASTDeclReader::VisitVarTemplatePartialSpecializationDecl(
VarTemplatePartialSpecializationDecl *D) {
RedeclarableResult Redecl = VisitVarTemplateSpecializationDeclImpl(D);
- D->TemplateParams = Record.readTemplateParameterList();
+ TemplateParameterList *Params = Record.readTemplateParameterList();
+ D->TemplateParams = Params;
D->ArgsAsWritten = Record.readASTTemplateArgumentListInfo();
// These are read/set from/to the first declaration.
@@ -2284,6 +2285,7 @@ void ASTDeclReader::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
D->setDeclaredWithTypename(Record.readInt());
+ // TODO: Concepts: Immediately introduced constraint
if (Record.readInt())
D->setDefaultArgument(GetTypeSourceInfo());
}
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index 5e9e650fce..aef3523116 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -6070,10 +6070,16 @@ void ASTRecordWriter::AddTemplateParameterList(
AddSourceLocation(TemplateParams->getTemplateLoc());
AddSourceLocation(TemplateParams->getLAngleLoc());
AddSourceLocation(TemplateParams->getRAngleLoc());
- // TODO: Concepts
+
Record->push_back(TemplateParams->size());
for (const auto &P : *TemplateParams)
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.
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index 2c22587957..039b57f88e 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -1608,7 +1608,7 @@ void ASTDeclWriter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
VisitTypeDecl(D);
Record.push_back(D->wasDeclaredWithTypename());
-
+ // TODO: Concepts - constrained parameters.
bool OwnsDefaultArg = D->hasDefaultArgument() &&
!D->defaultArgumentWasInherited();
Record.push_back(OwnsDefaultArg);
@@ -1638,6 +1638,7 @@ void ASTDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
Code = serialization::DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK;
} else {
+ // TODO: Concepts - constrained parameters.
// Rest of NonTypeTemplateParmDecl.
Record.push_back(D->isParameterPack());
bool OwnsDefaultArg = D->hasDefaultArgument() &&
@@ -1667,6 +1668,7 @@ void ASTDeclWriter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
Record.AddTemplateParameterList(D->getExpansionTemplateParameters(I));
Code = serialization::DECL_EXPANDED_TEMPLATE_TEMPLATE_PARM_PACK;
} else {
+ // TODO: Concepts - constrained parameters.
// Rest of TemplateTemplateParmDecl.
Record.push_back(D->isParameterPack());
bool OwnsDefaultArg = D->hasDefaultArgument() &&
diff --git a/test/CXX/temp/concept/p4.cpp b/test/CXX/temp/concept/p4.cpp
new file mode 100644
index 0000000000..2e0226779f
--- /dev/null
+++ b/test/CXX/temp/concept/p4.cpp
@@ -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.
diff --git a/test/CXX/temp/temp.constr/temp.constr.decl/class-template-decl.cpp b/test/CXX/temp/temp.constr/temp.constr.decl/class-template-decl.cpp
index d1ad0404ef..5d5361f9c2 100644
--- a/test/CXX/temp/temp.constr/temp.constr.decl/class-template-decl.cpp
+++ b/test/CXX/temp/temp.constr/temp.constr.decl/class-template-decl.cpp
@@ -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 {
@@ -13,15 +13,15 @@ namespace diag {
template <typename T> requires true // expected-note{{previous template declaration is here}}
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> 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;
template <typename T> requires true // expected-note{{previous template declaration is here}}
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;
} // end namespace diag
@@ -33,7 +33,7 @@ struct AA {
struct A;
};
-template <typename T> requires someFunc(T())
+template <typename U> requires someFunc(U())
struct AA::A { };
struct AAF {
@@ -47,18 +47,26 @@ namespace diag {
template <unsigned N>
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;
+ template <template <unsigned> class TT> requires TT<N>::happy // expected-note {{previous template declaration is here}}
+ struct B;
+
struct AF;
};
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>
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;
};
diff --git a/test/CXX/temp/temp.constr/temp.constr.decl/func-template-decl.cpp b/test/CXX/temp/temp.constr/temp.constr.decl/func-template-decl.cpp
new file mode 100644
index 0000000000..c83ab26059
--- /dev/null
+++ b/test/CXX/temp/temp.constr/temp.constr.decl/func-template-decl.cpp
@@ -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
diff --git a/test/CXX/temp/temp.constr/temp.constr.decl/var-template-decl.cpp b/test/CXX/temp/temp.constr/temp.constr.decl/var-template-decl.cpp
new file mode 100644
index 0000000000..cf6874f12d
--- /dev/null
+++ b/test/CXX/temp/temp.constr/temp.constr.decl/var-template-decl.cpp
@@ -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 \ No newline at end of file