From 034185c2f9e34c64ef7b3d2703443d7b2f248a81 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Sun, 21 Apr 2013 01:08:50 +0000 Subject: [PATCH] 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 --- .../clang/Basic/DiagnosticSemaKinds.td | 5 ++++ clang/lib/Parse/ParseDecl.cpp | 3 ++- clang/lib/Sema/SemaDecl.cpp | 19 ++++++++++++-- clang/test/CXX/basic/basic.types/p10.cpp | 10 +++---- .../CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp | 4 +-- .../CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp | 26 +++++++++---------- .../CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp | 2 +- .../CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp | 4 +-- .../CXX/dcl.dcl/dcl.spec/dcl.constexpr/p8.cpp | 14 +++++----- .../dcl.type/dcl.type.simple/p5-cxx0x.cpp | 2 +- clang/test/CXX/dcl.dcl/p4-0x.cpp | 8 +++--- .../dcl.fct.def/dcl.fct.def.default/p2.cpp | 4 +-- clang/test/CXX/expr/expr.ass/p9-cxx11.cpp | 4 +-- clang/test/CXX/expr/expr.const/p2-0x.cpp | 8 +++--- clang/test/CXX/expr/expr.const/p3-0x.cpp | 2 +- clang/test/CXX/expr/expr.const/p5-0x.cpp | 12 ++++----- .../stmt.select/stmt.switch/p2-0x.cpp | 4 +-- .../multi-level-substitution.cpp | 10 +++---- .../temp/temp.spec/temp.explicit/p1-0x.cpp | 2 +- clang/test/FixIt/fixit-cxx1y-compat.cpp | 12 +++++++++ clang/test/Parser/cxx0x-ambig.cpp | 6 ++--- clang/test/Parser/cxx0x-decl.cpp | 2 +- .../SemaCXX/constant-expression-cxx11.cpp | 26 +++++++++---------- .../SemaCXX/cxx1y-constexpr-not-const.cpp | 18 +++++++++++++ .../SemaCXX/enum-unscoped-nonexistent.cpp | 8 +++--- 25 files changed, 133 insertions(+), 82 deletions(-) create mode 100644 clang/test/FixIt/fixit-cxx1y-compat.cpp create mode 100644 clang/test/SemaCXX/cxx1y-constexpr-not-const.cpp diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 0bdd041db95c..7e9713069a4b 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -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, 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>; def err_invalid_constexpr : Error< "%select{function parameter|typedef|non-static data member}0 " "cannot be constexpr">; diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index a39cebccb315..1215e36824d3 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -5015,7 +5015,8 @@ void Parser::ParseFunctionDeclarator(Declarator &D, Sema::CXXThisScopeRAII ThisScope(Actions, dyn_cast(Actions.CurContext), DS.getTypeQualifiers() | - (D.getDeclSpec().isConstexprSpecified() + (D.getDeclSpec().isConstexprSpecified() && + !getLangOpts().CPlusPlus1y ? Qualifiers::Const : 0), IsCXX11MemberFunction); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index c20b5ff068af..6ecc84fac4d2 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -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(NewFD); - if (MD && MD->isConstexpr() && !MD->isStatic() && - !isa(MD) && + if (!getLangOpts().CPlusPlus1y && MD && MD->isConstexpr() && + !MD->isStatic() && !isa(MD) && (MD->getTypeQualifiers() & Qualifiers::Const) == 0) { CXXMethodDecl *OldMD = dyn_cast_or_null(OldDecl); if (FunctionTemplateDecl *OldTD = @@ -6743,6 +6746,18 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, ArrayRef(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()) + AddConstLoc = PP.getLocForEndOfToken(FTL.getRParenLoc()); + + Diag(MD->getLocation(), diag::warn_cxx1y_compat_constexpr_not_const) + << FixItHint::CreateInsertion(AddConstLoc, " const"); + } } } diff --git a/clang/test/CXX/basic/basic.types/p10.cpp b/clang/test/CXX/basic/basic.types/p10.cpp index 6401c29dcff0..690538d0532c 100644 --- a/clang/test/CXX/basic/basic.types/p10.cpp +++ b/clang/test/CXX/basic/basic.types/p10.cpp @@ -32,13 +32,13 @@ constexpr ClassTemp 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 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; diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp index a3a964a1ca38..122a400d9b4e 100644 --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp @@ -71,7 +71,7 @@ struct ConstexprDtor { template constexpr T ft(T t) { return t; } template T gt(T t) { return t; } struct S { - template constexpr T f(); + template constexpr T f(); // expected-warning {{C++1y}} template 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' 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' 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}} 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 0cef31b6c869..06993c225e86 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 @@ -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 diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp index bca73ee85f6d..5e40f69d77ba 100644 --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp @@ -102,7 +102,7 @@ X x = cmin(X(), X()); // ok, not constexpr template struct Y { constexpr Y() {} - constexpr int get() { return T(); } + constexpr int get() { return T(); } // expected-warning {{C++1y}} }; struct Z { operator int(); }; diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp index 1a6dc9ecfb5d..bb7f7ac326e7 100644 --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp @@ -24,7 +24,7 @@ struct S { struct T {}; template struct ImplicitVirtualFromDependentBase : T { - constexpr int ImplicitlyVirtual() { return 0; } + constexpr int ImplicitlyVirtual() const { return 0; } }; constexpr int a = ImplicitVirtualFromDependentBase().ImplicitlyVirtual(); // expected-error {{constant expression}} expected-note {{cannot evaluate virtual function call}} @@ -32,7 +32,7 @@ constexpr int b = ImplicitVirtualFromDependentBase().ImplicitlyVirtual(); // constexpr int c = ImplicitVirtualFromDependentBase().ImplicitVirtualFromDependentBase::ImplicitlyVirtual(); template struct ConstexprMember { - constexpr R F() { return 0; } + constexpr R F() const { return 0; } }; constexpr int d = ConstexprMember().F(); // ok constexpr int e = ConstexprMember().F(); // expected-error {{constant expression}} diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p8.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p8.cpp index 344f8ce8c488..40aa600ba1f7 100644 --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p8.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p8.cpp @@ -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 constexpr T tm(); + template constexpr T tm(); // expected-warning {{C++1y}} template 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 constexpr T S::tm() { return T(); } +template constexpr T S::tm() { return T(); } // expected-warning {{C++1y}} template 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; }; diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.simple/p5-cxx0x.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.simple/p5-cxx0x.cpp index 093bc14d47f1..d55de08144b9 100644 --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.simple/p5-cxx0x.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.simple/p5-cxx0x.cpp @@ -76,7 +76,7 @@ namespace libcxx_example { template struct swappable { typedef decltype(swap(declval(), declval())) type; static const bool value = !is_same::value; - constexpr operator bool() { return value; } + constexpr operator bool() const { return value; } }; static_assert(swappable(), ""); diff --git a/clang/test/CXX/dcl.dcl/p4-0x.cpp b/clang/test/CXX/dcl.dcl/p4-0x.cpp index 31d49127e7a7..1f4cdda1a1f5 100644 --- a/clang/test/CXX/dcl.dcl/p4-0x.cpp +++ b/clang/test/CXX/dcl.dcl/p4-0x.cpp @@ -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), ""); diff --git a/clang/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp b/clang/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp index 783aba182319..b9a1bc52886c 100644 --- a/clang/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp +++ b/clang/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp @@ -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; }; diff --git a/clang/test/CXX/expr/expr.ass/p9-cxx11.cpp b/clang/test/CXX/expr/expr.ass/p9-cxx11.cpp index 206c82c985c7..ecc6d2c3d5bf 100644 --- a/clang/test/CXX/expr/expr.ass/p9-cxx11.cpp +++ b/clang/test/CXX/expr/expr.ass/p9-cxx11.cpp @@ -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, ""); diff --git a/clang/test/CXX/expr/expr.const/p2-0x.cpp b/clang/test/CXX/expr/expr.const/p2-0x.cpp index 065a12b3f235..634dee3782fc 100644 --- a/clang/test/CXX/expr/expr.const/p2-0x.cpp +++ b/clang/test/CXX/expr/expr.const/p2-0x.cpp @@ -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; }; diff --git a/clang/test/CXX/expr/expr.const/p3-0x.cpp b/clang/test/CXX/expr/expr.const/p3-0x.cpp index 6ddd11bcee26..047e238190f8 100644 --- a/clang/test/CXX/expr/expr.const/p3-0x.cpp +++ b/clang/test/CXX/expr/expr.const/p3-0x.cpp @@ -101,7 +101,7 @@ int n = Val::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. diff --git a/clang/test/CXX/expr/expr.const/p5-0x.cpp b/clang/test/CXX/expr/expr.const/p5-0x.cpp index bdb2b23ec792..0a4ac22d06d2 100644 --- a/clang/test/CXX/expr/expr.const/p5-0x.cpp +++ b/clang/test/CXX/expr/expr.const/p5-0x.cpp @@ -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 diff --git a/clang/test/CXX/stmt.stmt/stmt.select/stmt.switch/p2-0x.cpp b/clang/test/CXX/stmt.stmt/stmt.select/stmt.switch/p2-0x.cpp index d0f15d4d3df2..fda0c5cff153 100644 --- a/clang/test/CXX/stmt.stmt/stmt.select/stmt.switch/p2-0x.cpp +++ b/clang/test/CXX/stmt.stmt/stmt.select/stmt.switch/p2-0x.cpp @@ -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(); diff --git a/clang/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp b/clang/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp index e0ffef5007a1..82114cfa9dea 100644 --- a/clang/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp +++ b/clang/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp @@ -193,18 +193,18 @@ namespace PacksAtDifferentLevels { template struct X6 { template - 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 - 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 struct Inner { template - 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().f1(255, 1) == 12, ""); static_assert(X6().f2(3, 4, 0, 0) == 34, ""); diff --git a/clang/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp b/clang/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp index e0c7b35a7969..f804d4db1299 100644 --- a/clang/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp +++ b/clang/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp @@ -9,7 +9,7 @@ template inline void X::f(); // expected-error{{explicit instantiation cann template struct Y { - constexpr int f() { return 0; } + constexpr int f() { return 0; } // expected-warning{{C++1y}} }; template constexpr int Y::f() const; // expected-error{{explicit instantiation cannot be 'constexpr'}} diff --git a/clang/test/FixIt/fixit-cxx1y-compat.cpp b/clang/test/FixIt/fixit-cxx1y-compat.cpp new file mode 100644 index 000000000000..9fd5ff26e558 --- /dev/null +++ b/clang/test/FixIt/fixit-cxx1y-compat.cpp @@ -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(); +}; diff --git a/clang/test/Parser/cxx0x-ambig.cpp b/clang/test/Parser/cxx0x-ambig.cpp index 3b864f980194..4c22ed3a9bbc 100644 --- a/clang/test/Parser/cxx0x-ambig.cpp +++ b/clang/test/Parser/cxx0x-ambig.cpp @@ -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 { diff --git a/clang/test/Parser/cxx0x-decl.cpp b/clang/test/Parser/cxx0x-decl.cpp index c079522e8fd0..e6cba726ab63 100644 --- a/clang/test/Parser/cxx0x-decl.cpp +++ b/clang/test/Parser/cxx0x-decl.cpp @@ -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; } diff --git a/clang/test/SemaCXX/constant-expression-cxx11.cpp b/clang/test/SemaCXX/constant-expression-cxx11.cpp index 30aa7d7b0b3a..eb17808a20fd 100644 --- a/clang/test/SemaCXX/constant-expression-cxx11.cpp +++ b/clang/test/SemaCXX/constant-expression-cxx11.cpp @@ -21,7 +21,7 @@ template constexpr T *begin(T (&xs)[N]) { return xs; } template 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(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}} diff --git a/clang/test/SemaCXX/cxx1y-constexpr-not-const.cpp b/clang/test/SemaCXX/cxx1y-constexpr-not-const.cpp new file mode 100644 index 000000000000..3f100b8b691e --- /dev/null +++ b/clang/test/SemaCXX/cxx1y-constexpr-not-const.cpp @@ -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 diff --git a/clang/test/SemaCXX/enum-unscoped-nonexistent.cpp b/clang/test/SemaCXX/enum-unscoped-nonexistent.cpp index d49800caa61a..e9da38f558d3 100644 --- a/clang/test/SemaCXX/enum-unscoped-nonexistent.cpp +++ b/clang/test/SemaCXX/enum-unscoped-nonexistent.cpp @@ -5,8 +5,8 @@ struct Base { }; template 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::E : int {}; // expected-note {{enum 'S::E' was explicitly specialized here}} @@ -16,13 +16,13 @@ template enum S::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 constexpr int S::f() { return a; } +template constexpr int S::f() const { return a; } static_assert(S().f() == 1, ""); static_assert(S().f() == 1, ""); // The unqualified-id here names a member of the current instantiation, which // bizarrely might not exist in some instantiations. -template constexpr int S::g() { return b; } // expected-error {{enumerator 'b' does not exist in instantiation of 'S'}} +template constexpr int S::g() const { return b; } // expected-error {{enumerator 'b' does not exist in instantiation of 'S'}} static_assert(S().g() == 1, ""); // expected-note {{here}} expected-error {{not an integral constant expression}} expected-note {{undefined}} static_assert(S().g() == 2, ""); static_assert(S().g() == 8, "");