[cfe-commits] r172376 - in /cfe/trunk: lib/Sema/SemaDecl.cpp lib/Sema/SemaOverload.cpp lib/Sema/SemaTemplate.cpp lib/Sema/SemaType.cpp test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p8.cpp test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp

Richard Smith richard-llvm at metafoo.co.uk
Sun Jan 13 21:37:29 PST 2013


Author: rsmith
Date: Sun Jan 13 23:37:29 2013
New Revision: 172376

URL: http://llvm.org/viewvc/llvm-project?rev=172376&view=rev
Log:
PR12008: defer adding the implicit 'const' to a constexpr member function until
we know whether it is static.

Modified:
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/lib/Sema/SemaType.cpp
    cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p8.cpp
    cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp

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

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

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

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

Modified: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p8.cpp
URL: 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
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p8.cpp (original)
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p8.cpp Sun Jan 13 23:37:29 2013
@@ -1,19 +1,35 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
 
+using size_t = decltype(sizeof(int));
+
 struct S {
   constexpr int f();
   constexpr int g() const;
   static constexpr int Sf();
+  /*static*/ constexpr void *operator new(size_t) noexcept;
+  template<typename T> constexpr T tm();
+  template<typename T> static constexpr T ts();
 };
 
 void f(const S &s) {
   s.f();
   s.g();
 
-  int (*f)() = &S::Sf;
+  int (*Sf)() = &S::Sf;
+  int (S::*f)() const = &S::f;
   int (S::*g)() const = &S::g;
+  void *(*opNew)(size_t) = &S::operator new;
+  int (S::*tm)() const = &S::tm;
+  int (*ts)() = &S::ts;
 }
 
+constexpr int S::f() const { return 0; }
+constexpr int S::g() { return 1; }
+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::ts() { return T(); }
+
 namespace std_example {
 
   class debug_flag { // expected-note {{not an aggregate and has no constexpr constructors}}

Modified: cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp
URL: 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
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp Sun Jan 13 23:37:29 2013
@@ -12,7 +12,7 @@
   constexpr int f() { return 0; }
 };
 
-template constexpr int Y<int>::f(); // expected-error{{explicit instantiation cannot be 'constexpr'}}
+template constexpr int Y<int>::f() const; // expected-error{{explicit instantiation cannot be 'constexpr'}}
 
 template<typename T>
 struct Z {





More information about the cfe-commits mailing list