]> granicus.if.org Git - clang/commitdiff
If a constexpr function template specialization is referenced, and then the
authorRichard Smith <richard-llvm@metafoo.co.uk>
Tue, 14 Feb 2012 22:25:15 +0000 (22:25 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Tue, 14 Feb 2012 22:25:15 +0000 (22:25 +0000)
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.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150518 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaExpr.cpp
test/SemaTemplate/constexpr-instantiate.cpp [new file with mode: 0644]

index 371a4e39ebd8fbbc3f51308953eb45d08f03320f..050386e2995f2e04c80aebbfd91fc47363c60272 100644 (file)
@@ -9404,7 +9404,11 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func) {
 
   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 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func) {
   // 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);
       }
diff --git a/test/SemaTemplate/constexpr-instantiate.cpp b/test/SemaTemplate/constexpr-instantiate.cpp
new file mode 100644 (file)
index 0000000..69ac0e4
--- /dev/null
@@ -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);
+}