summaryrefslogtreecommitdiffstats
path: root/clang/test/SemaCXX/constant-expression-cxx11.cpp
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2011-12-19 06:19:21 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2011-12-19 06:19:21 +0000
commitd0b4dd656d11d60855bf5b78c7059a3a6c5724d4 (patch)
tree35d257022b6b7e00a6cf5e0cc038a8a1c7b588ac /clang/test/SemaCXX/constant-expression-cxx11.cpp
parentdec792ebb5de0a6b9ff7b9f5ae25682c7031e529 (diff)
downloadbcm5719-llvm-d0b4dd656d11d60855bf5b78c7059a3a6c5724d4.tar.gz
bcm5719-llvm-d0b4dd656d11d60855bf5b78c7059a3a6c5724d4.zip
constexpr handling improvements. Produce detailed diagnostics when a 'constexpr'
variable is initialized by a non-constant expression, and pass in the variable being declared so that earlier-initialized fields' values can be used. Rearrange VarDecl init evaluation to make this possible, and in so doing fix a long-standing issue in our C++ constant expression handling, where we would mishandle cases like: extern const int a; const int n = a; const int a = 5; int arr[n]; Here, n is not initialized by a constant expression, so can't be used in an ICE, even though the initialization expression would be an ICE if it appeared later in the TU. This requires computing whether the initializer is an ICE eagerly, and saving that information in PCH files. llvm-svn: 146856
Diffstat (limited to 'clang/test/SemaCXX/constant-expression-cxx11.cpp')
-rw-r--r--clang/test/SemaCXX/constant-expression-cxx11.cpp67
1 files changed, 30 insertions, 37 deletions
diff --git a/clang/test/SemaCXX/constant-expression-cxx11.cpp b/clang/test/SemaCXX/constant-expression-cxx11.cpp
index 5b053e4ce67..94da73fcf6a 100644
--- a/clang/test/SemaCXX/constant-expression-cxx11.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx11.cpp
@@ -8,9 +8,7 @@ static_assert(false, "test"); // expected-error {{test}}
}
-// FIXME: support const T& parameters here.
-//template<typename T> constexpr T id(const T &t) { return t; }
-template<typename T> constexpr T id(T t) { return t; } // expected-note {{here}}
+template<typename T> constexpr T id(const T &t) { return t; } // expected-note {{here}}
// FIXME: support templates here.
//template<typename T> constexpr T min(const T &a, const T &b) {
// return a < b ? a : b;
@@ -104,8 +102,14 @@ namespace CaseStatements {
}
extern int &Recurse1;
-int &Recurse2 = Recurse1, &Recurse1 = Recurse2;
-constexpr int &Recurse3 = Recurse2; // expected-error {{must be initialized by a constant expression}}
+int &Recurse2 = Recurse1; // expected-note 2{{declared here}} expected-note {{initializer of 'Recurse1' is not a constant expression}}
+int &Recurse1 = Recurse2; // expected-note {{declared here}} expected-note {{initializer of 'Recurse2' is not a constant expression}}
+constexpr int &Recurse3 = Recurse2; // expected-error {{must be initialized by a constant expression}} expected-note {{initializer of 'Recurse2' is not a constant expression}}
+
+extern const int RecurseA;
+const int RecurseB = RecurseA; // expected-note {{declared here}}
+const int RecurseA = 10;
+constexpr int RecurseC = RecurseB; // expected-error {{must be initialized by a constant expression}} expected-note {{initializer of 'RecurseB' is not a constant expression}}
namespace MemberEnum {
struct WithMemberEnum {
@@ -188,26 +192,26 @@ namespace StaticMemberFunction {
namespace ParameterScopes {
const int k = 42;
- constexpr const int &ObscureTheTruth(const int &a) { return a; }
- constexpr const int &MaybeReturnJunk(bool b, const int a) {
- return ObscureTheTruth(b ? a : k);
+ constexpr const int &ObscureTheTruth(const int &a) { return a; } // expected-note 3{{reference to 'a' cannot be returned from a constexpr function}}
+ constexpr const int &MaybeReturnJunk(bool b, const int a) { // expected-note 2{{declared here}}
+ return ObscureTheTruth(b ? a : k); // expected-note 2{{in call to 'ObscureTheTruth(a)'}}
}
static_assert(MaybeReturnJunk(false, 0) == 42, ""); // ok
- constexpr int a = MaybeReturnJunk(true, 0); // expected-error {{constant expression}}
+ constexpr int a = MaybeReturnJunk(true, 0); // expected-error {{constant expression}} expected-note {{in call to 'MaybeReturnJunk(1, 0)'}}
- constexpr const int MaybeReturnNonstaticRef(bool b, const int a) {
+ constexpr const int MaybeReturnNonstaticRef(bool b, const int a) { // expected-note {{here}}
// If ObscureTheTruth returns a reference to 'a', the result is not a
// constant expression even though 'a' is still in scope.
- return ObscureTheTruth(b ? a : k);
+ return ObscureTheTruth(b ? a : k); // expected-note {{in call to 'ObscureTheTruth(a)'}}
}
static_assert(MaybeReturnNonstaticRef(false, 0) == 42, ""); // ok
- constexpr int b = MaybeReturnNonstaticRef(true, 0); // expected-error {{constant expression}}
+ constexpr int b = MaybeReturnNonstaticRef(true, 0); // expected-error {{constant expression}} expected-note {{in call to 'MaybeReturnNonstaticRef(1, 0)'}}
constexpr int InternalReturnJunk(int n) {
// FIXME: We should reject this: it never produces a constant expression.
- return MaybeReturnJunk(true, n);
+ return MaybeReturnJunk(true, n); // expected-note {{in call to 'MaybeReturnJunk(1, 0)'}}
}
- constexpr int n3 = InternalReturnJunk(0); // expected-error {{must be initialized by a constant expression}}
+ constexpr int n3 = InternalReturnJunk(0); // expected-error {{must be initialized by a constant expression}} expected-note {{in call to 'InternalReturnJunk(0)'}}
constexpr int LToR(int &n) { return n; }
constexpr int GrabCallersArgument(bool which, int a, int b) {
@@ -243,11 +247,11 @@ namespace FunctionPointers {
constexpr auto Select(int n) -> int (*)(int) {
return n == 2 ? &Double : n == 3 ? &Triple : n == 4 ? &Quadruple : 0;
}
- constexpr int Apply(int (*F)(int), int n) { return F(n); }
+ constexpr int Apply(int (*F)(int), int n) { return F(n); } // expected-note {{subexpression}}
static_assert(1 + Apply(Select(4), 5) + Apply(Select(3), 7) == 42, "");
- constexpr int Invalid = Apply(Select(0), 0); // expected-error {{must be initialized by a constant expression}}
+ constexpr int Invalid = Apply(Select(0), 0); // expected-error {{must be initialized by a constant expression}} expected-note {{in call to 'Apply(0, 0)'}}
}
@@ -293,9 +297,7 @@ static_assert(&x < &x, "false"); // expected-error {{false}}
static_assert(&x > &x, "false"); // expected-error {{false}}
constexpr S* sptr = &s;
-// FIXME: This is not a constant expression; check we reject this and move this
-// test elsewhere.
-constexpr bool dyncast = sptr == dynamic_cast<S*>(sptr);
+constexpr bool dyncast = sptr == dynamic_cast<S*>(sptr); // expected-error {{constant expression}} expected-note {{dynamic_cast}}
struct Str {
// FIXME: In C++ mode, we should say 'integral' not 'integer'
@@ -323,8 +325,6 @@ struct Str {
};
extern char externalvar[];
-// FIXME: This is not a constant expression; check we reject this and move this
-// test elsewhere.
constexpr bool constaddress = (void *)externalvar == (void *)0x4000UL; // expected-error {{must be initialized by a constant expression}}
constexpr bool litaddress = "foo" == "foo"; // expected-error {{must be initialized by a constant expression}} expected-warning {{unspecified}}
static_assert(0 != "foo", "");
@@ -509,21 +509,17 @@ struct D {
};
static_assert(D().c.n == 42, "");
-struct E {
- constexpr E() : p(&p) {}
+struct E { // expected-note {{here}}
+ constexpr E() : p(&p) {} // expected-note {{pointer to temporary cannot be used to initialize a member in a constant expression}}
void *p;
};
-constexpr const E &e1 = E(); // expected-error {{constant expression}}
+constexpr const E &e1 = E(); // expected-error {{constant expression}} expected-note {{in call to 'E()'}} expected-note {{temporary created here}}
// This is a constant expression if we elide the copy constructor call, and
// is not a constant expression if we don't! But we do, so it is.
// FIXME: The move constructor is not currently implicitly defined as constexpr.
-// We notice this when evaluating an expression which uses it, but not when
-// checking its initializer.
-constexpr E e2 = E(); // unexpected-error {{constant expression}}
-static_assert(e2.p == &e2.p, ""); // unexpected-error {{constant expression}} unexpected-note {{subexpression}}
-// FIXME: We don't pass through the fact that 'this' is ::e3 when checking the
-// initializer of this declaration.
-constexpr E e3; // unexpected-error {{constant expression}}
+constexpr E e2 = E(); // unexpected-error {{constant expression}} unexpected-note {{here}} unexpected-note {{non-constexpr constructor 'E' cannot be used in a constant expression}}
+static_assert(e2.p == &e2.p, ""); // unexpected-error {{constant expression}} unexpected-note {{initializer of 'e2' is not a constant expression}}
+constexpr E e3;
static_assert(e3.p == &e3.p, "");
extern const class F f;
@@ -531,7 +527,7 @@ struct F {
constexpr F() : p(&f.p) {}
const void *p;
};
-constexpr F f = F();
+constexpr F f;
struct G {
struct T {
@@ -624,10 +620,7 @@ struct Base : Bottom {
struct Base2 : Bottom {
constexpr Base2(const int &r) : r(r) {}
int q = 123;
- // FIXME: When we track the global for which we are computing the initializer,
- // use a reference here.
- //const int &r;
- int r;
+ const int &r;
};
struct Derived : Base, Base2 {
constexpr Derived() : Base(76), Base2(a) {}
@@ -646,7 +639,7 @@ static_assert(derived.b[2] == 's', "");
static_assert(derived.c == 76 + 'e', "");
static_assert(derived.q == 123, "");
static_assert(derived.r == 76, "");
-static_assert(&derived.r == &derived.a, ""); // expected-error {{}}
+static_assert(&derived.r == &derived.a, "");
static_assert(!(derived == base), "");
static_assert(derived == base2, "");
OpenPOWER on IntegriCloud