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.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@179969 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 0bdd041..7e97130 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1550,6 +1550,11 @@
 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">;
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index a39cebc..1215e36 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -5015,7 +5015,8 @@
       Sema::CXXThisScopeRAII ThisScope(Actions,
                                dyn_cast<CXXRecordDecl>(Actions.CurContext),
                                DS.getTypeQualifiers() |
-                               (D.getDeclSpec().isConstexprSpecified()
+                               (D.getDeclSpec().isConstexprSpecified() &&
+                                !getLangOpts().CPlusPlus1y
                                   ? Qualifiers::Const : 0),
                                IsCXX11MemberFunction);
 
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index c20b5ff..6ecc84f 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -6726,9 +6726,12 @@
   //
   // 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 @@
                                       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");
+      }
     }
   }
 
diff --git a/test/CXX/basic/basic.types/p10.cpp b/test/CXX/basic/basic.types/p10.cpp
index 6401c29..690538d 100644
--- a/test/CXX/basic/basic.types/p10.cpp
+++ b/test/CXX/basic/basic.types/p10.cpp
@@ -32,13 +32,13 @@
 
 //  - 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 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 @@
 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/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp
index a3a964a..122a400 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp
@@ -71,7 +71,7 @@
 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 <> 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}}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp
index 0cef31b..06993c2 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp
@@ -28,41 +28,41 @@
 // 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/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp
index bca73ee..5e40f69 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp
@@ -102,7 +102,7 @@
 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(); };
 
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp
index 1a6dc9e..bb7f7ac 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp
@@ -24,7 +24,7 @@
 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 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}}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p8.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p8.cpp
index 344f8ce..40aa600 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p8.cpp
+++ b/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<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 @@
 }
 
 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 @@
   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/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.simple/p5-cxx0x.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.simple/p5-cxx0x.cpp
index 093bc14..d55de08 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.simple/p5-cxx0x.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.simple/p5-cxx0x.cpp
@@ -76,7 +76,7 @@
   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>(), "");
diff --git a/test/CXX/dcl.dcl/p4-0x.cpp b/test/CXX/dcl.dcl/p4-0x.cpp
index 31d4912..1f4cdda 100644
--- a/test/CXX/dcl.dcl/p4-0x.cpp
+++ b/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/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp b/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp
index 783aba1..b9a1bc5 100644
--- a/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp
+++ b/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp
@@ -6,8 +6,8 @@
   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/test/CXX/expr/expr.ass/p9-cxx11.cpp b/test/CXX/expr/expr.ass/p9-cxx11.cpp
index 206c82c..ecc6d2c 100644
--- a/test/CXX/expr/expr.ass/p9-cxx11.cpp
+++ b/test/CXX/expr/expr.ass/p9-cxx11.cpp
@@ -24,8 +24,8 @@
   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/test/CXX/expr/expr.const/p2-0x.cpp b/test/CXX/expr/expr.const/p2-0x.cpp
index 065a12b..634dee3 100644
--- a/test/CXX/expr/expr.const/p2-0x.cpp
+++ b/test/CXX/expr/expr.const/p2-0x.cpp
@@ -118,7 +118,7 @@
   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 @@
     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 @@
   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/test/CXX/expr/expr.const/p3-0x.cpp b/test/CXX/expr/expr.const/p3-0x.cpp
index 6ddd11b..047e238 100644
--- a/test/CXX/expr/expr.const/p3-0x.cpp
+++ b/test/CXX/expr/expr.const/p3-0x.cpp
@@ -101,7 +101,7 @@
 
 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/test/CXX/expr/expr.const/p5-0x.cpp b/test/CXX/expr/expr.const/p5-0x.cpp
index bdb2b23..0a4ac22 100644
--- a/test/CXX/expr/expr.const/p5-0x.cpp
+++ b/test/CXX/expr/expr.const/p5-0x.cpp
@@ -7,8 +7,8 @@
 
 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 @@
 
 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/test/CXX/stmt.stmt/stmt.select/stmt.switch/p2-0x.cpp b/test/CXX/stmt.stmt/stmt.select/stmt.switch/p2-0x.cpp
index d0f15d4..fda0c5c 100644
--- a/test/CXX/stmt.stmt/stmt.select/stmt.switch/p2-0x.cpp
+++ b/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/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp b/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp
index e0ffef5..82114cf 100644
--- a/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp
+++ b/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp
@@ -193,18 +193,18 @@
     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, "");
diff --git a/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp b/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp
index e0c7b35..f804d4d 100644
--- a/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp
+++ b/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp
@@ -9,7 +9,7 @@
 
 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'}}
diff --git a/test/FixIt/fixit-cxx1y-compat.cpp b/test/FixIt/fixit-cxx1y-compat.cpp
new file mode 100644
index 0000000..9fd5ff2
--- /dev/null
+++ b/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/test/Parser/cxx0x-ambig.cpp b/test/Parser/cxx0x-ambig.cpp
index 3b864f9..4c22ed3 100644
--- a/test/Parser/cxx0x-ambig.cpp
+++ b/test/Parser/cxx0x-ambig.cpp
@@ -38,8 +38,8 @@
     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 @@
   };
 
   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/test/Parser/cxx0x-decl.cpp b/test/Parser/cxx0x-decl.cpp
index c079522..e6cba72 100644
--- a/test/Parser/cxx0x-decl.cpp
+++ b/test/Parser/cxx0x-decl.cpp
@@ -46,7 +46,7 @@
 // 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/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp
index 30aa7d7..eb17808 100644
--- a/test/SemaCXX/constant-expression-cxx11.cpp
+++ b/test/SemaCXX/constant-expression-cxx11.cpp
@@ -21,7 +21,7 @@
 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 @@
 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 @@
 
 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 @@
 namespace PR14171 {
 
 struct X {
-  constexpr (operator int)() { return 0; }
+  constexpr (operator int)() const { return 0; }
 };
 static_assert(X() == 0, "");
 
@@ -764,13 +764,13 @@
 
 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 @@
   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 @@
   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 @@
       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 @@
   };
   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 @@
 }
 
 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/test/SemaCXX/cxx1y-constexpr-not-const.cpp b/test/SemaCXX/cxx1y-constexpr-not-const.cpp
new file mode 100644
index 0000000..3f100b8
--- /dev/null
+++ b/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/test/SemaCXX/enum-unscoped-nonexistent.cpp b/test/SemaCXX/enum-unscoped-nonexistent.cpp
index d49800c..e9da38f 100644
--- a/test/SemaCXX/enum-unscoped-nonexistent.cpp
+++ b/test/SemaCXX/enum-unscoped-nonexistent.cpp
@@ -5,8 +5,8 @@
 };
 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 @@
 
 // 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, "");