// RUN: %clang_cc1 -fsyntax-only -verify=expected -std=c++23 %s
// This test covers modifications made by P2448R2.
// Check that there is no error when a constexpr function that never produces a
// constant expression, but still an error if such function is called from
// constexpr context.
constexpr int F(int N) {
double D = 2.0 / 0.0; // expected-note {{division by zero}}
return 1;
}
constexpr int F0(int N) {
if (N == 0)
double d2 = 2.0 / 0.0; // expected-note {{division by zero}}
return 1;
}
template <typename T>
constexpr int FT(T N) {
double D = 2.0 / 0.0; // expected-note {{division by zero}}
return 1;
}
class NonLiteral { // expected-note {{'NonLiteral' is not literal because it is not an aggregate and has no constexpr constructors}}
public:
NonLiteral() {}
~NonLiteral() {} // expected-note {{declared here}}
};
constexpr NonLiteral F1() {
return NonLiteral{};
}
constexpr int F2(NonLiteral N) { // expected-note {{non-constexpr function '~NonLiteral' cannot be used in a constant expression}}
return 8;
}
class Derived : public NonLiteral {
constexpr ~Derived() {};
};
class Derived1 : public NonLiteral {
constexpr Derived1() : NonLiteral () {}
};
struct X {
X(); // expected-note 2{{declared here}}
X(const X&);
X(X&&);
X& operator=(X&);
X& operator=(X&& other);
bool operator==(X const&) const;
};
template <typename T>
struct Wrapper {
constexpr Wrapper() = default;
constexpr Wrapper(Wrapper const&) = default;
constexpr Wrapper(T const& t) : t(t) { }
constexpr Wrapper(Wrapper &&) = default;
constexpr X get() const { return t; }
constexpr bool operator==(Wrapper const&) const = default;
private:
T t;
};
struct WrapperNonT {
constexpr WrapperNonT() = default;
constexpr WrapperNonT(WrapperNonT const&) = default;
constexpr WrapperNonT(X const& t) : t(t) { }
constexpr WrapperNonT(WrapperNonT &&) = default;
constexpr WrapperNonT& operator=(WrapperNonT &) = default;
constexpr WrapperNonT& operator=(WrapperNonT&& other) = default;
constexpr X get() const { return t; }
constexpr bool operator==(WrapperNonT const&) const = default;
private:
X t;
};
struct NonDefaultMembers {
constexpr NonDefaultMembers() {}; // expected-note 2{{non-constexpr constructor 'X' cannot be used in a constant expression}}
constexpr NonDefaultMembers(NonDefaultMembers const&) {};
constexpr NonDefaultMembers(NonDefaultMembers &&) {};
constexpr NonDefaultMembers& operator=(NonDefaultMembers &other) {this->t = other.t; return *this;}
constexpr NonDefaultMembers& operator=(NonDefaultMembers&& other) {this->t = other.t; return *this;}
constexpr bool operator==(NonDefaultMembers const& other) const {return this->t == other.t;}
X t;
};
int Glob = 0;
class C1 {
public:
constexpr C1() : D(Glob) {};
private:
int D;
};
void test() {
constexpr int A = F(3); // expected-error {{constexpr variable 'A' must be initialized by a constant expression}}
// expected-note@-1 {{in call}}
F(3);
constexpr int B = F0(0); // expected-error {{constexpr variable 'B' must be initialized by a constant expression}}
// expected-note@-1 {{in call}}
F0(0);
constexpr auto C = F1(); // expected-error {{constexpr variable cannot have non-literal type 'const NonLiteral'}}
F1();
NonLiteral L;
constexpr auto D = F2(L); // expected-error {{constexpr variable 'D' must be initialized by a constant expression}}
constexpr auto E = FT(1); // expected-error {{constexpr variable 'E' must be initialized by a constant expression}}
// expected-note@-1 {{in call}}
F2(L);
Wrapper<X> x;
WrapperNonT x1;
NonDefaultMembers x2;
// TODO these produce notes with an invalid source location.
// static_assert((Wrapper<X>(), true));
// static_assert((WrapperNonT(), true),"");
static_assert((NonDefaultMembers(), true),""); // expected-error{{expression is not an integral constant expression}} \
// expected-note {{in call to}}
constexpr bool FFF = (NonDefaultMembers() == NonDefaultMembers()); // expected-error {{must be initialized by a constant expression}} \
// expected-note {{in call to 'NonDefaultMembers()'}}
}
struct A {
A ();
~A();
};
template <class T>
struct opt
{
union {
char c;
T data;
};
constexpr opt() {}
constexpr ~opt() {
if (engaged)
data.~T();
}
bool engaged = false;
};
consteval void foo() {
opt<A> a;
}
void bar() { foo(); }