aboutsummaryrefslogtreecommitdiff
path: root/clang/test
diff options
context:
space:
mode:
authorCorentin Jabot <corentinjabot@gmail.com>2021-10-05 23:33:31 +0200
committerCorentin Jabot <corentinjabot@gmail.com>2022-03-22 19:51:19 +0100
commit683e83c56f98df6fe42d506a04dda44309ca758f (patch)
tree425747d6753617f8a8f10b6df4de06805135143b /clang/test
parentbafbae238aa1948aa511c734a613a95d89a72546 (diff)
downloadllvm-683e83c56f98df6fe42d506a04dda44309ca758f.zip
llvm-683e83c56f98df6fe42d506a04dda44309ca758f.tar.gz
llvm-683e83c56f98df6fe42d506a04dda44309ca758f.tar.bz2
[Clang][C++2b] P2242R3: Non-literal variables [...] in constexpr
Allow goto, labelled statements as well as `static`, `thread_local`, and non-literal variables in `constexpr` functions. As specified. for all of the above (except labelled statements) constant evaluation of the construct still fails. For `constexpr` bodies, the proposal is implemented with diagnostics as a language extension in older language modes. For determination of whether a lambda body satisfies the requirements for a constexpr function, the proposal is implemented only in C++2b mode to retain the semantics of older modes for programs conforming to them. Reviewed By: aaron.ballman, hubert.reinterpretcast, erichkeane Differential Revision: https://reviews.llvm.org/D111400
Diffstat (limited to 'clang/test')
-rw-r--r--clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/dtor.cpp26
-rw-r--r--clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3-2b.cpp55
-rw-r--r--clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp64
-rw-r--r--clang/test/Lexer/cxx-features.cpp2
-rw-r--r--clang/test/SemaCXX/constant-expression-cxx14.cpp10
-rw-r--r--clang/test/SemaCXX/constant-expression-cxx2b.cpp240
6 files changed, 366 insertions, 31 deletions
diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/dtor.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/dtor.cpp
index 3d45949..dcb9f60 100644
--- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/dtor.cpp
+++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/dtor.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -std=c++2a -verify %s
+// RUN: %clang_cc1 -std=c++2a -verify=expected,cxx2a %s
+// RUN: %clang_cc1 -std=c++2b -verify=expected %s
// p3: if the function is a constructor or destructor, its class shall not have
// any virtual base classes;
@@ -9,40 +10,43 @@ namespace vbase {
};
}
-// p3: its function-body shall not enclose
-// -- a goto statement
-// -- an identifier label
-// -- a variable of non-literal type or of static or thread storage duration
namespace contents {
struct A {
constexpr ~A() {
- goto x; // expected-error {{statement not allowed in constexpr function}}
+ return;
+ goto x; // cxx2a-warning {{use of this statement in a constexpr function is a C++2b extension}}
x: ;
}
};
struct B {
constexpr ~B() {
- x: ; // expected-error {{statement not allowed in constexpr function}}
+ x:; // cxx2a-warning {{use of this statement in a constexpr function is a C++2b extension}}
}
};
- struct Nonlit { Nonlit(); }; // expected-note {{not literal}}
+ struct Nonlit { // cxx2a-note {{'Nonlit' is not literal because}}
+ Nonlit();
+ };
struct C {
constexpr ~C() {
- Nonlit nl; // expected-error {{non-literal}}
+ return;
+ Nonlit nl; // cxx2a-error {{variable of non-literal type 'contents::Nonlit' cannot be defined in a constexpr function before C++2b}}
}
};
struct D {
constexpr ~D() {
- static int a; // expected-error {{static variable}}
+ return;
+ static int a; // cxx2a-warning {{definition of a static variable in a constexpr function is a C++2b extension}}
}
};
struct E {
constexpr ~E() {
- thread_local int e; // expected-error {{thread_local variable}}
+ return;
+ thread_local int e; // cxx2a-warning {{definition of a thread_local variable in a constexpr function is a C++2b extension}}
}
};
struct F {
constexpr ~F() {
+ return;
extern int f;
}
};
diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3-2b.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3-2b.cpp
new file mode 100644
index 0000000..671895b
--- /dev/null
+++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3-2b.cpp
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 -verify -std=c++2b -Wpre-c++2b-compat %s
+
+constexpr int h(int n) {
+ if (!n)
+ return 0;
+ static const int m = n; // expected-warning {{definition of a static variable in a constexpr function is incompatible with C++ standards before C++2b}}
+ return m;
+}
+
+constexpr int i(int n) {
+ if (!n)
+ return 0;
+ thread_local const int m = n; // expected-warning {{definition of a thread_local variable in a constexpr function is incompatible with C++ standards before C++2b}}
+ return m;
+}
+
+constexpr int g() { // expected-error {{constexpr function never produces a constant expression}}
+ goto test; // expected-note {{subexpression not valid in a constant expression}} \
+ // expected-warning {{use of this statement in a constexpr function is incompatible with C++ standards before C++2b}}
+test:
+ return 0;
+}
+
+constexpr void h() {
+label:; // expected-warning {{use of this statement in a constexpr function is incompatible with C++ standards before C++2b}}
+}
+
+struct NonLiteral {
+ NonLiteral() {}
+};
+
+constexpr void non_literal() { // expected-error {{constexpr function never produces a constant expression}}
+ NonLiteral n; // expected-note {{non-literal type 'NonLiteral' cannot be used in a constant expression}}
+}
+
+constexpr void non_literal2(bool b) {
+ if (!b)
+ NonLiteral n;
+}
+
+constexpr int c_thread_local(int n) {
+ if (!n)
+ return 0;
+ static _Thread_local int a; // expected-warning {{definition of a static variable in a constexpr function is incompatible with C++ standards before C++2b}}
+ _Thread_local int b; // // expected-error {{'_Thread_local' variables must have global storage}}
+ return 0;
+}
+
+constexpr int gnu_thread_local(int n) {
+ if (!n)
+ return 0;
+ static __thread int a; // expected-warning {{definition of a static variable in a constexpr function is incompatible with C++ standards before C++2b}}
+ __thread int b; // expected-error {{'__thread' variables must have global storage}}
+ return 0;
+}
diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp
index 9b0e7cc..3dbe3e9 100644
--- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp
+++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp
@@ -1,6 +1,7 @@
-// RUN: %clang_cc1 -verify -fcxx-exceptions -triple=x86_64-linux-gnu -std=c++11 -Werror=c++14-extensions -Werror=c++20-extensions %s
-// RUN: %clang_cc1 -verify -fcxx-exceptions -triple=x86_64-linux-gnu -std=c++14 -DCXX14 -Werror=c++20-extensions %s
-// RUN: %clang_cc1 -verify -fcxx-exceptions -triple=x86_64-linux-gnu -std=c++20 -DCXX14 -DCXX20 %s
+// RUN: %clang_cc1 -verify -fcxx-exceptions -triple=x86_64-linux-gnu -std=c++11 -Werror=c++14-extensions -Werror=c++20-extensions -Werror=c++2b-extensions %s
+// RUN: %clang_cc1 -verify -fcxx-exceptions -triple=x86_64-linux-gnu -std=c++14 -DCXX14 -Werror=c++20-extensions -Werror=c++2b-extensions %s
+// RUN: %clang_cc1 -verify -fcxx-exceptions -triple=x86_64-linux-gnu -std=c++20 -DCXX14 -DCXX20 -Werror=c++2b-extensions %s
+// RUN: %clang_cc1 -verify -fcxx-exceptions -triple=x86_64-linux-gnu -std=c++2b -DCXX14 -DCXX20 -DCXX2b %s
namespace N {
typedef char C;
@@ -10,7 +11,7 @@ namespace M {
typedef double D;
}
-struct NonLiteral { // expected-note 3{{no constexpr constructors}}
+struct NonLiteral { // expected-note 2{{no constexpr constructors}}
NonLiteral() {}
NonLiteral(int) {}
};
@@ -150,16 +151,26 @@ constexpr int DisallowedStmtsCXX14_1(bool b) {
}
constexpr int DisallowedStmtsCXX14_2() {
// - a goto statement
- goto x; // expected-error {{statement not allowed in constexpr function}}
-x:
+ try {
+ } catch (...) {
+ goto x;
+ x:;
+ }
+#ifndef CXX2b
+ // expected-error@-4 {{use of this statement in a constexpr function is a C++2b extension}}
+#endif
return 0;
}
constexpr int DisallowedStmtsCXX14_2_1() {
try {
- return 0;
} catch (...) {
- merp: goto merp; // expected-error {{statement not allowed in constexpr function}}
+ merp:
+ goto merp;
+#ifndef CXX2b
+ // expected-error@-3 {{use of this statement in a constexpr function is a C++2b extension}}
+#endif
}
+ return 0;
}
constexpr int DisallowedStmtsCXX14_3() {
// - a try-block,
@@ -171,18 +182,35 @@ constexpr int DisallowedStmtsCXX14_3() {
}
constexpr int DisallowedStmtsCXX14_4() {
// - a definition of a variable of non-literal type
- NonLiteral nl; // expected-error {{variable of non-literal type 'NonLiteral' cannot be defined in a constexpr function}}
return 0;
+ NonLiteral nl;
+#ifndef CXX2b
+ // expected-error@-2 {{variable of non-literal type 'NonLiteral' cannot be defined in a constexpr function before C++2b}}
+ // expected-note@14 {{'NonLiteral' is not literal}}
+#endif
}
+
constexpr int DisallowedStmtsCXX14_5() {
+ return 0;
// - a definition of a variable of static storage duration
- static constexpr int n = 123; // expected-error {{static variable not permitted in a constexpr function}}
- return n;
+ static constexpr int n = 123;
+#ifndef CXX2b
+ // expected-error@-2 {{definition of a static variable in a constexpr function is a C++2b extension}}
+#endif
+#if !defined(CXX14)
+ // expected-error@-5 {{variable declaration in a constexpr function is a C++14 extension}}
+#endif
}
constexpr int DisallowedStmtsCXX14_6() {
// - a definition of a variable of thread storage duration
- thread_local constexpr int n = 123; // expected-error {{thread_local variable not permitted in a constexpr function}}
- return n;
+ return 0;
+ thread_local constexpr int n = 123;
+#ifndef CXX2b
+ // expected-error@-2 {{definition of a thread_local variable in a constexpr function is a C++2b extension}}
+#endif
+#if !defined(CXX14)
+ // expected-error@-5 {{variable declaration in a constexpr function is a C++14 extension}}
+#endif
}
constexpr int DisallowedStmtsCXX14_7() {
// - a definition of a variable for which no initialization is performed
@@ -317,8 +345,14 @@ namespace std_example {
return x;
}
constexpr int first(int n) {
- static int value = n; // expected-error {{static variable not permitted}}
- return value;
+ return 0;
+ static int value = n;
+#ifndef CXX2b
+ // expected-error@-2 {{definition of a static variable in a constexpr function is a C++2b extension}}
+#endif
+#ifndef CXX14
+ // expected-error@-5 {{variable declaration in a constexpr function is a C++14 extension}}
+#endif
}
constexpr int uninit() {
int a;
diff --git a/clang/test/Lexer/cxx-features.cpp b/clang/test/Lexer/cxx-features.cpp
index 2847273..6b6729d 100644
--- a/clang/test/Lexer/cxx-features.cpp
+++ b/clang/test/Lexer/cxx-features.cpp
@@ -277,7 +277,7 @@
#error "wrong value for __cpp_lambdas"
#endif
-#if check(constexpr, 0, 200704, 201304, 201603, 201907, 201907)
+#if check(constexpr, 0, 200704, 201304, 201603, 201907, 202110)
#error "wrong value for __cpp_constexpr"
#endif
diff --git a/clang/test/SemaCXX/constant-expression-cxx14.cpp b/clang/test/SemaCXX/constant-expression-cxx14.cpp
index 84ffad3..9f8d8f7 100644
--- a/clang/test/SemaCXX/constant-expression-cxx14.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx14.cpp
@@ -44,12 +44,14 @@ constexpr int g(int k) {
return 3 * k3 + 5 * k2 + n * k - 20;
}
static_assert(g(2) == 42, "");
-constexpr int h(int n) {
- static const int m = n; // expected-error {{static variable not permitted in a constexpr function}}
+constexpr int h(int n) { // expected-error {{constexpr function never produces a constant expression}}
+ static const int m = n; // expected-note {{control flows through the definition of a static variable}} \
+ // cxx14_20-warning {{definition of a static variable in a constexpr function is a C++2b extension}}
return m;
}
-constexpr int i(int n) {
- thread_local const int m = n; // expected-error {{thread_local variable not permitted in a constexpr function}}
+constexpr int i(int n) { // expected-error {{constexpr function never produces a constant expression}}
+ thread_local const int m = n; // expected-note {{control flows through the definition of a thread_local variable}} \
+ // cxx14_20-warning {{definition of a thread_local variable in a constexpr function is a C++2b extension}}
return m;
}
diff --git a/clang/test/SemaCXX/constant-expression-cxx2b.cpp b/clang/test/SemaCXX/constant-expression-cxx2b.cpp
new file mode 100644
index 0000000..0657a35
--- /dev/null
+++ b/clang/test/SemaCXX/constant-expression-cxx2b.cpp
@@ -0,0 +1,240 @@
+// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify=expected,cxx2a %s -fcxx-exceptions -triple=x86_64-linux-gnu -Wno-c++2b-extensions
+// RUN: %clang_cc1 -std=c++2b -fsyntax-only -verify=expected,cxx2b %s -fcxx-exceptions -triple=x86_64-linux-gnu -Wpre-c++2b-compat
+
+struct NonLiteral { // cxx2a-note {{'NonLiteral' is not literal}}
+ NonLiteral() {}
+};
+
+#if __cplusplus > 202002L
+
+constexpr int f(int n) { // expected-error {{constexpr function never produces a constant expression}}
+ static const int m = n; // expected-note {{control flows through the definition of a static variable}} \
+ // cxx2b-warning {{definition of a static variable in a constexpr function is incompatible with C++ standards before C++2b}}
+ return m;
+}
+constexpr int g(int n) { // expected-error {{constexpr function never produces a constant expression}}
+ thread_local const int m = n; // expected-note {{control flows through the definition of a thread_local variable}} \
+ // cxx2b-warning {{definition of a thread_local variable in a constexpr function is incompatible with C++ standards before C++2b}}
+ return m;
+}
+
+constexpr int c_thread_local(int n) { // expected-error {{constexpr function never produces a constant expression}}
+ static _Thread_local int m = 0; // expected-note {{control flows through the definition of a thread_local variable}} \
+ // cxx2b-warning {{definition of a static variable in a constexpr function is incompatible with C++ standards before C++2b}}
+ return m;
+}
+
+constexpr int gnu_thread_local(int n) { // expected-error {{constexpr function never produces a constant expression}}
+ static __thread int m = 0; // expected-note {{control flows through the definition of a thread_local variable}} \
+ // cxx2b-warning {{definition of a static variable in a constexpr function is incompatible with C++ standards before C++2b}}
+ return m;
+}
+
+constexpr int h(int n) { // expected-error {{constexpr function never produces a constant expression}}
+ static const int m = n; // expected-note {{control flows through the definition of a static variable}} \
+ // cxx2b-warning {{definition of a static variable in a constexpr function is incompatible with C++ standards before C++2b}}
+ return &m - &m;
+}
+constexpr int i(int n) { // expected-error {{constexpr function never produces a constant expression}}
+ thread_local const int m = n; // expected-note {{control flows through the definition of a thread_local variable}} \
+ // cxx2b-warning {{definition of a thread_local variable in a constexpr function is incompatible with C++ standards before C++2b}}
+ return &m - &m;
+}
+
+constexpr int j(int n) {
+ if (!n)
+ return 0;
+ static const int m = n; // cxx2b-warning {{definition of a static variable in a constexpr function is incompatible with C++ standards before C++2b}}
+ return m;
+}
+constexpr int j0 = j(0);
+
+constexpr int k(int n) {
+ if (!n)
+ return 0;
+ thread_local const int m = n; // cxx2b-warning {{definition of a thread_local variable in a constexpr function is incompatible with C++ standards before C++2b}}
+
+ return m;
+}
+constexpr int k0 = k(0);
+
+constexpr int j_evaluated(int n) {
+ if (!n)
+ return 0;
+ static const int m = n; // expected-note {{control flows through the definition of a static variable}} \
+ // cxx2b-warning {{definition of a static variable in a constexpr function is incompatible with C++ standards before C++2b}}
+ return m;
+}
+
+constexpr int je = j_evaluated(1); // expected-error {{constexpr variable 'je' must be initialized by a constant expression}} \
+ // expected-note {{in call}}
+
+constexpr int k_evaluated(int n) {
+ if (!n)
+ return 0;
+ thread_local const int m = n; // expected-note {{control flows through the definition of a thread_local variable}} \
+ // cxx2b-warning {{definition of a thread_local variable in a constexpr function is incompatible with C++ standards before C++2b}}
+
+ return m;
+}
+
+constexpr int ke = k_evaluated(1); // expected-error {{constexpr variable 'ke' must be initialized by a constant expression}} \
+ // expected-note {{in call}}
+
+constexpr int static_constexpr() { // expected-error {{constexpr function never produces a constant expression}}
+ static constexpr int m = 42; // expected-note {{control flows through the definition of a static variable}} \
+ // cxx2b-warning {{definition of a static variable in a constexpr function is incompatible with C++ standards before C++2b}}
+ return m;
+}
+
+constexpr int thread_local_constexpr() { // expected-error {{constexpr function never produces a constant expression}}
+ thread_local constexpr int m = 42; // expected-note {{control flows through the definition of a thread_local variable}} \
+ // cxx2b-warning {{definition of a thread_local variable in a constexpr function is incompatible with C++ standards before C++2b}}
+ return m;
+}
+
+constexpr int non_literal(bool b) {
+ if (!b)
+ return 0;
+ NonLiteral n;
+}
+
+constexpr int non_literal_1 = non_literal(false);
+
+namespace eval_goto {
+
+constexpr int f(int x) {
+ if (x) {
+ return 0;
+ } else {
+ goto test; // expected-note {{subexpression not valid in a constant expression}} \
+ // cxx2b-warning {{use of this statement in a constexpr function is incompatible with C++ standards before C++2b}}
+ }
+test:
+ return 0;
+}
+
+int a = f(0);
+constexpr int b = f(0); // expected-error {{must be initialized by a constant expression}} \
+ // expected-note {{in call to 'f(0)'}}
+constexpr int c = f(1);
+
+constexpr int label() {
+
+test: // cxx2b-warning {{use of this statement in a constexpr function is incompatible with C++ standards before C++2b}}
+ return 0;
+}
+
+constexpr int d = label();
+
+} // namespace eval_goto
+
+#endif
+
+// Test that explicitly constexpr lambdas behave correctly,
+// This is to be contrasted with the test for implicitly constexpr lambdas below.
+int test_in_lambdas() {
+ auto a = []() constexpr { // expected-error{{constexpr function never produces a constant expression}}
+ static const int m = 32; // expected-note {{control flows through the definition of a static variable}} \
+ // cxx2b-warning {{definition of a static variable in a constexpr function is incompatible with C++ standards before C++2b}}
+ return m;
+ };
+
+ auto b = [](int n) constexpr {
+ if (!n)
+ return 0;
+ static const int m = n; // cxx2b-warning {{definition of a static variable in a constexpr function is incompatible with C++ standards before C++2b}}
+ return m;
+ }
+ (1);
+
+ auto c = [](int n) constexpr {
+ if (!n)
+ return 0;
+ else
+ goto test; // expected-note {{subexpression not valid in a constant expression}} \
+ // cxx2b-warning {{use of this statement in a constexpr function is incompatible with C++ standards before C++2b}}
+ test:
+ return 1;
+ };
+ c(0);
+ constexpr auto c_error = c(1); // expected-error {{constexpr variable 'c_error' must be initialized by a constant expression}} \
+ // expected-note {{in call to}}
+
+ auto non_literal = [](bool b) constexpr {
+ if (!b)
+ NonLiteral n; // cxx2b-note {{non-literal type 'NonLiteral' cannot be used in a constant expression}} \
+ // cxx2a-error {{variable of non-literal type 'NonLiteral' cannot be defined in a constexpr function before C++2b}}
+ return 0;
+ };
+
+#if __cplusplus > 202002L
+ constexpr auto non_literal_ko = non_literal(false); // cxx2b-error {{constexpr variable 'non_literal_ko' must be initialized by a constant expression}} \
+ // cxx2b-note {{in call}}
+
+ constexpr auto non_literal_ok = non_literal(true);
+#endif
+}
+
+// Test whether lambdas are correctly treated as implicitly constexpr under the
+// relaxed C++23 rules (and similarly as not implicitly constexpr under the
+// C++20 rules).
+int test_lambdas_implicitly_constexpr() {
+
+ auto b = [](int n) { // cxx2a-note 2{{declared here}}
+ if (!n)
+ return 0;
+ static const int m = n; // cxx2b-note {{control flows through the definition of a static variable}}
+ return m;
+ };
+
+ auto b1 = b(1);
+ constexpr auto b2 = b(0); // cxx2a-error {{must be initialized by a constant expression}} \
+ // cxx2a-note {{non-constexpr function}}
+
+ constexpr auto b3 = b(1); // expected-error{{constexpr variable 'b3' must be initialized by a constant expression}} \
+ // cxx2a-note {{non-constexpr function}} \
+ // cxx2b-note {{in call}}
+
+ auto c = [](int n) { // cxx2a-note 2{{declared here}}
+ if (!n)
+ return 0;
+ else
+ goto test; // cxx2b-note {{subexpression not valid in a constant expression}}
+ test:
+ return 1;
+ };
+ c(0);
+ constexpr auto c_ok = c(0); // cxx2a-error {{must be initialized by a constant expression}} \
+ // cxx2a-note {{non-constexpr function}}
+
+ constexpr auto c_error = c(1); // expected-error {{constexpr variable 'c_error' must be initialized by a constant expression}} \
+ // cxx2a-note {{non-constexpr function}} \
+ // cxx2b-note {{in call to}}
+
+ auto non_literal = [](bool b) { // cxx2a-note 2{{declared here}}
+ if (b)
+ NonLiteral n; // cxx2b-note {{non-literal type 'NonLiteral' cannot be used in a constant expression}}
+ return 0;
+ };
+
+ constexpr auto non_literal_ko = non_literal(true); // expected-error {{constexpr variable 'non_literal_ko' must be initialized by a constant expression}} \
+ // cxx2a-note {{non-constexpr function}} \
+ // cxx2b-note {{in call}}
+
+ constexpr auto non_literal_ok = non_literal(false); // cxx2a-error {{must be initialized by a constant expression}} \
+ // cxx2a-note {{non-constexpr function}}
+}
+
+template <typename T>
+constexpr auto dependent_var_def_lambda(void) {
+ return [](bool b) { // cxx2a-note {{declared here}}
+ if (!b)
+ T t;
+ return 0;
+ };
+}
+
+constexpr auto non_literal_valid_in_cxx2b = dependent_var_def_lambda<NonLiteral>()(true); // \
+ // cxx2a-error {{constexpr variable 'non_literal_valid_in_cxx2b' must be initialized by a constant expression}} \
+ // cxx2a-note {{non-constexpr function}}