r294697 - [Concepts] Class template associated constraints

Hubert Tong via cfe-commits cfe-commits at lists.llvm.org
Thu Feb 9 18:46:19 PST 2017


Author: hubert.reinterpretcast
Date: Thu Feb  9 20:46:19 2017
New Revision: 294697

URL: http://llvm.org/viewvc/llvm-project?rev=294697&view=rev
Log:
[Concepts] Class template associated constraints

Summary:
This adds associated constraints as a property of class templates.
An error is produced if redeclarations are not similarly constrained.

Reviewers: rsmith, faisalv, aaron.ballman

Reviewed By: rsmith

Subscribers: cfe-commits, nwilson

Differential Revision: https://reviews.llvm.org/D25674

Added:
    cfe/trunk/test/CXX/concepts-ts/temp/
    cfe/trunk/test/CXX/concepts-ts/temp/temp.constr/
    cfe/trunk/test/CXX/concepts-ts/temp/temp.constr/temp.constr.decl/
    cfe/trunk/test/CXX/concepts-ts/temp/temp.constr/temp.constr.decl/class-template-decl.cpp
Modified:
    cfe/trunk/include/clang/AST/DeclTemplate.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/AST/DeclTemplate.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/lib/Serialization/ASTReaderDecl.cpp

Modified: cfe/trunk/include/clang/AST/DeclTemplate.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclTemplate.h?rev=294697&r1=294696&r2=294697&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclTemplate.h (original)
+++ cfe/trunk/include/clang/AST/DeclTemplate.h Thu Feb  9 20:46:19 2017
@@ -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);

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=294697&r1=294696&r2=294697&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Feb  9 20:46:19 2017
@@ -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">,

Modified: cfe/trunk/lib/AST/DeclTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclTemplate.cpp?rev=294697&r1=294696&r2=294697&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclTemplate.cpp (original)
+++ cfe/trunk/lib/AST/DeclTemplate.cpp Thu Feb  9 20:46:19 2017
@@ -297,10 +297,18 @@ ClassTemplateDecl *ClassTemplateDecl::Cr
                                              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;
 }
 

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=294697&r1=294696&r2=294697&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Thu Feb  9 20:46:19 2017
@@ -45,6 +45,26 @@ clang::getTemplateParamsRange(TemplatePa
   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, unsig
     }
   }
 
+  // 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, unsig
                                         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, unsig
     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);

Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=294697&r1=294696&r2=294697&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Thu Feb  9 20:46:19 2017
@@ -1876,6 +1876,7 @@ DeclID ASTDeclReader::VisitTemplateDecl(
   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;

Added: cfe/trunk/test/CXX/concepts-ts/temp/temp.constr/temp.constr.decl/class-template-decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/concepts-ts/temp/temp.constr/temp.constr.decl/class-template-decl.cpp?rev=294697&view=auto
==============================================================================
--- cfe/trunk/test/CXX/concepts-ts/temp/temp.constr/temp.constr.decl/class-template-decl.cpp (added)
+++ cfe/trunk/test/CXX/concepts-ts/temp/temp.constr/temp.constr.decl/class-template-decl.cpp Thu Feb  9 20:46:19 2017
@@ -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




More information about the cfe-commits mailing list