diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-01-18 23:55:52 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-01-18 23:55:52 +0000 |
commit | 8ef7b203332b0c8d65876a1f5e6d1db4e6f40e4b (patch) | |
tree | dee9b186a48a66f3c8be5c56c4e774338408bece /test/CXX/expr/expr.const/p3-0x.cpp | |
parent | d6c7c67313634b317a0d63c32be0511a121bb33d (diff) |
constexpr: converted constant expression handling for enumerator values, case
values and non-type template arguments of integral and enumeration types.
This change causes some legal C++98 code to no longer compile in C++11 mode, by
enforcing the C++11 rule that narrowing integral conversions are not permitted
in the final implicit conversion sequence for the above cases.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@148439 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'test/CXX/expr/expr.const/p3-0x.cpp')
-rw-r--r-- | test/CXX/expr/expr.const/p3-0x.cpp | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/test/CXX/expr/expr.const/p3-0x.cpp b/test/CXX/expr/expr.const/p3-0x.cpp new file mode 100644 index 0000000000..6ddd11bcee --- /dev/null +++ b/test/CXX/expr/expr.const/p3-0x.cpp @@ -0,0 +1,110 @@ +// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s + +// A converted constant expression of type T is a core constant expression, +int nonconst = 8; // expected-note 3 {{here}} +enum NonConstE : unsigned char { NCE = nonconst }; // expected-error {{enumerator value is not a constant expression}} expected-note {{read of non-const}} +template<int = nonconst> struct NonConstT {}; // expected-error {{non-type template argument is not a constant expression}} expected-note {{read of non-const}} +void NonConstF() { + switch (nonconst) { + case nonconst: // expected-error {{case value is not a constant expression}} expected-note {{read of non-const}} + break; + } + return; +} + +// implicitly converted to a prvalue of type T, where the converted expression +// is a literal constant expression + +bool a(int n) { + constexpr char vowels[] = "aeiou"; + switch (n) { + case vowels[0]: + case vowels[1]: + case vowels[2]: + case vowels[3]: + case vowels[4]: + static_assert(!vowels[5], "unexpected number of vowels"); + return true; + } + return false; +} + +// and the implicit conversion sequence contains only +// +// user-defined conversions, +struct S { constexpr operator int() const { return 5; } }; +enum E : unsigned char { E5 = S(), E6, E10 = S() * 2, E1 = E5 / 5 }; + +// lvalue-to-rvalue conversions, +const E e10 = E10; +template<E> struct T {}; +T<e10> s10; + +// integral promotions, and +enum class EE { EE32 = ' ', EE65 = 'A', EE1 = (short)1, EE5 = E5 }; + +// integral conversions other than narrowing conversions +int b(unsigned n) { + switch (n) { + case E6: + case EE::EE32: // expected-error {{not implicitly convertible}} + case (int)EE::EE32: + case 1000: + case (long long)1e10: // expected-error {{case value evaluates to 10000000000, which cannot be narrowed to type 'unsigned int'}} + case -3: // expected-error {{case value evaluates to -3, which cannot be narrowed to type 'unsigned int'}} + return n; + } + return 0; +} +enum class EEE : unsigned short { + a = E6, + b = EE::EE32, // expected-error {{not implicitly convertible}} + c = (int)EE::EE32, + d = 1000, + e = 123456, // expected-error {{enumerator value evaluates to 123456, which cannot be narrowed to type 'unsigned short'}} + f = -3 // expected-error {{enumerator value evaluates to -3, which cannot be narrowed to type 'unsigned short'}} +}; +template<unsigned char> using A = int; +using Int = A<E6>; +using Int = A<EE::EE32>; // expected-error {{not implicitly convertible}} +using Int = A<(int)EE::EE32>; +using Int = A<200>; +using Int = A<1000>; // expected-error {{template argument evaluates to 1000, which cannot be narrowed to type 'unsigned char'}} +using Int = A<-3>; // expected-error {{template argument evaluates to -3, which cannot be narrowed to type 'unsigned char'}} + +// Note, conversions from integral or unscoped enumeration types to bool are +// integral conversions as well as boolean conversions. +template<typename T, T v> struct Val { static constexpr T value = v; }; +static_assert(Val<bool, E1>::value == 1, ""); // ok +static_assert(Val<bool, '\0'>::value == 0, ""); // ok +static_assert(Val<bool, U'\1'>::value == 1, ""); // ok +static_assert(Val<bool, E5>::value == 1, ""); // expected-error {{5, which cannot be narrowed to type 'bool'}} + +// (no other conversions are permitted) +using Int = A<1.0>; // expected-error {{conversion from 'double' to 'unsigned char' is not allowed in a converted constant expression}} +enum B : bool { + True = &a, // expected-error {{conversion from 'bool (*)(int)' to 'bool' is not allowed in a converted constant expression}} + False = nullptr // expected-error {{conversion from 'nullptr_t' to 'bool' is not allowed in a converted constant expression}} +}; +void c() { + // Note, promoted type of switch is 'int'. + switch (bool b = a(5)) { // expected-warning {{boolean value}} + case 0.0f: // expected-error {{conversion from 'float' to 'int' is not allowed in a converted constant expression}} + break; + } +} +template<bool B> int f() { return B; } +template int f<&S::operator int>(); // expected-error {{does not refer to a function template}} +template int f<(bool)&S::operator int>(); + +int n = Val<bool, &S::operator int>::value; // expected-error {{conversion from 'int (S::*)() const' to 'bool' is not allowed in a converted constant expression}} + +namespace NonConstLValue { + struct S { + constexpr operator int() { return 10; } + }; + S s; // not constexpr + // Under the FDIS, this is not a converted constant expression. + // Under the new proposed wording, it is. + enum E : char { e = s }; +} |