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
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; }
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.
///
void markedVirtualFunctionPure();
friend void FunctionDecl::setPure(bool);
+ void markedConstructorConstexpr(CXXConstructorDecl *CD);
+ friend void FunctionDecl::setConstexpr(bool);
+
friend class ASTNodeImporter;
protected:
bool hasConstexprDefaultConstructor() const {
return data().HasConstexprDefaultConstructor ||
(!data().UserDeclaredConstructor &&
- defaultedDefaultConstructorIsConstexpr() && isLiteral());
+ defaultedDefaultConstructorIsConstexpr());
}
/// hasConstexprCopyConstructor - Whether this class has a constexpr copy
bool hasConstexprCopyConstructor() const {
return data().HasConstexprCopyConstructor ||
(!data().DeclaredCopyConstructor &&
- data().DefaultedCopyConstructorIsConstexpr && isLiteral());
+ data().DefaultedCopyConstructorIsConstexpr);
}
/// hasConstexprMoveConstructor - Whether this class has a constexpr move
bool hasConstexprMoveConstructor() const {
return data().HasConstexprMoveConstructor ||
(needsImplicitMoveConstructor() &&
- data().DefaultedMoveConstructorIsConstexpr && isLiteral());
+ data().DefaultedMoveConstructorIsConstexpr);
}
// hasTrivialCopyConstructor - Whether this class has a trivial copy
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());
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) &&
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;
+ };
+}
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 &);
};