]> granicus.if.org Git - clang/commitdiff
PR13051: If a constructor is explicitly defaulted, it isn't marked as being
authorRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 8 Jun 2012 21:09:22 +0000 (21:09 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 8 Jun 2012 21:09:22 +0000 (21:09 +0000)
constexpr until we get to the end of the class definition. When that happens,
be sure to remember that the class actually does have a constexpr constructor.

This is a stopgap solution, which still doesn't cover the case of a class with
multiple copy constructors (only some of which are constexpr). We should be
performing constructor lookup when implicitly defining a constructor in order
to determine whether all constructors it invokes are constexpr.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@158228 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/Decl.h
include/clang/AST/DeclCXX.h
lib/AST/Decl.cpp
lib/AST/DeclCXX.cpp
test/CXX/special/class.copy/p13-0x.cpp
test/CXX/special/class.copy/p8-cxx11.cpp

index 8ec69b43f09719d4f145e6ad6e90be90cefa25e5..a7bf599636f3b113cccade0b66f1b2bf44a6e61d 100644 (file)
@@ -1183,7 +1183,7 @@ public:
   bool isARCPseudoStrong() const { return VarDeclBits.ARCPseudoStrong; }
   void setARCPseudoStrong(bool ps) { VarDeclBits.ARCPseudoStrong = ps; }
 
-  /// Whether this variable is (C++0x) constexpr.
+  /// Whether this variable is (C++11) constexpr.
   bool isConstexpr() const { return VarDeclBits.IsConstexpr; }
   void setConstexpr(bool IC) { VarDeclBits.IsConstexpr = IC; }
 
@@ -1736,9 +1736,9 @@ public:
   bool hasInheritedPrototype() const { return HasInheritedPrototype; }
   void setHasInheritedPrototype(bool P = true) { HasInheritedPrototype = P; }
 
-  /// Whether this is a (C++0x) constexpr function or constexpr constructor.
+  /// Whether this is a (C++11) constexpr function or constexpr constructor.
   bool isConstexpr() const { return IsConstexpr; }
-  void setConstexpr(bool IC) { IsConstexpr = IC; }
+  void setConstexpr(bool IC);
 
   /// \brief Whether this function has been deleted.
   ///
index 6b44f777bb96a81181aebacf28bbe45748f5cd53..21e8a98bef304a146bd258a00ee040ce8d3c9b74 100644 (file)
@@ -650,6 +650,9 @@ class CXXRecordDecl : public RecordDecl {
   void markedVirtualFunctionPure();
   friend void FunctionDecl::setPure(bool);
 
+  void markedConstructorConstexpr(CXXConstructorDecl *CD);
+  friend void FunctionDecl::setConstexpr(bool);
+
   friend class ASTNodeImporter;
 
 protected:
@@ -1119,7 +1122,7 @@ public:
   bool hasConstexprDefaultConstructor() const {
     return data().HasConstexprDefaultConstructor ||
            (!data().UserDeclaredConstructor &&
-            defaultedDefaultConstructorIsConstexpr() && isLiteral());
+            defaultedDefaultConstructorIsConstexpr());
   }
 
   /// hasConstexprCopyConstructor - Whether this class has a constexpr copy
@@ -1127,7 +1130,7 @@ public:
   bool hasConstexprCopyConstructor() const {
     return data().HasConstexprCopyConstructor ||
            (!data().DeclaredCopyConstructor &&
-            data().DefaultedCopyConstructorIsConstexpr && isLiteral());
+            data().DefaultedCopyConstructorIsConstexpr);
   }
 
   /// hasConstexprMoveConstructor - Whether this class has a constexpr move
@@ -1135,7 +1138,7 @@ public:
   bool hasConstexprMoveConstructor() const {
     return data().HasConstexprMoveConstructor ||
            (needsImplicitMoveConstructor() &&
-            data().DefaultedMoveConstructorIsConstexpr && isLiteral());
+            data().DefaultedMoveConstructorIsConstexpr);
   }
 
   // hasTrivialCopyConstructor - Whether this class has a trivial copy
index 1d5ff10f7b5681109405763ca8d3c724c546081c..ee90b23e5c2e8e972629728cac3124a7695d9362 100644 (file)
@@ -1684,6 +1684,13 @@ void FunctionDecl::setPure(bool P) {
       Parent->markedVirtualFunctionPure();
 }
 
+void FunctionDecl::setConstexpr(bool IC) {
+  IsConstexpr = IC;
+  CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(this);
+  if (IC && CD)
+    CD->getParent()->markedConstructorConstexpr(CD);
+}
+
 bool FunctionDecl::isMain() const {
   const TranslationUnitDecl *tunit =
     dyn_cast<TranslationUnitDecl>(getDeclContext()->getRedeclContext());
index 1c0316db71cc0b3494b8f36c3315676042dfd288..84aa7c5c881321809852501da77f7b313bb6224d 100644 (file)
@@ -470,6 +470,18 @@ void CXXRecordDecl::markedVirtualFunctionPure() {
   data().Abstract = true;
 }
 
+void CXXRecordDecl::markedConstructorConstexpr(CXXConstructorDecl *CD) {
+  if (CD->isCopyConstructor())
+    data().HasConstexprCopyConstructor = true;
+  else if (CD->isMoveConstructor())
+    data().HasConstexprMoveConstructor = true;
+  else
+    data().HasConstexprNonCopyMoveConstructor = true;
+
+  if (CD->isDefaultConstructor())
+    data().HasConstexprDefaultConstructor = true;
+}
+
 void CXXRecordDecl::addedMember(Decl *D) {
   if (!D->isImplicit() &&
       !isa<FieldDecl>(D) &&
index 0a9aa6214594fff7c40f9a6757caa2e508c3dfe3..5d436016a056f04ed1b51e0e582480ea3db3bcac 100644 (file)
@@ -58,3 +58,59 @@ struct Constexpr5Base {};
 struct Constexpr5 : Constexpr5Base { constexpr Constexpr5() {} };
 constexpr Constexpr5 ce5move = Constexpr5();
 constexpr Constexpr5 ce5copy = ce5move;
+
+// An explicitly-defaulted constructor doesn't become constexpr until the end of
+// its class. Make sure we note that the class has a constexpr constructor when
+// that happens.
+namespace PR13052 {
+  template<typename T> struct S {
+    S() = default; // expected-note 2{{here}}
+    S(S&&) = default;
+    S(const S&) = default;
+    T t;
+  };
+
+  struct U {
+    U() = default;
+    U(U&&) = default;
+    U(const U&) = default;
+  };
+
+  struct V {
+    V(); // expected-note {{here}}
+    V(V&&) = default;
+    V(const V&) = default;
+  };
+
+  struct W {
+    W(); // expected-note {{here}}
+  };
+
+  static_assert(__is_literal_type(U), "");
+  static_assert(!__is_literal_type(V), "");
+  static_assert(!__is_literal_type(W), "");
+  static_assert(__is_literal_type(S<U>), "");
+  static_assert(!__is_literal_type(S<V>), "");
+  static_assert(!__is_literal_type(S<W>), "");
+
+  struct X {
+    friend constexpr U::U() noexcept;
+    friend constexpr U::U(U&&) noexcept;
+    friend constexpr U::U(const U&) noexcept;
+    friend constexpr V::V(); // expected-error {{follows non-constexpr declaration}}
+    friend constexpr V::V(V&&) noexcept;
+    friend constexpr V::V(const V&) noexcept;
+    friend constexpr W::W(); // expected-error {{follows non-constexpr declaration}}
+    friend constexpr W::W(W&&) noexcept;
+    friend constexpr W::W(const W&) noexcept;
+    friend constexpr S<U>::S() noexcept;
+    friend constexpr S<U>::S(S<U>&&) noexcept;
+    friend constexpr S<U>::S(const S<U>&) noexcept;
+    friend constexpr S<V>::S(); // expected-error {{follows non-constexpr declaration}}
+    friend constexpr S<V>::S(S<V>&&) noexcept;
+    friend constexpr S<V>::S(const S<V>&) noexcept;
+    friend constexpr S<W>::S(); // expected-error {{follows non-constexpr declaration}}
+    friend constexpr S<W>::S(S<W>&&) noexcept;
+    friend constexpr S<W>::S(const S<W>&) noexcept;
+  };
+}
index 02e6cd1c9ab6cc36801e4c1d3adf69fb09216074..a2613f4612989d64746cf31b1bfbbab9e1643d13 100644 (file)
@@ -43,6 +43,6 @@ struct Test {
   friend C::C(C &);
   friend D::D(const D &);
   friend E::E(E &);
-  friend F::F(const F &);
+  constexpr friend F::F(const F &);
   friend G::G(G &);
 };