summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/DeclTemplate.h116
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td3
-rw-r--r--lib/AST/DeclTemplate.cpp14
-rw-r--r--lib/Sema/SemaTemplate.cpp53
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp1
-rw-r--r--test/CXX/concepts-ts/temp/temp.constr/temp.constr.decl/class-template-decl.cpp65
6 files changed, 231 insertions, 21 deletions
diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h
index 761d3cedc7..1d9045aac3 100644
--- a/include/clang/AST/DeclTemplate.h
+++ b/include/clang/AST/DeclTemplate.h
@@ -344,6 +344,32 @@ public:
// Kinds of Templates
//===----------------------------------------------------------------------===//
+/// \brief Stores the template parameter list and associated constraints for
+/// \c TemplateDecl objects that track associated constraints.
+class ConstrainedTemplateDeclInfo {
+ friend TemplateDecl;
+
+public:
+ ConstrainedTemplateDeclInfo() : TemplateParams(), AssociatedConstraints() {}
+
+ 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;
+ Expr *AssociatedConstraints;
+};
+
+
/// \brief The base class of all kinds of template declarations (e.g.,
/// class, function, etc.).
///
@@ -352,33 +378,53 @@ public:
class TemplateDecl : public NamedDecl {
void anchor() override;
protected:
- // This is probably never used.
- TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name)
+ // 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, false),
- TemplateParams(nullptr) {}
+ TemplateParams(CTDI) {
+ this->setTemplateParameters(Params);
+ }
- // Construct a template decl with the given name and parameters.
- // Used when there is not templated element (tt-params).
TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name,
TemplateParameterList *Params)
- : NamedDecl(DK, DC, L, Name), TemplatedDecl(nullptr, false),
- TemplateParams(Params) {}
+ : TemplateDecl(nullptr, DK, DC, L, Name, Params) {}
// Construct a template decl with name, parameters, and templated element.
- TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name,
+ TemplateDecl(ConstrainedTemplateDeclInfo *CTDI, Kind DK, DeclContext *DC,
+ SourceLocation L, DeclarationName Name,
TemplateParameterList *Params, NamedDecl *Decl)
: NamedDecl(DK, DC, L, Name), TemplatedDecl(Decl, false),
- TemplateParams(Params) {}
+ 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:
/// Get the list of template parameters
TemplateParameterList *getTemplateParameters() const {
- return TemplateParams;
+ const auto *const CTDI =
+ TemplateParams.dyn_cast<ConstrainedTemplateDeclInfo *>();
+ return CTDI ? CTDI->getTemplateParameters()
+ : TemplateParams.get<TemplateParameterList *>();
}
/// Get the constraint-expression from the associated requires-clause (if any)
const Expr *getRequiresClause() const {
- return TemplateParams ? TemplateParams->getRequiresClause() : nullptr;
+ const TemplateParameterList *const TP = getTemplateParameters();
+ return TP ? TP->getRequiresClause() : nullptr;
+ }
+
+ Expr *getAssociatedConstraints() const {
+ const TemplateDecl *const C = cast<TemplateDecl>(getCanonicalDecl());
+ const auto *const CTDI =
+ C->TemplateParams.dyn_cast<ConstrainedTemplateDeclInfo *>();
+ return CTDI ? CTDI->getAssociatedConstraints() : nullptr;
}
/// Get the underlying, templated declaration.
@@ -391,7 +437,7 @@ public:
}
SourceRange getSourceRange() const override LLVM_READONLY {
- return SourceRange(TemplateParams->getTemplateLoc(),
+ return SourceRange(getTemplateParameters()->getTemplateLoc(),
TemplatedDecl.getPointer()->getSourceRange().getEnd());
}
@@ -407,7 +453,29 @@ protected:
/// (function or variable) is a concept.
llvm::PointerIntPair<NamedDecl *, 1, bool> TemplatedDecl;
- TemplateParameterList* TemplateParams;
+ /// \brief 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) {
+ 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);
+ }
public:
/// \brief Initialize the underlying templated declaration and
@@ -737,11 +805,17 @@ 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),
+ Common() {}
+
RedeclarableTemplateDecl(Kind DK, ASTContext &C, DeclContext *DC,
SourceLocation L, DeclarationName Name,
TemplateParameterList *Params, NamedDecl *Decl)
- : TemplateDecl(DK, DC, L, Name, Params, Decl), redeclarable_base(C),
- Common() {}
+ : RedeclarableTemplateDecl(nullptr, DK, C, DC, L, Name, Params, Decl) {}
public:
template <class decl_type> friend class RedeclarableTemplate;
@@ -1997,10 +2071,16 @@ 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)
- : RedeclarableTemplateDecl(ClassTemplate, C, DC, L, Name, Params, Decl) {}
+ : ClassTemplateDecl(nullptr, C, DC, L, Name, Params, Decl) {}
CommonBase *newCommon(ASTContext &C) const override;
@@ -2023,12 +2103,14 @@ public:
return getTemplatedDecl()->isThisDeclarationADefinition();
}
+ // FIXME: remove default argument for AssociatedConstraints
/// \brief Create a class template node.
static ClassTemplateDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
DeclarationName Name,
TemplateParameterList *Params,
- NamedDecl *Decl);
+ NamedDecl *Decl,
+ Expr *AssociatedConstraints = nullptr);
/// \brief Create an empty class template node.
static ClassTemplateDecl *CreateDeserialized(ASTContext &C, unsigned ID);
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index e03bda9c36..fca2b82c58 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2287,6 +2287,9 @@ def err_concept_specialized : Error<
"%select{function|variable}0 concept cannot be "
"%select{explicitly instantiated|explicitly specialized|partially specialized}1">;
+def err_template_different_associated_constraints : Error<
+ "associated constraints differ in template redeclaration">;
+
// C++11 char16_t/char32_t
def warn_cxx98_compat_unicode_type : Warning<
"'%0' type specifier is incompatible with C++98">,
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index a5fbb0a3ba..22f6e18d56 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -297,10 +297,18 @@ ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C,
SourceLocation L,
DeclarationName Name,
TemplateParameterList *Params,
- NamedDecl *Decl) {
+ NamedDecl *Decl,
+ Expr *AssociatedConstraints) {
AdoptTemplateParameterList(Params, cast<DeclContext>(Decl));
- ClassTemplateDecl *New = new (C, DC) ClassTemplateDecl(C, DC, L, Name,
- Params, Decl);
+
+ if (!AssociatedConstraints) {
+ return new (C, DC) ClassTemplateDecl(C, DC, L, Name, Params, Decl);
+ }
+
+ ConstrainedTemplateDeclInfo *const CTDI = new (C) ConstrainedTemplateDeclInfo;
+ ClassTemplateDecl *const New =
+ new (C, DC) ClassTemplateDecl(CTDI, C, DC, L, Name, Params, Decl);
+ New->setAssociatedConstraints(AssociatedConstraints);
return New;
}
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index d0ed17cc49..9d9d1270bf 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -45,6 +45,26 @@ clang::getTemplateParamsRange(TemplateParameterList const * const *Ps,
return SourceRange(Ps[0]->getTemplateLoc(), Ps[N-1]->getRAngleLoc());
}
+namespace clang {
+/// \brief [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();
+}
+
/// \brief Determine whether the declaration found is acceptable as the name
/// of a template and, if so, return that template declaration. Otherwise,
/// returns NULL.
@@ -1137,6 +1157,9 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
}
}
+ // 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
@@ -1148,6 +1171,29 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
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->getLocStart() : NameLoc,
+ diag::err_template_different_associated_constraints);
+ Diag(PrevAC ? PrevAC->getLocStart() : 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,
@@ -1250,10 +1296,15 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
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);
+ NewClass, ACtoAttach);
if (ShouldAddRedecl)
NewTemplate->setPreviousDecl(PrevClassTemplate);
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index 5638cdfde5..6da820f09a 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -1876,6 +1876,7 @@ DeclID ASTDeclReader::VisitTemplateDecl(TemplateDecl *D) {
DeclID PatternID = ReadDeclID();
NamedDecl *TemplatedDecl = cast_or_null<NamedDecl>(Reader.GetDecl(PatternID));
TemplateParameterList *TemplateParams = Record.readTemplateParameterList();
+ // FIXME handle associated constraints
D->init(TemplatedDecl, TemplateParams);
return PatternID;
diff --git a/test/CXX/concepts-ts/temp/temp.constr/temp.constr.decl/class-template-decl.cpp b/test/CXX/concepts-ts/temp/temp.constr/temp.constr.decl/class-template-decl.cpp
new file mode 100644
index 0000000000..d1ad0404ef
--- /dev/null
+++ b/test/CXX/concepts-ts/temp/temp.constr/temp.constr.decl/class-template-decl.cpp
@@ -0,0 +1,65 @@
+// RUN: %clang_cc1 -std=c++14 -fconcepts-ts -x c++ -verify %s
+
+namespace nodiag {
+
+template <typename T> requires bool(T())
+struct A;
+template <typename U> requires bool(U())
+struct A;
+
+} // end namespace nodiag
+
+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 B; // expected-note{{previous template declaration is here}}
+template <typename T> requires true // expected-error{{associated constraints differ 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}}
+struct C;
+
+} // end namespace diag
+
+namespace nodiag {
+
+struct AA {
+ template <typename T> requires someFunc(T())
+ struct A;
+};
+
+template <typename T> requires someFunc(T())
+struct AA::A { };
+
+struct AAF {
+ template <typename T> requires someFunc(T())
+ friend struct AA::A;
+};
+
+} // end namespace nodiag
+
+namespace diag {
+
+template <unsigned N>
+struct TA {
+ template <template <unsigned> class TT> requires TT<N>::happy // expected-note 2{{previous template declaration is here}}
+ struct A;
+
+ struct AF;
+};
+
+template <unsigned N>
+template <template <unsigned> class TT> struct TA<N>::A { }; // expected-error{{associated constraints differ 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}}
+ friend struct TA::A;
+};
+
+} // end namespace diag