[cfe-commits] r150518 - in /cfe/trunk: lib/Sema/SemaExpr.cpp test/SemaTemplate/constexpr-instantiate.cpp

Richard Smith richard-llvm at metafoo.co.uk
Tue Feb 14 14:25:15 PST 2012


Author: rsmith
Date: Tue Feb 14 16:25:15 2012
New Revision: 150518

URL: http://llvm.org/viewvc/llvm-project?rev=150518&view=rev
Log:
If a constexpr function template specialization is referenced, and then the
template is defined, and then the specialization is referenced again, don't
forget to instantiate the template on the second reference. Use the source
location of the first reference as the point of instantiation, though.

Added:
    cfe/trunk/test/SemaTemplate/constexpr-instantiate.cpp
Modified:
    cfe/trunk/lib/Sema/SemaExpr.cpp

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=150518&r1=150517&r2=150518&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Tue Feb 14 16:25:15 2012
@@ -9404,7 +9404,11 @@
 
   Func->setReferenced();
 
-  if (Func->isUsed(false))
+  // Don't mark this function as used multiple times, unless it's a constexpr
+  // function which we need to instantiate.
+  if (Func->isUsed(false) &&
+      !(Func->isConstexpr() && !Func->getBody() &&
+        Func->isImplicitlyInstantiable()))
     return;
 
   if (!IsPotentiallyEvaluatedContext(*this))
@@ -9455,34 +9459,40 @@
   // class templates.
   if (Func->isImplicitlyInstantiable()) {
     bool AlreadyInstantiated = false;
+    SourceLocation PointOfInstantiation = Loc;
     if (FunctionTemplateSpecializationInfo *SpecInfo
                               = Func->getTemplateSpecializationInfo()) {
       if (SpecInfo->getPointOfInstantiation().isInvalid())
         SpecInfo->setPointOfInstantiation(Loc);
       else if (SpecInfo->getTemplateSpecializationKind()
-                 == TSK_ImplicitInstantiation)
+                 == TSK_ImplicitInstantiation) {
         AlreadyInstantiated = true;
+        PointOfInstantiation = SpecInfo->getPointOfInstantiation();
+      }
     } else if (MemberSpecializationInfo *MSInfo
                                 = Func->getMemberSpecializationInfo()) {
       if (MSInfo->getPointOfInstantiation().isInvalid())
         MSInfo->setPointOfInstantiation(Loc);
       else if (MSInfo->getTemplateSpecializationKind()
-                 == TSK_ImplicitInstantiation)
+                 == TSK_ImplicitInstantiation) {
         AlreadyInstantiated = true;
+        PointOfInstantiation = MSInfo->getPointOfInstantiation();
+      }
     }
 
-    if (!AlreadyInstantiated) {
+    if (!AlreadyInstantiated || Func->isConstexpr()) {
       if (isa<CXXRecordDecl>(Func->getDeclContext()) &&
           cast<CXXRecordDecl>(Func->getDeclContext())->isLocalClass())
-        PendingLocalImplicitInstantiations.push_back(std::make_pair(Func,
-                                                                    Loc));
-      else if (Func->getTemplateInstantiationPattern()->isConstexpr())
+        PendingLocalImplicitInstantiations.push_back(
+            std::make_pair(Func, PointOfInstantiation));
+      else if (Func->isConstexpr())
         // Do not defer instantiations of constexpr functions, to avoid the
         // expression evaluator needing to call back into Sema if it sees a
         // call to such a function.
-        InstantiateFunctionDefinition(Loc, Func);
+        InstantiateFunctionDefinition(PointOfInstantiation, Func);
       else {
-        PendingInstantiations.push_back(std::make_pair(Func, Loc));
+        PendingInstantiations.push_back(std::make_pair(Func,
+                                                       PointOfInstantiation));
         // Notify the consumer that a function was implicitly instantiated.
         Consumer.HandleCXXImplicitFunctionInstantiation(Func);
       }

Added: cfe/trunk/test/SemaTemplate/constexpr-instantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/constexpr-instantiate.cpp?rev=150518&view=auto
==============================================================================
--- cfe/trunk/test/SemaTemplate/constexpr-instantiate.cpp (added)
+++ cfe/trunk/test/SemaTemplate/constexpr-instantiate.cpp Tue Feb 14 16:25:15 2012
@@ -0,0 +1,59 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+namespace UseBeforeDefinition {
+  struct A {
+    template<typename T> static constexpr T get() { return T(); }
+    // ok, not a constant expression.
+    int n = get<int>();
+  };
+
+  // ok, constant expression.
+  constexpr int j = A::get<int>();
+
+  template<typename T> constexpr int consume(T);
+  // ok, not a constant expression.
+  const int k = consume(0); // expected-note {{here}}
+
+  template<typename T> constexpr int consume(T) { return 0; }
+  // ok, constant expression.
+  constexpr int l = consume(0);
+
+  constexpr int m = k; // expected-error {{constant expression}} expected-note {{initializer of 'k'}}
+}
+
+namespace IntegralConst {
+  template<typename T> constexpr T f(T n) { return n; }
+  enum E {
+    v = f(0), w = f(1) // ok
+  };
+  static_assert(w == 1, "");
+
+  char arr[f('x')]; // ok
+  static_assert(sizeof(arr) == 'x', "");
+}
+
+namespace ConvertedConst {
+  template<typename T> constexpr T f(T n) { return n; }
+  int f() {
+    switch (f()) {
+      case f(4): return 0;
+    }
+    return 1;
+  }
+}
+
+namespace OverloadResolution {
+  template<typename T> constexpr T f(T t) { return t; }
+
+  template<int n> struct S { };
+
+  template<typename T> auto g(T t) -> S<f(sizeof(T))> &;
+  char &f(...);
+
+  template<typename T> auto h(T t[f(sizeof(T))]) -> decltype(&*t) {
+    return t;
+  }
+
+  S<4> &k = g(0);
+  int *p, *q = h(p);
+}





More information about the cfe-commits mailing list