<div dir="ltr"><div class="gmail_default" style>Hi Richard!</div><div class="gmail_default" style><br></div><div class="gmail_default" style>Looks like this breaks compilation of libcxx with Clang:</div><div class="gmail_default" style>
<pre style="font-family:'Courier New',courier,monotype,monospace;color:rgb(0,0,0);font-size:medium"><span class="">linux-cmake/build/llvm/projects/libcxx/include/bitset:674:47: error: functions that differ only in their return type cannot be overloaded
    _LIBCPP_INLINE_VISIBILITY       reference operator[](size_t __p)       {return base::__make_ref(__p);}
                                              ^
linux-cmake/build/llvm/projects/libcxx/include/bitset:673:47: note: previous declaration is here
                              const_reference operator[](size_t __p) const {return base::__make_ref(__p);}
                                              ^</span></pre></div></div><div class="gmail_extra"><br><br><div class="gmail_quote">On Mon, Jan 14, 2013 at 9:37 AM, Richard Smith <span dir="ltr"><<a href="mailto:richard-llvm@metafoo.co.uk" target="_blank">richard-llvm@metafoo.co.uk</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: rsmith<br>
Date: Sun Jan 13 23:37:29 2013<br>
New Revision: 172376<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=172376&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=172376&view=rev</a><br>
Log:<br>
PR12008: defer adding the implicit 'const' to a constexpr member function until<br>
we know whether it is static.<br>
<br>
Modified:<br>
    cfe/trunk/lib/Sema/SemaDecl.cpp<br>
    cfe/trunk/lib/Sema/SemaOverload.cpp<br>
    cfe/trunk/lib/Sema/SemaTemplate.cpp<br>
    cfe/trunk/lib/Sema/SemaType.cpp<br>
    cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p8.cpp<br>
    cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=172376&r1=172375&r2=172376&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=172376&r1=172375&r2=172376&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Sun Jan 13 23:37:29 2013<br>
@@ -5598,11 +5598,11 @@<br>
     }<br>
<br>
     if (isConstexpr) {<br>
-      // C++0x [dcl.constexpr]p2: constexpr functions and constexpr constructors<br>
+      // C++11 [dcl.constexpr]p2: constexpr functions and constexpr constructors<br>
       // are implicitly inline.<br>
       NewFD->setImplicitlyInline();<br>
<br>
-      // C++0x [dcl.constexpr]p3: functions declared constexpr are required to<br>
+      // C++11 [dcl.constexpr]p3: functions declared constexpr are required to<br>
       // be either constructors or to return a literal type. Therefore,<br>
       // destructors cannot be declared constexpr.<br>
       if (isa<CXXDestructorDecl>(NewFD))<br>
@@ -6162,6 +6162,7 @@<br>
   filterNonConflictingPreviousDecls(Context, NewFD, Previous);<br>
<br>
   bool Redeclaration = false;<br>
+  NamedDecl *OldDecl = 0;<br>
<br>
   // Merge or overload the declaration with an existing declaration of<br>
   // the same name, if appropriate.<br>
@@ -6170,8 +6171,6 @@<br>
     // a declaration that requires merging. If it's an overload,<br>
     // there's no more work to do here; we'll just add the new<br>
     // function to the scope.<br>
-<br>
-    NamedDecl *OldDecl = 0;<br>
     if (!AllowOverloadingOfFunction(Previous, Context)) {<br>
       Redeclaration = true;<br>
       OldDecl = Previous.getFoundDecl();<br>
@@ -6208,43 +6207,68 @@<br>
                                                         Context));<br>
       }<br>
     }<br>
+  }<br>
<br>
-    if (Redeclaration) {<br>
-      // NewFD and OldDecl represent declarations that need to be<br>
-      // merged.<br>
-      if (MergeFunctionDecl(NewFD, OldDecl, S)) {<br>
-        NewFD->setInvalidDecl();<br>
-        return Redeclaration;<br>
-      }<br>
+  // C++11 [dcl.constexpr]p8:<br>
+  //   A constexpr specifier for a non-static member function that is not<br>
+  //   a constructor declares that member function to be const.<br>
+  //<br>
+  // This needs to be delayed until we know whether this is an out-of-line<br>
+  // definition of a static member function.<br>
+  CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewFD);<br>
+  if (MD && MD->isConstexpr() && !MD->isStatic() &&<br>
+      !isa<CXXConstructorDecl>(MD) &&<br>
+      (MD->getTypeQualifiers() & Qualifiers::Const) == 0) {<br>
+    CXXMethodDecl *OldMD = dyn_cast_or_null<CXXMethodDecl>(OldDecl);<br>
+    if (FunctionTemplateDecl *OldTD =<br>
+          dyn_cast_or_null<FunctionTemplateDecl>(OldDecl))<br>
+      OldMD = dyn_cast<CXXMethodDecl>(OldTD->getTemplatedDecl());<br>
+    if (!OldMD || !OldMD->isStatic()) {<br>
+      const FunctionProtoType *FPT =<br>
+        MD->getType()->castAs<FunctionProtoType>();<br>
+      FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();<br>
+      EPI.TypeQuals |= Qualifiers::Const;<br>
+      MD->setType(Context.getFunctionType(FPT->getResultType(),<br>
+                                          FPT->arg_type_begin(),<br>
+                                          FPT->getNumArgs(), EPI));<br>
+    }<br>
+  }<br>
<br>
-      Previous.clear();<br>
-      Previous.addDecl(OldDecl);<br>
+  if (Redeclaration) {<br>
+    // NewFD and OldDecl represent declarations that need to be<br>
+    // merged.<br>
+    if (MergeFunctionDecl(NewFD, OldDecl, S)) {<br>
+      NewFD->setInvalidDecl();<br>
+      return Redeclaration;<br>
+    }<br>
<br>
-      if (FunctionTemplateDecl *OldTemplateDecl<br>
-                                    = dyn_cast<FunctionTemplateDecl>(OldDecl)) {<br>
-        NewFD->setPreviousDeclaration(OldTemplateDecl->getTemplatedDecl());<br>
-        FunctionTemplateDecl *NewTemplateDecl<br>
-          = NewFD->getDescribedFunctionTemplate();<br>
-        assert(NewTemplateDecl && "Template/non-template mismatch");<br>
-        if (CXXMethodDecl *Method<br>
-              = dyn_cast<CXXMethodDecl>(NewTemplateDecl->getTemplatedDecl())) {<br>
-          Method->setAccess(OldTemplateDecl->getAccess());<br>
-          NewTemplateDecl->setAccess(OldTemplateDecl->getAccess());<br>
-        }<br>
-<br>
-        // If this is an explicit specialization of a member that is a function<br>
-        // template, mark it as a member specialization.<br>
-        if (IsExplicitSpecialization &&<br>
-            NewTemplateDecl->getInstantiatedFromMemberTemplate()) {<br>
-          NewTemplateDecl->setMemberSpecialization();<br>
-          assert(OldTemplateDecl->isMemberSpecialization());<br>
-        }<br>
-<br>
-      } else {<br>
-        if (isa<CXXMethodDecl>(NewFD)) // Set access for out-of-line definitions<br>
-          NewFD->setAccess(OldDecl->getAccess());<br>
-        NewFD->setPreviousDeclaration(cast<FunctionDecl>(OldDecl));<br>
+    Previous.clear();<br>
+    Previous.addDecl(OldDecl);<br>
+<br>
+    if (FunctionTemplateDecl *OldTemplateDecl<br>
+                                  = dyn_cast<FunctionTemplateDecl>(OldDecl)) {<br>
+      NewFD->setPreviousDeclaration(OldTemplateDecl->getTemplatedDecl());<br>
+      FunctionTemplateDecl *NewTemplateDecl<br>
+        = NewFD->getDescribedFunctionTemplate();<br>
+      assert(NewTemplateDecl && "Template/non-template mismatch");<br>
+      if (CXXMethodDecl *Method<br>
+            = dyn_cast<CXXMethodDecl>(NewTemplateDecl->getTemplatedDecl())) {<br>
+        Method->setAccess(OldTemplateDecl->getAccess());<br>
+        NewTemplateDecl->setAccess(OldTemplateDecl->getAccess());<br>
+      }<br>
+<br>
+      // If this is an explicit specialization of a member that is a function<br>
+      // template, mark it as a member specialization.<br>
+      if (IsExplicitSpecialization &&<br>
+          NewTemplateDecl->getInstantiatedFromMemberTemplate()) {<br>
+        NewTemplateDecl->setMemberSpecialization();<br>
+        assert(OldTemplateDecl->isMemberSpecialization());<br>
       }<br>
+<br>
+    } else {<br>
+      if (isa<CXXMethodDecl>(NewFD)) // Set access for out-of-line definitions<br>
+        NewFD->setAccess(OldDecl->getAccess());<br>
+      NewFD->setPreviousDeclaration(cast<FunctionDecl>(OldDecl));<br>
     }<br>
   }<br>
<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=172376&r1=172375&r2=172376&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=172376&r1=172375&r2=172376&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Sun Jan 13 23:37:29 2013<br>
@@ -1012,28 +1012,37 @@<br>
   // 13.1p2). While not part of the definition of the signature,<br>
   // this check is important to determine whether these functions<br>
   // can be overloaded.<br>
-  CXXMethodDecl* OldMethod = dyn_cast<CXXMethodDecl>(Old);<br>
-  CXXMethodDecl* NewMethod = dyn_cast<CXXMethodDecl>(New);<br>
+  CXXMethodDecl *OldMethod = dyn_cast<CXXMethodDecl>(Old);<br>
+  CXXMethodDecl *NewMethod = dyn_cast<CXXMethodDecl>(New);<br>
   if (OldMethod && NewMethod &&<br>
-      !OldMethod->isStatic() && !NewMethod->isStatic() &&<br>
-      (OldMethod->getTypeQualifiers() != NewMethod->getTypeQualifiers() ||<br>
-       OldMethod->getRefQualifier() != NewMethod->getRefQualifier())) {<br>
-    if (!UseUsingDeclRules &&<br>
-        OldMethod->getRefQualifier() != NewMethod->getRefQualifier() &&<br>
-        (OldMethod->getRefQualifier() == RQ_None ||<br>
-         NewMethod->getRefQualifier() == RQ_None)) {<br>
-      // C++0x [over.load]p2:<br>
-      //   - Member function declarations with the same name and the same<br>
-      //     parameter-type-list as well as member function template<br>
-      //     declarations with the same name, the same parameter-type-list, and<br>
-      //     the same template parameter lists cannot be overloaded if any of<br>
-      //     them, but not all, have a ref-qualifier (8.3.5).<br>
-      Diag(NewMethod->getLocation(), diag::err_ref_qualifier_overload)<br>
-        << NewMethod->getRefQualifier() << OldMethod->getRefQualifier();<br>
-      Diag(OldMethod->getLocation(), diag::note_previous_declaration);<br>
+      !OldMethod->isStatic() && !NewMethod->isStatic()) {<br>
+    if (OldMethod->getRefQualifier() != NewMethod->getRefQualifier()) {<br>
+      if (!UseUsingDeclRules &&<br>
+          (OldMethod->getRefQualifier() == RQ_None ||<br>
+           NewMethod->getRefQualifier() == RQ_None)) {<br>
+        // C++0x [over.load]p2:<br>
+        //   - Member function declarations with the same name and the same<br>
+        //     parameter-type-list as well as member function template<br>
+        //     declarations with the same name, the same parameter-type-list, and<br>
+        //     the same template parameter lists cannot be overloaded if any of<br>
+        //     them, but not all, have a ref-qualifier (8.3.5).<br>
+        Diag(NewMethod->getLocation(), diag::err_ref_qualifier_overload)<br>
+          << NewMethod->getRefQualifier() << OldMethod->getRefQualifier();<br>
+        Diag(OldMethod->getLocation(), diag::note_previous_declaration);<br>
+      }<br>
+      return true;<br>
     }<br>
<br>
-    return true;<br>
+    // We may not have applied the implicit const for a constexpr member<br>
+    // function yet (because we haven't yet resolved whether this is a static<br>
+    // or non-static member function). Add it now, on the assumption that this<br>
+    // is a redeclaration of OldMethod.<br>
+    unsigned NewQuals = NewMethod->getTypeQualifiers();<br>
+    if ((OldMethod->isConstexpr() || NewMethod->isConstexpr()) &&<br>
+        !isa<CXXConstructorDecl>(NewMethod))<br>
+      NewQuals |= Qualifiers::Const;<br>
+    if (OldMethod->getTypeQualifiers() != NewQuals)<br>
+      return true;<br>
   }<br>
<br>
   // The signatures match; this is not an overload.<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=172376&r1=172375&r2=172376&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=172376&r1=172375&r2=172376&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Sun Jan 13 23:37:29 2013<br>
@@ -5918,6 +5918,25 @@<br>
                                 Ovl->getDeclContext()->getRedeclContext()))<br>
         continue;<br>
<br>
+      // When matching a constexpr member function template specialization<br>
+      // against the primary template, we don't yet know whether the<br>
+      // specialization has an implicit 'const' (because we don't know whether<br>
+      // it will be a static member function until we know which template it<br>
+      // specializes), so adjust it now assuming it specializes this template.<br>
+      QualType FT = FD->getType();<br>
+      if (FD->isConstexpr()) {<br>
+        CXXMethodDecl *OldMD =<br>
+          dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl());<br>
+        if (OldMD && OldMD->isConst()) {<br>
+          const FunctionProtoType *FPT = FT->castAs<FunctionProtoType>();<br>
+          FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();<br>
+          EPI.TypeQuals |= Qualifiers::Const;<br>
+          FT = Context.getFunctionType(FPT->getResultType(),<br>
+                                       FPT->arg_type_begin(),<br>
+                                       FPT->getNumArgs(), EPI);<br>
+        }<br>
+      }<br>
+<br>
       // C++ [temp.expl.spec]p11:<br>
       //   A trailing template-argument can be left unspecified in the<br>
       //   template-id naming an explicit function template specialization<br>
@@ -5928,10 +5947,8 @@<br>
       TemplateDeductionInfo Info(FD->getLocation());<br>
       FunctionDecl *Specialization = 0;<br>
       if (TemplateDeductionResult TDK<br>
-            = DeduceTemplateArguments(FunTmpl, ExplicitTemplateArgs,<br>
-                                      FD->getType(),<br>
-                                      Specialization,<br>
-                                      Info)) {<br>
+            = DeduceTemplateArguments(FunTmpl, ExplicitTemplateArgs, FT,<br>
+                                      Specialization, Info)) {<br>
         // FIXME: Template argument deduction failed; record why it failed, so<br>
         // that we can provide nifty diagnostics.<br>
         (void)TDK;<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaType.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=172376&r1=172375&r2=172376&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=172376&r1=172375&r2=172376&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaType.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaType.cpp Sun Jan 13 23:37:29 2013<br>
@@ -2690,30 +2690,6 @@<br>
       FreeFunction = (DC && !DC->isRecord());<br>
     }<br>
<br>
-    // C++0x [dcl.constexpr]p8: A constexpr specifier for a non-static member<br>
-    // function that is not a constructor declares that function to be const.<br>
-    // FIXME: This should be deferred until we know whether this is a static<br>
-    //        member function (for an out-of-class definition, we don't know<br>
-    //        this until we perform redeclaration lookup).<br>
-    if (D.getDeclSpec().isConstexprSpecified() && !FreeFunction &&<br>
-        D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static &&<br>
-        D.getName().getKind() != UnqualifiedId::IK_ConstructorName &&<br>
-        D.getName().getKind() != UnqualifiedId::IK_ConstructorTemplateId &&<br>
-        !(FnTy->getTypeQuals() & DeclSpec::TQ_const)) {<br>
-      // Rebuild function type adding a 'const' qualifier.<br>
-      FunctionProtoType::ExtProtoInfo EPI = FnTy->getExtProtoInfo();<br>
-      EPI.TypeQuals |= DeclSpec::TQ_const;<br>
-      T = Context.getFunctionType(FnTy->getResultType(),<br>
-                                  FnTy->arg_type_begin(),<br>
-                                  FnTy->getNumArgs(), EPI);<br>
-      // Rebuild any parens around the identifier in the function type.<br>
-      for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {<br>
-        if (D.getTypeObject(i).Kind != DeclaratorChunk::Paren)<br>
-          break;<br>
-        T = S.BuildParenType(T);<br>
-      }<br>
-    }<br>
-<br>
     // C++11 [dcl.fct]p6 (w/DR1417):<br>
     // An attempt to specify a function type with a cv-qualifier-seq or a<br>
     // ref-qualifier (including by typedef-name) is ill-formed unless it is:<br>
<br>
Modified: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p8.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p8.cpp?rev=172376&r1=172375&r2=172376&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p8.cpp?rev=172376&r1=172375&r2=172376&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p8.cpp (original)<br>
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p8.cpp Sun Jan 13 23:37:29 2013<br>
@@ -1,19 +1,35 @@<br>
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s<br>
<br>
+using size_t = decltype(sizeof(int));<br>
+<br>
 struct S {<br>
   constexpr int f();<br>
   constexpr int g() const;<br>
   static constexpr int Sf();<br>
+  /*static*/ constexpr void *operator new(size_t) noexcept;<br>
+  template<typename T> constexpr T tm();<br>
+  template<typename T> static constexpr T ts();<br>
 };<br>
<br>
 void f(const S &s) {<br>
   s.f();<br>
   s.g();<br>
<br>
-  int (*f)() = &S::Sf;<br>
+  int (*Sf)() = &S::Sf;<br>
+  int (S::*f)() const = &S::f;<br>
   int (S::*g)() const = &S::g;<br>
+  void *(*opNew)(size_t) = &S::operator new;<br>
+  int (S::*tm)() const = &S::tm;<br>
+  int (*ts)() = &S::ts;<br>
 }<br>
<br>
+constexpr int S::f() const { return 0; }<br>
+constexpr int S::g() { return 1; }<br>
+constexpr int S::Sf() { return 2; }<br>
+constexpr void *S::operator new(size_t) noexcept { return 0; }<br>
+template<typename T> constexpr T S::tm() { return T(); }<br>
+template<typename T> constexpr T S::ts() { return T(); }<br>
+<br>
 namespace std_example {<br>
<br>
   class debug_flag { // expected-note {{not an aggregate and has no constexpr constructors}}<br>
<br>
Modified: cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp?rev=172376&r1=172375&r2=172376&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp?rev=172376&r1=172375&r2=172376&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp (original)<br>
+++ cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp Sun Jan 13 23:37:29 2013<br>
@@ -12,7 +12,7 @@<br>
   constexpr int f() { return 0; }<br>
 };<br>
<br>
-template constexpr int Y<int>::f(); // expected-error{{explicit instantiation cannot be 'constexpr'}}<br>
+template constexpr int Y<int>::f() const; // expected-error{{explicit instantiation cannot be 'constexpr'}}<br>
<br>
 template<typename T><br>
 struct Z {<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@cs.uiuc.edu">cfe-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br><br clear="all"><div><br></div>-- <br><div>Alexey Samsonov, MSK</div>
</div>