summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2012-06-08 21:09:22 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2012-06-08 21:09:22 +0000
commit12f247f43f7c82c252b1c85b9a94f6494d362996 (patch)
treebfca3c75327b797a1369869d4a30f6e7ef2c5390
parent3293f460e7c413d68556457d1fbc2fad94a62afb (diff)
downloadbcm5719-llvm-12f247f43f7c82c252b1c85b9a94f6494d362996.tar.gz
bcm5719-llvm-12f247f43f7c82c252b1c85b9a94f6494d362996.zip
PR13051: If a constructor is explicitly defaulted, it isn't marked as being
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. llvm-svn: 158228
-rw-r--r--clang/include/clang/AST/Decl.h6
-rw-r--r--clang/include/clang/AST/DeclCXX.h9
-rw-r--r--clang/lib/AST/Decl.cpp7
-rw-r--r--clang/lib/AST/DeclCXX.cpp12
-rw-r--r--clang/test/CXX/special/class.copy/p13-0x.cpp56
-rw-r--r--clang/test/CXX/special/class.copy/p8-cxx11.cpp2
6 files changed, 85 insertions, 7 deletions
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 8ec69b43f09..a7bf599636f 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -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.
///
diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h
index 6b44f777bb9..21e8a98bef3 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -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
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 1d5ff10f7b5..ee90b23e5c2 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -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());
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 1c0316db71c..84aa7c5c881 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -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) &&
diff --git a/clang/test/CXX/special/class.copy/p13-0x.cpp b/clang/test/CXX/special/class.copy/p13-0x.cpp
index 0a9aa621459..5d436016a05 100644
--- a/clang/test/CXX/special/class.copy/p13-0x.cpp
+++ b/clang/test/CXX/special/class.copy/p13-0x.cpp
@@ -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;
+ };
+}
diff --git a/clang/test/CXX/special/class.copy/p8-cxx11.cpp b/clang/test/CXX/special/class.copy/p8-cxx11.cpp
index 02e6cd1c9ab..a2613f46129 100644
--- a/clang/test/CXX/special/class.copy/p8-cxx11.cpp
+++ b/clang/test/CXX/special/class.copy/p8-cxx11.cpp
@@ -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 &);
};
OpenPOWER on IntegriCloud