diff options
Diffstat (limited to 'clang/test')
-rw-r--r-- | clang/test/CXX/expr/expr.const/p2-0x.cpp | 26 | ||||
-rw-r--r-- | clang/test/SemaCXX/constant-expression-cxx11.cpp | 39 | ||||
-rw-r--r-- | clang/test/SemaCXX/constexpr-turing.cpp | 55 |
3 files changed, 92 insertions, 28 deletions
diff --git a/clang/test/CXX/expr/expr.const/p2-0x.cpp b/clang/test/CXX/expr/expr.const/p2-0x.cpp index a22d1e4e4e3..8d3638ffc6b 100644 --- a/clang/test/CXX/expr/expr.const/p2-0x.cpp +++ b/clang/test/CXX/expr/expr.const/p2-0x.cpp @@ -49,25 +49,23 @@ struct UndefinedConstexpr { }; // - an invocation of a constexpr function with arguments that, when substituted -// by function invocation substitution (7.1.5), do not produce a constant +// by function invocation substitution (7.1.5), do not produce a core constant // expression; namespace NonConstExprReturn { static constexpr const int &id_ref(const int &n) { - return n; // expected-note {{reference to temporary cannot be returned from a constexpr function}} + return n; } struct NonConstExprFunction { - int n : id_ref( // expected-error {{constant expression}} expected-note {{in call to 'id_ref(16)'}} - 16 // expected-note {{temporary created here}} - ); + int n : id_ref(16); // ok }; constexpr const int *address_of(const int &a) { - return &a; // expected-note {{pointer to 'n' cannot be returned from a constexpr function}} + return &a; } constexpr const int *return_param(int n) { // expected-note {{declared here}} - return address_of(n); // expected-note {{in call to 'address_of(n)'}} + return address_of(n); } struct S { - int n : *return_param(0); // expected-error {{constant expression}} expected-note {{in call to 'return_param(0)'}} + int n : *return_param(0); // expected-error {{constant expression}} expected-note {{read of variable whose lifetime has ended}} }; } @@ -78,16 +76,16 @@ namespace NonConstExprReturn { namespace NonConstExprCtor { struct T { constexpr T(const int &r) : - r(r) { // expected-note 2{{reference to temporary cannot be used to initialize a member in a constant expression}} + r(r) { } const int &r; }; constexpr int n = 0; constexpr T t1(n); // ok - constexpr T t2(0); // expected-error {{must be initialized by a constant expression}} expected-note {{temporary created here}} expected-note {{in call to 'T(0)'}} + constexpr T t2(0); // expected-error {{must be initialized by a constant expression}} expected-note {{temporary created here}} expected-note {{reference to temporary is not a constant expression}} struct S { - int n : T(4).r; // expected-error {{constant expression}} expected-note {{temporary created here}} expected-note {{in call to 'T(4)'}} + int n : T(4).r; // ok }; } @@ -176,12 +174,12 @@ namespace UndefinedBehavior { struct S { int m; }; - constexpr S s = { 5 }; // expected-note {{declared here}} + constexpr S s = { 5 }; constexpr const int *p = &s.m + 1; constexpr const int &f(const int *q) { - return q[0]; // expected-note {{dereferenced pointer past the end of subobject of 's' is not a constant expression}} + return q[0]; } - constexpr int n = (f(p), 0); // expected-error {{constant expression}} expected-note {{in call to 'f(&s.m + 1)'}} + constexpr int n = (f(p), 0); // ok struct T { int n : f(p); // expected-error {{not an integral constant expression}} expected-note {{read of dereferenced one-past-the-end pointer}} }; diff --git a/clang/test/SemaCXX/constant-expression-cxx11.cpp b/clang/test/SemaCXX/constant-expression-cxx11.cpp index 58f36fdf9c8..aa4031189d8 100644 --- a/clang/test/SemaCXX/constant-expression-cxx11.cpp +++ b/clang/test/SemaCXX/constant-expression-cxx11.cpp @@ -190,26 +190,21 @@ namespace StaticMemberFunction { namespace ParameterScopes { const int k = 42; - 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 &ObscureTheTruth(const int &a) { return a; } 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)'}} + return ObscureTheTruth(b ? a : k); } static_assert(MaybeReturnJunk(false, 0) == 42, ""); // ok - constexpr int a = MaybeReturnJunk(true, 0); // expected-error {{constant expression}} expected-note {{in call to 'MaybeReturnJunk(1, 0)'}} + constexpr int a = MaybeReturnJunk(true, 0); // expected-error {{constant expression}} expected-note {{read of variable whose lifetime has ended}} - 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); // expected-note {{in call to 'ObscureTheTruth(a)'}} + constexpr const int MaybeReturnNonstaticRef(bool b, const int a) { + return ObscureTheTruth(b ? a : k); } static_assert(MaybeReturnNonstaticRef(false, 0) == 42, ""); // ok - constexpr int b = MaybeReturnNonstaticRef(true, 0); // expected-error {{constant expression}} expected-note {{in call to 'MaybeReturnNonstaticRef(1, 0)'}} + constexpr int b = MaybeReturnNonstaticRef(true, 0); // ok constexpr int InternalReturnJunk(int n) { - // TODO: We could reject this: it never produces a constant expression. - // However, we currently don't evaluate function calls while testing for - // potential constant expressions, for performance. - return MaybeReturnJunk(true, n); // expected-note {{in call to 'MaybeReturnJunk(1, 0)'}} + return MaybeReturnJunk(true, n); // expected-note {{read of variable whose lifetime has ended}} } constexpr int n3 = InternalReturnJunk(0); // expected-error {{must be initialized by a constant expression}} expected-note {{in call to 'InternalReturnJunk(0)'}} @@ -528,10 +523,10 @@ struct D { static_assert(D().c.n == 42, ""); struct E { - constexpr E() : p(&p) {} // expected-note {{pointer to subobject of temporary cannot be used to initialize a member in a constant expression}} + constexpr E() : p(&p) {} void *p; }; -constexpr const E &e1 = E(); // expected-error {{constant expression}} expected-note {{in call to 'E()'}} expected-note {{temporary created here}} +constexpr const E &e1 = E(); // expected-error {{constant expression}} expected-note {{reference to temporary is not a constant expression}} 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. constexpr E e2 = E(); @@ -1158,3 +1153,19 @@ namespace Fold { #undef fold } + +namespace DR1454 { + +constexpr const int &f(const int &n) { return n; } +constexpr int k1 = f(0); // ok + +struct Wrap { + const int &value; +}; +constexpr const Wrap &g(const Wrap &w) { return w; } +constexpr int k2 = g({0}).value; // ok + +constexpr const int &i = 0; // expected-error {{constant expression}} expected-note {{temporary}} expected-note 2{{here}} +constexpr const int j = i; // expected-error {{constant expression}} expected-note {{initializer of 'i' is not a constant expression}} + +} diff --git a/clang/test/SemaCXX/constexpr-turing.cpp b/clang/test/SemaCXX/constexpr-turing.cpp new file mode 100644 index 00000000000..c5153788adf --- /dev/null +++ b/clang/test/SemaCXX/constexpr-turing.cpp @@ -0,0 +1,55 @@ +// RUN: %clang_cc1 -verify -std=c++11 %s + +// A direct proof that constexpr is Turing-complete, once DR1454 is implemented. + +const unsigned halt = (unsigned)-1; + +enum Dir { L, R }; +struct Action { + bool tape; + Dir dir; + unsigned next; +}; +using State = Action[2]; + +// An infinite tape! +struct Tape { + constexpr Tape() : l(0), val(false), r(0) {} + constexpr Tape(const Tape &old, bool write) : + l(old.l), val(write), r(old.r) {} + constexpr Tape(const Tape &old, Dir dir) : + l(dir == L ? old.l ? old.l->l : 0 : &old), + val(dir == L ? old.l ? old.l->val : false + : old.r ? old.r->val : false), + r(dir == R ? old.r ? old.r->r : 0 : &old) {} + const Tape *l; + bool val; + const Tape *r; +}; +constexpr Tape update(const Tape &old, bool write) { return Tape(old, write); } +constexpr Tape move(const Tape &old, Dir dir) { return Tape(old, dir); } + +// Run turing machine 'tm' on tape 'tape' from state 'state'. Return number of +// steps taken until halt. +constexpr unsigned run(const State *tm, const Tape &tape, unsigned state) { + return state == halt ? 1 : + run(tm, move(update(tape, tm[state][tape.val].tape), + tm[state][tape.val].dir), + tm[state][tape.val].next) + 1; +} + +// 3-state busy beaver. 14 steps. +constexpr State bb3[] = { + { { true, R, 1 }, { true, L, 2 } }, + { { true, L, 0 }, { true, R, 1 } }, + { { true, L, 1 }, { true, R, halt } } +}; +static_assert(run(bb3, Tape(), 0) == 14, ""); + +// 4-state busy beaver. 108 steps. +constexpr State bb4[] = { + { { true, R, 1 }, { true, L, 1 } }, + { { true, L, 0 }, { false, L, 2 } }, + { { true, R, halt }, { true, L, 3 } }, + { { true, R, 3 }, { false, R, 0 } } }; +static_assert(run(bb4, Tape(), 0) == 108, ""); |