Fix PR10177 where non-type template arguments to alias templates are not marked as...
authorLarisse Voufo <lvoufo@google.com>
Tue, 29 Jul 2014 18:44:19 +0000 (18:44 +0000)
committerLarisse Voufo <lvoufo@google.com>
Tue, 29 Jul 2014 18:44:19 +0000 (18:44 +0000)
llvm-svn: 214192

clang/lib/Sema/SemaExpr.cpp
clang/test/SemaCXX/PR10177.cpp

index dbf0f8e..3312f0c 100644 (file)
@@ -12439,6 +12439,8 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
          "Invalid Expr argument to DoMarkVarDeclReferenced");
   Var->setReferenced();
 
+  TemplateSpecializationKind TSK = Var->getTemplateSpecializationKind();
+
   // If the context is not potentially evaluated, this is not an odr-use and
   // does not trigger instantiation.
   if (!IsPotentiallyEvaluatedContext(SemaRef)) {
@@ -12453,25 +12455,26 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
     // arguments, where local variables can't be used.
     const bool RefersToEnclosingScope =
         (SemaRef.CurContext != Var->getDeclContext() &&
-         Var->getDeclContext()->isFunctionOrMethod() &&
-         Var->hasLocalStorage());
-    if (!RefersToEnclosingScope)
-      return;
-
-    if (LambdaScopeInfo *const LSI = SemaRef.getCurLambda()) {
-      // If a variable could potentially be odr-used, defer marking it so
-      // until we finish analyzing the full expression for any lvalue-to-rvalue
-      // or discarded value conversions that would obviate odr-use.
-      // Add it to the list of potential captures that will be analyzed
-      // later (ActOnFinishFullExpr) for eventual capture and odr-use marking
-      // unless the variable is a reference that was initialized by a constant
-      // expression (this will never need to be captured or odr-used).
-      assert(E && "Capture variable should be used in an expression.");
-      if (!Var->getType()->isReferenceType() ||
-          !IsVariableNonDependentAndAConstantExpression(Var, SemaRef.Context))
-        LSI->addPotentialCapture(E->IgnoreParens());
+         Var->getDeclContext()->isFunctionOrMethod() && Var->hasLocalStorage());
+    if (RefersToEnclosingScope) {
+      if (LambdaScopeInfo *const LSI = SemaRef.getCurLambda()) {
+        // If a variable could potentially be odr-used, defer marking it so
+        // until we finish analyzing the full expression for any
+        // lvalue-to-rvalue
+        // or discarded value conversions that would obviate odr-use.
+        // Add it to the list of potential captures that will be analyzed
+        // later (ActOnFinishFullExpr) for eventual capture and odr-use marking
+        // unless the variable is a reference that was initialized by a constant
+        // expression (this will never need to be captured or odr-used).
+        assert(E && "Capture variable should be used in an expression.");
+        if (!Var->getType()->isReferenceType() ||
+            !IsVariableNonDependentAndAConstantExpression(Var, SemaRef.Context))
+          LSI->addPotentialCapture(E->IgnoreParens());
+      }
     }
-    return;
+
+    if (!isTemplateInstantiation(TSK))
+       return;
   }
 
   VarTemplateSpecializationDecl *VarSpec =
@@ -12483,7 +12486,6 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
   // templates of class templates, and variable template specializations. Delay
   // instantiations of variable templates, except for those that could be used
   // in a constant expression.
-  TemplateSpecializationKind TSK = Var->getTemplateSpecializationKind();
   if (isTemplateInstantiation(TSK)) {
     bool TryInstantiating = TSK == TSK_ImplicitInstantiation;
 
index 8d745de..8093e18 100644 (file)
@@ -9,22 +9,28 @@ struct U {
   static int a;
 };
 
-template<int N> struct S; // expected-note 2{{here}}
+template<int N> struct S; // expected-note 6{{here}}
 
 template<int N>
-int U<N>::a = S<N>::kError; // expected-error 2{{undefined}}
+int U<N>::a = S<N>::kError; // expected-error 6{{undefined}}
 
 template<typename T>
 void f() {
-  // FIXME: The standard suggests that U<0>::a is odr-used by this expression,
-  // but it's not entirely clear that's the right behaviour.
-  (void)alias_ref<int, int&, U<0>::a>();
+  (void)alias_ref<int, int&, U<0>::a>(); // expected-note {{here}}
   (void)func_ref<int, int&, U<1>::a>(); // expected-note {{here}}
   (void)class_ref<int, int&, U<2>::a>(); // expected-note {{here}}
 };
 
+template<int N>
+void fi() {
+  (void)alias_ref<int, int&, U<N>::a>(); // expected-note {{here}}
+  (void)func_ref<int, int&, U<N+1>::a>(); // expected-note {{here}}
+  (void)class_ref<int, int&, U<N+2>::a>(); // expected-note {{here}}
+};
+
 int main() {
-  f<int>(); // expected-note 2{{here}}
+  f<int>();   // NOTE: Non-dependent name uses are type-checked at template definition time.
+  fi<10>();   // expected-note 3{{here}}
 }
 
 namespace N {
@@ -38,3 +44,4 @@ namespace N {
   }
   int j = f<int>();
 }
+