From: Larisse Voufo <lvoufo@google.com> Date: Tue, 29 Jul 2014 18:44:19 +0000 (+0000) Subject: Fix PR10177 where non-type template arguments to alias templates are not marked as... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=90d51707ff2f75330b3e3816c36b37dfc8bddbb8;p=clang Fix PR10177 where non-type template arguments to alias templates are not marked as used in dependent contexts. The fix actually forces non-dependent names to be checked at template definition time as expected from the standard. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@214192 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index dbf0f8ef44..3312f0ccc0 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -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; diff --git a/test/SemaCXX/PR10177.cpp b/test/SemaCXX/PR10177.cpp index 8d745de0a6..8093e18e33 100644 --- a/test/SemaCXX/PR10177.cpp +++ b/test/SemaCXX/PR10177.cpp @@ -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>(); } +