The 'constexpr implies const' rule for non-static member functions is gone in
C++1y, so stop adding the 'const' there. Provide a compatibility warning for code relying on this in C++11, with a fix-it hint. Update our lazily-written tests to add the const, except for those ones which were testing our implementation of this rule. llvm-svn: 179969
This commit is contained in:
parent
3eab2e43d2
commit
034185c2f9
|
@ -1550,6 +1550,11 @@ def note_for_range_begin_end : Note<
|
|||
def warn_cxx98_compat_constexpr : Warning<
|
||||
"'constexpr' specifier is incompatible with C++98">,
|
||||
InGroup<CXX98Compat>, DefaultIgnore;
|
||||
// FIXME: Maybe this should also go in -Wc++1y-compat?
|
||||
def warn_cxx1y_compat_constexpr_not_const : Warning<
|
||||
"'constexpr' non-static member function will not be implicitly 'const' "
|
||||
"in C++1y; add 'const' to avoid a change in behavior">,
|
||||
InGroup<DiagGroup<"constexpr-not-const">>;
|
||||
def err_invalid_constexpr : Error<
|
||||
"%select{function parameter|typedef|non-static data member}0 "
|
||||
"cannot be constexpr">;
|
||||
|
|
|
@ -5015,7 +5015,8 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
|
|||
Sema::CXXThisScopeRAII ThisScope(Actions,
|
||||
dyn_cast<CXXRecordDecl>(Actions.CurContext),
|
||||
DS.getTypeQualifiers() |
|
||||
(D.getDeclSpec().isConstexprSpecified()
|
||||
(D.getDeclSpec().isConstexprSpecified() &&
|
||||
!getLangOpts().CPlusPlus1y
|
||||
? Qualifiers::Const : 0),
|
||||
IsCXX11MemberFunction);
|
||||
|
||||
|
|
|
@ -6726,9 +6726,12 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
|
|||
//
|
||||
// This needs to be delayed until we know whether this is an out-of-line
|
||||
// definition of a static member function.
|
||||
//
|
||||
// This rule is not present in C++1y, so we produce a backwards
|
||||
// compatibility warning whenever it happens in C++11.
|
||||
CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewFD);
|
||||
if (MD && MD->isConstexpr() && !MD->isStatic() &&
|
||||
!isa<CXXConstructorDecl>(MD) &&
|
||||
if (!getLangOpts().CPlusPlus1y && MD && MD->isConstexpr() &&
|
||||
!MD->isStatic() && !isa<CXXConstructorDecl>(MD) &&
|
||||
(MD->getTypeQualifiers() & Qualifiers::Const) == 0) {
|
||||
CXXMethodDecl *OldMD = dyn_cast_or_null<CXXMethodDecl>(OldDecl);
|
||||
if (FunctionTemplateDecl *OldTD =
|
||||
|
@ -6743,6 +6746,18 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
|
|||
ArrayRef<QualType>(FPT->arg_type_begin(),
|
||||
FPT->getNumArgs()),
|
||||
EPI));
|
||||
|
||||
// Warn that we did this, if we're not performing template instantiation.
|
||||
// In that case, we'll have warned already when the template was defined.
|
||||
if (ActiveTemplateInstantiations.empty()) {
|
||||
SourceLocation AddConstLoc;
|
||||
if (FunctionTypeLoc FTL = MD->getTypeSourceInfo()->getTypeLoc()
|
||||
.IgnoreParens().getAs<FunctionTypeLoc>())
|
||||
AddConstLoc = PP.getLocForEndOfToken(FTL.getRParenLoc());
|
||||
|
||||
Diag(MD->getLocation(), diag::warn_cxx1y_compat_constexpr_not_const)
|
||||
<< FixItHint::CreateInsertion(AddConstLoc, " const");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -32,13 +32,13 @@ constexpr ClassTemp<int> classtemplate2[] = {};
|
|||
|
||||
// - it has a trivial destructor
|
||||
struct UserProvDtor {
|
||||
constexpr int f(); // expected-error {{non-literal type 'UserProvDtor' cannot have constexpr members}}
|
||||
constexpr int f() const; // expected-error {{non-literal type 'UserProvDtor' cannot have constexpr members}}
|
||||
~UserProvDtor(); // expected-note {{has a user-provided destructor}}
|
||||
};
|
||||
|
||||
struct NonTrivDtor {
|
||||
constexpr NonTrivDtor();
|
||||
constexpr int f(); // expected-error {{non-literal type 'NonTrivDtor' cannot have constexpr members}}
|
||||
constexpr int f() const; // expected-error {{non-literal type 'NonTrivDtor' cannot have constexpr members}}
|
||||
virtual ~NonTrivDtor() = default; // expected-note {{has a non-trivial destructor}} expected-note {{because it is virtual}}
|
||||
};
|
||||
struct NonTrivDtorBase {
|
||||
|
@ -71,11 +71,11 @@ struct CtorTemplate {
|
|||
};
|
||||
struct CopyCtorOnly { // expected-note {{'CopyCtorOnly' is not literal because it is not an aggregate and has no constexpr constructors other than copy or move constructors}}
|
||||
constexpr CopyCtorOnly(CopyCtorOnly&);
|
||||
constexpr int f(); // expected-error {{non-literal type 'CopyCtorOnly' cannot have constexpr members}}
|
||||
constexpr int f() const; // expected-error {{non-literal type 'CopyCtorOnly' cannot have constexpr members}}
|
||||
};
|
||||
struct MoveCtorOnly { // expected-note {{no constexpr constructors other than copy or move constructors}}
|
||||
constexpr MoveCtorOnly(MoveCtorOnly&&);
|
||||
constexpr int f(); // expected-error {{non-literal type 'MoveCtorOnly' cannot have constexpr members}}
|
||||
constexpr int f() const; // expected-error {{non-literal type 'MoveCtorOnly' cannot have constexpr members}}
|
||||
};
|
||||
template<typename T>
|
||||
struct CtorArg {
|
||||
|
@ -104,7 +104,7 @@ constexpr int f(NonLitMember) {} // expected-error {{1st parameter type 'NonLitM
|
|||
struct NonLitBase :
|
||||
S { // expected-note {{base class 'S' of non-literal type}}
|
||||
constexpr NonLitBase();
|
||||
constexpr int f() { return 0; } // expected-error {{non-literal type 'NonLitBase' cannot have constexpr members}}
|
||||
constexpr int f() const { return 0; } // expected-error {{non-literal type 'NonLitBase' cannot have constexpr members}}
|
||||
};
|
||||
struct LitMemBase : Agg {
|
||||
Agg agg;
|
||||
|
|
|
@ -71,7 +71,7 @@ struct ConstexprDtor {
|
|||
template <typename T> constexpr T ft(T t) { return t; }
|
||||
template <typename T> T gt(T t) { return t; }
|
||||
struct S {
|
||||
template<typename T> constexpr T f();
|
||||
template<typename T> constexpr T f(); // expected-warning {{C++1y}}
|
||||
template<typename T> T g() const;
|
||||
};
|
||||
|
||||
|
@ -81,7 +81,7 @@ template <> char ft(char c) { return c; } // expected-note {{previous}}
|
|||
template <> constexpr char ft(char nl); // expected-error {{constexpr declaration of 'ft<char>' follows non-constexpr declaration}}
|
||||
template <> constexpr int gt(int nl) { return nl; }
|
||||
template <> notlit S::f() const { return notlit(); }
|
||||
template <> constexpr int S::g() { return 0; } // expected-note {{previous}}
|
||||
template <> constexpr int S::g() { return 0; } // expected-note {{previous}} expected-warning {{C++1y}}
|
||||
template <> int S::g() const; // expected-error {{non-constexpr declaration of 'g<int>' follows constexpr declaration}}
|
||||
// specializations can drop the 'constexpr' but not the implied 'const'.
|
||||
template <> char S::g() { return 0; } // expected-error {{no function template matches}}
|
||||
|
|
|
@ -28,41 +28,41 @@ struct SS : S {
|
|||
// constraints:
|
||||
struct T : SS, NonLiteral { // expected-note {{base class 'NonLiteral' of non-literal type}}
|
||||
constexpr T();
|
||||
constexpr int f(); // expected-error {{non-literal type 'T' cannot have constexpr members}}
|
||||
constexpr int f() const; // expected-error {{non-literal type 'T' cannot have constexpr members}}
|
||||
|
||||
// - it shall not be virtual;
|
||||
virtual constexpr int ExplicitlyVirtual() { return 0; } // expected-error {{virtual function cannot be constexpr}}
|
||||
virtual constexpr int ExplicitlyVirtual() const { return 0; } // expected-error {{virtual function cannot be constexpr}}
|
||||
|
||||
constexpr int ImplicitlyVirtual() { return 0; } // expected-error {{virtual function cannot be constexpr}}
|
||||
constexpr int ImplicitlyVirtual() const { return 0; } // expected-error {{virtual function cannot be constexpr}}
|
||||
|
||||
// - its return type shall be a literal type;
|
||||
constexpr NonLiteral NonLiteralReturn() { return {}; } // expected-error {{constexpr function's return type 'NonLiteral' is not a literal type}}
|
||||
constexpr void VoidReturn() { return; } // expected-error {{constexpr function's return type 'void' is not a literal type}}
|
||||
constexpr NonLiteral NonLiteralReturn() const { return {}; } // expected-error {{constexpr function's return type 'NonLiteral' is not a literal type}}
|
||||
constexpr void VoidReturn() const { return; } // expected-error {{constexpr function's return type 'void' is not a literal type}}
|
||||
constexpr ~T(); // expected-error {{destructor cannot be marked constexpr}}
|
||||
typedef NonLiteral F();
|
||||
typedef NonLiteral F() const;
|
||||
constexpr F NonLiteralReturn2; // ok until definition
|
||||
|
||||
// - each of its parameter types shall be a literal type;
|
||||
constexpr int NonLiteralParam(NonLiteral) { return 0; } // expected-error {{constexpr function's 1st parameter type 'NonLiteral' is not a literal type}}
|
||||
typedef int G(NonLiteral);
|
||||
constexpr int NonLiteralParam(NonLiteral) const { return 0; } // expected-error {{constexpr function's 1st parameter type 'NonLiteral' is not a literal type}}
|
||||
typedef int G(NonLiteral) const;
|
||||
constexpr G NonLiteralParam2; // ok until definition
|
||||
|
||||
// - its function-body shall be = delete, = default,
|
||||
constexpr int Deleted() = delete;
|
||||
constexpr int Deleted() const = delete;
|
||||
// It's not possible for the function-body to legally be "= default" here.
|
||||
// Other than constructors, only the copy- and move-assignment operators and
|
||||
// destructor can be defaulted. Destructors can't be constexpr since they
|
||||
// don't have a literal return type. Defaulted assignment operators can't be
|
||||
// constexpr since they can't be const.
|
||||
constexpr T &operator=(const T&) = default; // expected-error {{an explicitly-defaulted copy assignment operator may not have 'const', 'constexpr' or 'volatile' qualifiers}}
|
||||
constexpr T &operator=(const T&) = default; // expected-error {{an explicitly-defaulted copy assignment operator may not have 'const', 'constexpr' or 'volatile' qualifiers}} expected-warning {{C++1y}}
|
||||
};
|
||||
struct U {
|
||||
constexpr U SelfReturn();
|
||||
constexpr int SelfParam(U);
|
||||
constexpr U SelfReturn() const;
|
||||
constexpr int SelfParam(U) const;
|
||||
};
|
||||
|
||||
struct V : virtual U { // expected-note {{here}}
|
||||
constexpr int F() { return 0; } // expected-error {{constexpr member function not allowed in struct with virtual base class}}
|
||||
constexpr int F() const { return 0; } // expected-error {{constexpr member function not allowed in struct with virtual base class}}
|
||||
};
|
||||
|
||||
// or a compound-statememt that contains only
|
||||
|
|
|
@ -102,7 +102,7 @@ X x = cmin(X(), X()); // ok, not constexpr
|
|||
template<typename T>
|
||||
struct Y {
|
||||
constexpr Y() {}
|
||||
constexpr int get() { return T(); }
|
||||
constexpr int get() { return T(); } // expected-warning {{C++1y}}
|
||||
};
|
||||
struct Z { operator int(); };
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ struct S {
|
|||
struct T {};
|
||||
|
||||
template<typename T> struct ImplicitVirtualFromDependentBase : T {
|
||||
constexpr int ImplicitlyVirtual() { return 0; }
|
||||
constexpr int ImplicitlyVirtual() const { return 0; }
|
||||
};
|
||||
|
||||
constexpr int a = ImplicitVirtualFromDependentBase<S>().ImplicitlyVirtual(); // expected-error {{constant expression}} expected-note {{cannot evaluate virtual function call}}
|
||||
|
@ -32,7 +32,7 @@ constexpr int b = ImplicitVirtualFromDependentBase<T>().ImplicitlyVirtual(); //
|
|||
constexpr int c = ImplicitVirtualFromDependentBase<S>().ImplicitVirtualFromDependentBase<S>::ImplicitlyVirtual();
|
||||
|
||||
template<typename R> struct ConstexprMember {
|
||||
constexpr R F() { return 0; }
|
||||
constexpr R F() const { return 0; }
|
||||
};
|
||||
constexpr int d = ConstexprMember<int>().F(); // ok
|
||||
constexpr int e = ConstexprMember<NonLiteral>().F(); // expected-error {{constant expression}}
|
||||
|
|
|
@ -3,13 +3,13 @@
|
|||
using size_t = decltype(sizeof(int));
|
||||
|
||||
struct S {
|
||||
constexpr int f();
|
||||
constexpr int f(); // expected-warning {{C++1y}}
|
||||
constexpr int g() const;
|
||||
constexpr int h();
|
||||
constexpr int h(); // expected-warning {{C++1y}}
|
||||
int h();
|
||||
static constexpr int Sf();
|
||||
/*static*/ constexpr void *operator new(size_t) noexcept;
|
||||
template<typename T> constexpr T tm();
|
||||
template<typename T> constexpr T tm(); // expected-warning {{C++1y}}
|
||||
template<typename T> static constexpr T ts();
|
||||
};
|
||||
|
||||
|
@ -26,12 +26,12 @@ void f(const S &s) {
|
|||
}
|
||||
|
||||
constexpr int S::f() const { return 0; }
|
||||
constexpr int S::g() { return 1; }
|
||||
constexpr int S::h() { return 0; }
|
||||
constexpr int S::g() { return 1; } // expected-warning {{C++1y}}
|
||||
constexpr int S::h() { return 0; } // expected-warning {{C++1y}}
|
||||
int S::h() { return 0; }
|
||||
constexpr int S::Sf() { return 2; }
|
||||
constexpr void *S::operator new(size_t) noexcept { return 0; }
|
||||
template<typename T> constexpr T S::tm() { return T(); }
|
||||
template<typename T> constexpr T S::tm() { return T(); } // expected-warning {{C++1y}}
|
||||
template<typename T> constexpr T S::ts() { return T(); }
|
||||
|
||||
namespace std_example {
|
||||
|
@ -39,7 +39,7 @@ namespace std_example {
|
|||
class debug_flag { // expected-note {{not an aggregate and has no constexpr constructors}}
|
||||
public:
|
||||
explicit debug_flag(bool);
|
||||
constexpr bool is_on(); // expected-error {{non-literal type 'std_example::debug_flag' cannot have constexpr members}}
|
||||
constexpr bool is_on() const; // expected-error {{non-literal type 'std_example::debug_flag' cannot have constexpr members}}
|
||||
private:
|
||||
bool flag;
|
||||
};
|
||||
|
|
|
@ -76,7 +76,7 @@ namespace libcxx_example {
|
|||
template<typename T> struct swappable {
|
||||
typedef decltype(swap(declval<T&>(), declval<T&>())) type;
|
||||
static const bool value = !is_same<type, nat>::value;
|
||||
constexpr operator bool() { return value; }
|
||||
constexpr operator bool() const { return value; }
|
||||
};
|
||||
|
||||
static_assert(swappable<int>(), "");
|
||||
|
|
|
@ -2,15 +2,15 @@
|
|||
|
||||
struct S {
|
||||
constexpr S(bool b) : b(b) {}
|
||||
constexpr explicit operator bool() { return b; }
|
||||
constexpr explicit operator bool() const { return b; }
|
||||
bool b;
|
||||
};
|
||||
struct T {
|
||||
constexpr operator int() { return 1; }
|
||||
constexpr operator int() const { return 1; }
|
||||
};
|
||||
struct U {
|
||||
constexpr operator int() { return 1; } // expected-note {{candidate}}
|
||||
constexpr operator long() { return 0; } // expected-note {{candidate}}
|
||||
constexpr operator int() const { return 1; } // expected-note {{candidate}}
|
||||
constexpr operator long() const { return 0; } // expected-note {{candidate}}
|
||||
};
|
||||
|
||||
static_assert(S(true), "");
|
||||
|
|
|
@ -6,8 +6,8 @@ struct S1 {
|
|||
constexpr S1() = default; // expected-error {{defaulted definition of default constructor is not constexpr}}
|
||||
constexpr S1(const S1&) = default;
|
||||
constexpr S1(S1&&) = default;
|
||||
constexpr S1 &operator=(const S1&) = default; // expected-error {{explicitly-defaulted copy assignment operator may not have}}
|
||||
constexpr S1 &operator=(S1&&) = default; // expected-error {{explicitly-defaulted move assignment operator may not have}}
|
||||
constexpr S1 &operator=(const S1&) const = default; // expected-error {{explicitly-defaulted copy assignment operator may not have}}
|
||||
constexpr S1 &operator=(S1&&) const = default; // expected-error {{explicitly-defaulted move assignment operator may not have}}
|
||||
constexpr ~S1() = default; // expected-error {{destructor cannot be marked constexpr}}
|
||||
int n;
|
||||
};
|
||||
|
|
|
@ -24,8 +24,8 @@ struct S {
|
|||
int a, b;
|
||||
};
|
||||
struct T {
|
||||
constexpr int operator=(S s) { return s.a; }
|
||||
constexpr int operator+=(S s) { return s.b; }
|
||||
constexpr int operator=(S s) const { return s.a; }
|
||||
constexpr int operator+=(S s) const { return s.b; }
|
||||
};
|
||||
static_assert((T() = {4, 9}) == 4, "");
|
||||
static_assert((T() += {4, 9}) == 9, "");
|
||||
|
|
|
@ -118,7 +118,7 @@ namespace IncompleteClassTypeAddr {
|
|||
constexpr S (*p2)[] = &sArr; // ok
|
||||
|
||||
struct S {
|
||||
constexpr S *operator&() { return nullptr; }
|
||||
constexpr S *operator&() const { return nullptr; }
|
||||
};
|
||||
constexpr S *q = &s; // ok
|
||||
static_assert(!q, "");
|
||||
|
@ -205,7 +205,7 @@ namespace UndefinedBehavior {
|
|||
constexpr const int &np = (*(int(*)[4])nullptr)[2]; // expected-error {{constant expression}} expected-note {{cannot access array element of null pointer}}
|
||||
|
||||
struct C {
|
||||
constexpr int f() { return 0; }
|
||||
constexpr int f() const { return 0; }
|
||||
} constexpr c = C();
|
||||
constexpr int k1 = c.f(); // ok
|
||||
constexpr int k2 = ((C*)nullptr)->f(); // expected-error {{constant expression}} expected-note {{cannot call member function on null pointer}}
|
||||
|
@ -481,14 +481,14 @@ namespace UnspecifiedRelations {
|
|||
public:
|
||||
constexpr A() : a(0), b(0) {}
|
||||
int a;
|
||||
constexpr bool cmp() { return &a < &b; } // expected-error {{constexpr function never produces a constant expression}} expected-note {{comparison of address of fields 'a' and 'b' of 'A' with differing access specifiers (public vs private) has unspecified value}}
|
||||
constexpr bool cmp() const { return &a < &b; } // expected-error {{constexpr function never produces a constant expression}} expected-note {{comparison of address of fields 'a' and 'b' of 'A' with differing access specifiers (public vs private) has unspecified value}}
|
||||
private:
|
||||
int b;
|
||||
};
|
||||
class B {
|
||||
public:
|
||||
A a;
|
||||
constexpr bool cmp() { return &a.a < &b.a; } // expected-error {{constexpr function never produces a constant expression}} expected-note {{comparison of address of fields 'a' and 'b' of 'B' with differing access specifiers (public vs protected) has unspecified value}}
|
||||
constexpr bool cmp() const { return &a.a < &b.a; } // expected-error {{constexpr function never produces a constant expression}} expected-note {{comparison of address of fields 'a' and 'b' of 'B' with differing access specifiers (public vs protected) has unspecified value}}
|
||||
protected:
|
||||
A b;
|
||||
};
|
||||
|
|
|
@ -101,7 +101,7 @@ int n = Val<bool, &S::operator int>::value; // expected-error {{conversion from
|
|||
|
||||
namespace NonConstLValue {
|
||||
struct S {
|
||||
constexpr operator int() { return 10; }
|
||||
constexpr operator int() const { return 10; }
|
||||
};
|
||||
S s; // not constexpr
|
||||
// Under the FDIS, this is not a converted constant expression.
|
||||
|
|
|
@ -7,8 +7,8 @@ namespace std_example {
|
|||
|
||||
struct A {
|
||||
constexpr A(int i) : val(i) { }
|
||||
constexpr operator int() { return val; }
|
||||
constexpr operator long() { return 43; }
|
||||
constexpr operator int() const { return val; }
|
||||
constexpr operator long() const { return 43; }
|
||||
private:
|
||||
int val;
|
||||
};
|
||||
|
@ -21,17 +21,17 @@ int ary[a]; // expected-error {{size of array has non-integer type 'const std_ex
|
|||
|
||||
struct OK {
|
||||
constexpr OK() {}
|
||||
constexpr operator int() { return 8; }
|
||||
constexpr operator int() const { return 8; }
|
||||
} constexpr ok;
|
||||
extern struct Incomplete incomplete; // expected-note 4{{forward decl}}
|
||||
struct Explicit {
|
||||
constexpr Explicit() {}
|
||||
constexpr explicit operator int() { return 4; } // expected-note 4{{here}}
|
||||
constexpr explicit operator int() const { return 4; } // expected-note 4{{here}}
|
||||
} constexpr expl;
|
||||
struct Ambiguous {
|
||||
constexpr Ambiguous() {}
|
||||
constexpr operator int() { return 2; } // expected-note 4{{here}}
|
||||
constexpr operator long() { return 1; } // expected-note 4{{here}}
|
||||
constexpr operator int() const { return 2; } // expected-note 4{{here}}
|
||||
constexpr operator long() const { return 1; } // expected-note 4{{here}}
|
||||
} constexpr ambig;
|
||||
|
||||
constexpr int test_ok = ok; // ok
|
||||
|
|
|
@ -3,12 +3,12 @@
|
|||
|
||||
struct Value {
|
||||
constexpr Value(int n) : n(n) {}
|
||||
constexpr operator short() { return n; }
|
||||
constexpr operator short() const { return n; }
|
||||
int n;
|
||||
};
|
||||
enum E { E0, E1 };
|
||||
struct Alt {
|
||||
constexpr operator E() { return E0; }
|
||||
constexpr operator E() const { return E0; }
|
||||
};
|
||||
|
||||
constexpr short s = Alt();
|
||||
|
|
|
@ -193,18 +193,18 @@ namespace PacksAtDifferentLevels {
|
|||
template<typename...A>
|
||||
struct X6 {
|
||||
template<typename...B>
|
||||
constexpr auto f1(A ...a) -> decltype(g(A(a + B())...)) { return g(A(a + B())...); }
|
||||
constexpr auto f1(A ...a) const -> decltype(g(A(a + B())...)) { return g(A(a + B())...); }
|
||||
|
||||
template<typename...B>
|
||||
constexpr auto f2(A ...a, B ...b) -> decltype(g((&a)[b] ...)) { return g((&a)[b] ...); } // expected-note {{past-the-end}}
|
||||
constexpr auto f2(A ...a, B ...b) const -> decltype(g((&a)[b] ...)) { return g((&a)[b] ...); } // expected-note {{past-the-end}}
|
||||
|
||||
template<typename...B> struct Inner {
|
||||
template<typename...C>
|
||||
constexpr auto f(A ...a, B ...b, C ...c) -> decltype(g(a+b+c...)) { return g(a+b+c...); }
|
||||
constexpr auto f(A ...a, B ...b, C ...c) const -> decltype(g(a+b+c...)) { return g(a+b+c...); }
|
||||
};
|
||||
};
|
||||
struct A { constexpr operator int() { return 2; } };
|
||||
struct B { constexpr operator int() { return 1; } };
|
||||
struct A { constexpr operator int() const { return 2; } };
|
||||
struct B { constexpr operator int() const { return 1; } };
|
||||
|
||||
static_assert(X6<unsigned char, int>().f1<A, B>(255, 1) == 12, "");
|
||||
static_assert(X6<int, int>().f2(3, 4, 0, 0) == 34, "");
|
||||
|
|
|
@ -9,7 +9,7 @@ template inline void X<int>::f(); // expected-error{{explicit instantiation cann
|
|||
|
||||
template<typename T>
|
||||
struct Y {
|
||||
constexpr int f() { return 0; }
|
||||
constexpr int f() { return 0; } // expected-warning{{C++1y}}
|
||||
};
|
||||
|
||||
template constexpr int Y<int>::f() const; // expected-error{{explicit instantiation cannot be 'constexpr'}}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
// RUN: %clang_cc1 -verify -std=c++11 %s
|
||||
// RUN: cp %s %t
|
||||
// RUN: %clang_cc1 -x c++ -std=c++11 -fixit %t
|
||||
// RUN: %clang_cc1 -Wall -pedantic-errors -Werror -x c++ -std=c++11 %t
|
||||
// RUN: %clang_cc1 -Wall -pedantic-errors -Werror -x c++ -std=c++1y %t
|
||||
|
||||
// This is a test of the code modification hints for C++1y-compatibility problems.
|
||||
|
||||
struct S {
|
||||
constexpr int &f(); // expected-warning {{'constexpr' non-static member function will not be implicitly 'const' in C++1y; add 'const' to avoid a change in behavior}}
|
||||
int &f();
|
||||
};
|
|
@ -38,8 +38,8 @@ namespace bitfield {
|
|||
constexpr T() {}
|
||||
constexpr T(int) {}
|
||||
constexpr T(T, T, T, T) {}
|
||||
constexpr T operator=(T) { return *this; }
|
||||
constexpr operator int() { return 4; }
|
||||
constexpr T operator=(T) const { return *this; }
|
||||
constexpr operator int() const { return 4; }
|
||||
};
|
||||
constexpr T a, b, c, d;
|
||||
|
||||
|
@ -68,7 +68,7 @@ namespace bitfield {
|
|||
};
|
||||
|
||||
struct U {
|
||||
constexpr operator T() { return T(); } // expected-note 2{{candidate}}
|
||||
constexpr operator T() const { return T(); } // expected-note 2{{candidate}}
|
||||
};
|
||||
// This could be a bit-field.
|
||||
struct S7 {
|
||||
|
|
|
@ -46,7 +46,7 @@ using PR14855 = int S::; // expected-error {{expected ';' after alias declaratio
|
|||
// a constexpr function.
|
||||
struct ConstexprTrailingReturn {
|
||||
int n;
|
||||
constexpr auto f() -> decltype((n));
|
||||
constexpr auto f() const -> decltype((n));
|
||||
};
|
||||
constexpr const int &ConstexprTrailingReturn::f() const { return n; }
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ template<typename T, size_t N> constexpr T *begin(T (&xs)[N]) { return xs; }
|
|||
template<typename T, size_t N> constexpr T *end(T (&xs)[N]) { return xs + N; }
|
||||
|
||||
struct MemberZero {
|
||||
constexpr int zero() { return 0; }
|
||||
constexpr int zero() const { return 0; }
|
||||
};
|
||||
|
||||
namespace DerivedToVBaseCast {
|
||||
|
@ -486,7 +486,7 @@ static_assert(CountZero(arr, arr + 40) == 36, "");
|
|||
struct ArrayElem {
|
||||
constexpr ArrayElem() : n(0) {}
|
||||
int n;
|
||||
constexpr int f() { return n; }
|
||||
constexpr int f() const { return n; }
|
||||
};
|
||||
struct ArrayRVal {
|
||||
constexpr ArrayRVal() {}
|
||||
|
@ -731,14 +731,14 @@ namespace ConversionOperators {
|
|||
|
||||
struct T {
|
||||
constexpr T(int n) : k(5*n - 3) {}
|
||||
constexpr operator int() { return k; }
|
||||
constexpr operator int() const { return k; }
|
||||
int k;
|
||||
};
|
||||
|
||||
struct S {
|
||||
constexpr S(int n) : k(2*n + 1) {}
|
||||
constexpr operator int() { return k; }
|
||||
constexpr operator T() { return T(k); }
|
||||
constexpr operator int() const { return k; }
|
||||
constexpr operator T() const { return T(k); }
|
||||
int k;
|
||||
};
|
||||
|
||||
|
@ -750,7 +750,7 @@ static_assert(check(S(5), 11), "");
|
|||
namespace PR14171 {
|
||||
|
||||
struct X {
|
||||
constexpr (operator int)() { return 0; }
|
||||
constexpr (operator int)() const { return 0; }
|
||||
};
|
||||
static_assert(X() == 0, "");
|
||||
|
||||
|
@ -764,13 +764,13 @@ namespace Temporaries {
|
|||
|
||||
struct S {
|
||||
constexpr S() {}
|
||||
constexpr int f();
|
||||
constexpr int f() const;
|
||||
};
|
||||
struct T : S {
|
||||
constexpr T(int n) : S(), n(n) {}
|
||||
int n;
|
||||
};
|
||||
constexpr int S::f() {
|
||||
constexpr int S::f() const {
|
||||
// 'this' must be the postfix-expression in a class member access expression,
|
||||
// so we can't just use
|
||||
// return static_cast<T*>(this)->n;
|
||||
|
@ -825,7 +825,7 @@ namespace MemberPointer {
|
|||
struct A {
|
||||
constexpr A(int n) : n(n) {}
|
||||
int n;
|
||||
constexpr int f() { return n + 3; }
|
||||
constexpr int f() const { return n + 3; }
|
||||
};
|
||||
constexpr A a(7);
|
||||
static_assert(A(5).*&A::n == 5, "");
|
||||
|
@ -836,7 +836,7 @@ namespace MemberPointer {
|
|||
struct B : A {
|
||||
constexpr B(int n, int m) : A(n), m(m) {}
|
||||
int m;
|
||||
constexpr int g() { return n + m + 1; }
|
||||
constexpr int g() const { return n + m + 1; }
|
||||
};
|
||||
constexpr B b(9, 13);
|
||||
static_assert(B(4, 11).*&A::n == 4, "");
|
||||
|
@ -857,7 +857,7 @@ namespace MemberPointer {
|
|||
m(m), n(n), pf(pf), pn(pn) {}
|
||||
constexpr S() : m(), n(), pf(&S::f), pn(&S::n) {}
|
||||
|
||||
constexpr int f() { return this->*pn; }
|
||||
constexpr int f() const { return this->*pn; }
|
||||
virtual int g() const;
|
||||
|
||||
int m, n;
|
||||
|
@ -938,7 +938,7 @@ namespace ArrayBaseDerived {
|
|||
};
|
||||
struct Derived : Base {
|
||||
constexpr Derived() {}
|
||||
constexpr const int *f() { return &n; }
|
||||
constexpr const int *f() const { return &n; }
|
||||
};
|
||||
|
||||
constexpr Derived a[10];
|
||||
|
@ -1038,7 +1038,7 @@ static_assert(makeComplexWrap(1,0) != complex(0, 1), "");
|
|||
}
|
||||
|
||||
namespace PR11595 {
|
||||
struct A { constexpr bool operator==(int x) { return true; } };
|
||||
struct A { constexpr bool operator==(int x) const { return true; } };
|
||||
struct B { B(); A& x; };
|
||||
static_assert(B().x == 3, ""); // expected-error {{constant expression}} expected-note {{non-literal type 'PR11595::B' cannot be used in a constant expression}}
|
||||
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
// RUN: %clang_cc1 -std=c++11 %s -verify
|
||||
// RUN: %clang_cc1 -std=c++1y %s -verify -DCXX1Y
|
||||
|
||||
struct X {
|
||||
constexpr int f(); // @5
|
||||
int f(); // @6
|
||||
};
|
||||
|
||||
#ifdef CXX1Y
|
||||
// FIXME: Detect this situation and provide a better recovery.
|
||||
|
||||
// expected-error@6 {{class member cannot be redeclared}}
|
||||
// expected-note@5 {{previous}}
|
||||
// expected-error@6 {{non-constexpr declaration of 'f' follows constexpr declaration}}
|
||||
// expected-note@5 {{previous}}
|
||||
#else
|
||||
// expected-warning@5 {{'constexpr' non-static member function will not be implicitly 'const' in C++1y; add 'const' to avoid a change in behavior}}
|
||||
#endif
|
|
@ -5,8 +5,8 @@ struct Base {
|
|||
};
|
||||
template<typename T> struct S : Base {
|
||||
enum E : int;
|
||||
constexpr int f();
|
||||
constexpr int g(); // expected-note {{declared here}}
|
||||
constexpr int f() const;
|
||||
constexpr int g() const; // expected-note {{declared here}}
|
||||
void h();
|
||||
};
|
||||
template<> enum S<char>::E : int {}; // expected-note {{enum 'S<char>::E' was explicitly specialized here}}
|
||||
|
@ -16,13 +16,13 @@ template<typename T> enum S<T>::E : int { b = 8 };
|
|||
|
||||
// The unqualified-id here names a member of the non-dependent base class Base
|
||||
// and not the injected enumerator name 'a' from the specialization.
|
||||
template<typename T> constexpr int S<T>::f() { return a; }
|
||||
template<typename T> constexpr int S<T>::f() const { return a; }
|
||||
static_assert(S<char>().f() == 1, "");
|
||||
static_assert(S<int>().f() == 1, "");
|
||||
|
||||
// The unqualified-id here names a member of the current instantiation, which
|
||||
// bizarrely might not exist in some instantiations.
|
||||
template<typename T> constexpr int S<T>::g() { return b; } // expected-error {{enumerator 'b' does not exist in instantiation of 'S<char>'}}
|
||||
template<typename T> constexpr int S<T>::g() const { return b; } // expected-error {{enumerator 'b' does not exist in instantiation of 'S<char>'}}
|
||||
static_assert(S<char>().g() == 1, ""); // expected-note {{here}} expected-error {{not an integral constant expression}} expected-note {{undefined}}
|
||||
static_assert(S<short>().g() == 2, "");
|
||||
static_assert(S<long>().g() == 8, "");
|
||||
|
|
Loading…
Reference in New Issue