hubert.reinterpretcast created this revision.
hubert.reinterpretcast added reviewers: rsmith, faisalv, aaron.ballman.
hubert.reinterpretcast added subscribers: nwilson, cfe-commits.
This adds associated constraints as a property of class templates.
An error is produced if redeclarations are not similarly constrained.
https://reviews.llvm.org/D25674
Files:
include/clang/AST/DeclTemplate.h
include/clang/Basic/DiagnosticSemaKinds.td
lib/AST/DeclTemplate.cpp
lib/Sema/SemaTemplate.cpp
test/CXX/concepts-ts/temp/
test/CXX/concepts-ts/temp/temp.constr/
test/CXX/concepts-ts/temp/temp.constr/temp.constr.decl/
test/CXX/concepts-ts/temp/temp.constr/temp.constr.decl/class-template-decl.cpp
Index: test/CXX/concepts-ts/temp/temp.constr/temp.constr.decl/class-template-decl.cpp
===================================================================
--- /dev/null
+++ test/CXX/concepts-ts/temp/temp.constr/temp.constr.decl/class-template-decl.cpp
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -std=c++14 -fconcepts-ts -x c++ -verify %s
+
+namespace nodiag {
+
+using MyBool = bool;
+
+template <typename T> requires !!sizeof(bool)
+struct A;
+template <typename T> requires !!sizeof(MyBool)
+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
Index: lib/Sema/SemaTemplate.cpp
===================================================================
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -45,6 +45,26 @@
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.
@@ -1117,6 +1137,9 @@
}
}
+ // 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
@@ -1128,6 +1151,26 @@
TPL_TemplateMatch))
return true;
+ // Check for matching associated constraints on redeclarations.
+ do {
+ const Expr *const PrevAC = PrevClassTemplate->getAssociatedConstraints();
+ if (!(CurAC || PrevAC))
+ continue; // nothing to check
+ if (CurAC && PrevAC) {
+ llvm::FoldingSetNodeID CurACInfo, PrevACInfo;
+ CurAC->Profile(CurACInfo, Context, /*Canonical=*/true);
+ PrevAC->Profile(PrevACInfo, Context, /*Canonical=*/true);
+ if (CurACInfo == PrevACInfo)
+ continue; // all good
+ }
+
+ 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;
+ } while (0);
+
// C++ [temp.class]p4:
// In a redeclaration, partial specialization, explicit
// specialization or explicit instantiation of a class template,
@@ -1225,7 +1268,8 @@
ClassTemplateDecl *NewTemplate
= ClassTemplateDecl::Create(Context, SemanticContext, NameLoc,
DeclarationName(Name), TemplateParams,
- NewClass, PrevClassTemplate);
+ NewClass, PrevClassTemplate,
+ PrevClassTemplate ? nullptr : CurAC);
NewClass->setDescribedClassTemplate(NewTemplate);
if (ModulePrivateLoc.isValid())
Index: lib/AST/DeclTemplate.cpp
===================================================================
--- lib/AST/DeclTemplate.cpp
+++ lib/AST/DeclTemplate.cpp
@@ -334,11 +334,20 @@
DeclarationName Name,
TemplateParameterList *Params,
NamedDecl *Decl,
- ClassTemplateDecl *PrevDecl) {
+ ClassTemplateDecl *PrevDecl,
+ Expr *AssociatedConstraints) {
AdoptTemplateParameterList(Params, cast<DeclContext>(Decl));
- ClassTemplateDecl *New = new (C, DC) ClassTemplateDecl(C, DC, L, Name,
- Params, Decl);
+ assert(!(AssociatedConstraints && PrevDecl) &&
+ "Attaching associated constraints to later (not first) declaration");
+ ClassTemplateDecl *New =
+ new (C, DC, ClassTemplateDecl::additionalSizeToAlloc<Expr *>(
+ AssociatedConstraints ? 1u : 0u))
+ ClassTemplateDecl(C, DC, L, Name, Params, Decl);
New->setPreviousDecl(PrevDecl);
+ if (AssociatedConstraints) {
+ New->setStoresAssociatedConstraints();
+ New->storedAssociatedConstraintsField() = AssociatedConstraints;
+ }
return New;
}
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -2178,6 +2178,9 @@
"%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">,
Index: include/clang/AST/DeclTemplate.h
===================================================================
--- include/clang/AST/DeclTemplate.h
+++ include/clang/AST/DeclTemplate.h
@@ -355,30 +355,32 @@
// This is probably never used.
TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name)
: NamedDecl(DK, DC, L, Name), TemplatedDecl(nullptr, false),
- TemplateParams(nullptr) {}
+ TemplateParams(nullptr, false) {}
// 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) {}
+ TemplateParams(Params, false) {}
// Construct a template decl with name, parameters, and templated element.
TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name,
TemplateParameterList *Params, NamedDecl *Decl)
: NamedDecl(DK, DC, L, Name), TemplatedDecl(Decl, false),
- TemplateParams(Params) {}
+ TemplateParams(Params, false) {}
public:
/// Get the list of template parameters
TemplateParameterList *getTemplateParameters() const {
- return TemplateParams;
+ return TemplateParams.getPointer();
}
/// Get the constraint-expression from the associated requires-clause (if any)
const Expr *getRequiresClause() const {
- return TemplateParams ? TemplateParams->getRequiresClause() : nullptr;
+ return TemplateParams.getPointer()
+ ? TemplateParams.getPointer()->getRequiresClause()
+ : nullptr;
}
/// Get the underlying, templated declaration.
@@ -391,7 +393,7 @@
}
SourceRange getSourceRange() const override LLVM_READONLY {
- return SourceRange(TemplateParams->getTemplateLoc(),
+ return SourceRange(TemplateParams.getPointer()->getTemplateLoc(),
TemplatedDecl.getPointer()->getSourceRange().getEnd());
}
@@ -407,16 +409,24 @@
/// (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.
+ ///
+ /// The boolean value indicates whether this particular declaration has an
+ /// attached \c Expr representing the associated constraints of the template.
+ llvm::PointerIntPair<TemplateParameterList *, 1, bool> TemplateParams;
+
+ bool storesAssociatedConstraints() const { return TemplateParams.getInt(); }
+ void setStoresAssociatedConstraints() { TemplateParams.setInt(true); }
public:
/// \brief Initialize the underlying templated declaration and
/// template parameters.
void init(NamedDecl *templatedDecl, TemplateParameterList* templateParams) {
assert(!TemplatedDecl.getPointer() && "TemplatedDecl already set!");
- assert(!TemplateParams && "TemplateParams already set!");
+ assert(!TemplateParams.getPointer() && "TemplateParams already set!");
TemplatedDecl.setPointer(templatedDecl);
- TemplateParams = templateParams;
+ TemplateParams.setPointer(templateParams);
}
};
@@ -1959,7 +1969,10 @@
};
/// Declaration of a class template.
-class ClassTemplateDecl : public RedeclarableTemplateDecl {
+class ClassTemplateDecl final
+ : public RedeclarableTemplateDecl,
+ private llvm::TrailingObjects<ClassTemplateDecl, Expr *> {
+ friend TrailingObjects;
static void DeallocateCommon(void *Ptr);
protected:
@@ -2008,6 +2021,16 @@
return static_cast<Common *>(RedeclarableTemplateDecl::getCommonPtr());
}
+ Expr *&storedAssociatedConstraintsField() {
+ assert(storesAssociatedConstraints() && "Accessing non-existent field?");
+ return *getTrailingObjects<Expr *>();
+ }
+
+ Expr *storedAssociatedConstraintsField() const {
+ assert(storesAssociatedConstraints() && "Accessing non-existent field?");
+ return *getTrailingObjects<Expr *>();
+ }
+
public:
/// \brief Load any lazily-loaded specializations from the external source.
void LoadLazySpecializations() const;
@@ -2023,13 +2046,23 @@
return getTemplatedDecl()->isThisDeclarationADefinition();
}
+ /// \brief Returns the associated constraints for this template (if any).
+ Expr *getAssociatedConstraints() const {
+ const ClassTemplateDecl *const C = ClassTemplateDecl::getCanonicalDecl();
+ return C->storesAssociatedConstraints()
+ ? C->storedAssociatedConstraintsField()
+ : nullptr;
+ }
+
+ // 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,
- ClassTemplateDecl *PrevDecl);
+ ClassTemplateDecl *PrevDecl,
+ Expr *AssociatedConstraints = nullptr);
/// \brief Create an empty class template node.
static ClassTemplateDecl *CreateDeserialized(ASTContext &C, unsigned ID);
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits