[PATCH] D19175: Fix for PR27015 (variable template initialized with a generic lambda expression)

Akira Hatanaka via cfe-commits cfe-commits at lists.llvm.org
Wed Apr 27 17:01:39 PDT 2016


ahatanak updated this revision to Diff 55356.
ahatanak added a comment.

Made a couple of changes to distinguish between an explicit specialization ('template<>') and a template declaration which doesn't have a named template parameter (see the variable template fn0 in test case vartemplate-lambda.cpp for an example).

- In Parser::ParseTemplateDeclarationOrSpecialization, clear the TemplateParamScope bit of the scope's flag if it's seen only explicit specializations.

- In Sema::ActOnStartOfLambdaDefinition, instead of checking whether the decl list is empty, check the TemplateParamScope bit of the template scope to see if it's in a "real" template declaration scope. I initially tried just removing the decls_empty() check, but found out that it asserted when the following code in test/CodeGenCXX/mangle-lambdas.cpp was compiled:

template<> double StaticMembers<double>::z = []{return 42; }();

Also, I had to change the check in test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp. Because the dependent bit of the lambda class is now set to true, Sema::CheckTemplateArgument returns early (near line 4876) before printing the last two of the three diagnostic messages:

1. error: lambda expression in an unevaluated operand
2. error: non-type template argument is not a constant expression
3. note: non-literal type 'const lambdas::(lambda at p1.cpp:2:21)' cannot be used in a constant expression

I'm not sure whether the lambda in p1.cpp should be considered dependent, but I don't think we've been doing the check correctly. If we add another template parameter in front of "I", clang prints only the first message:

template<int J, int I = ([] { return 5; }())>
int f();


http://reviews.llvm.org/D19175

Files:
  lib/Parse/ParseTemplate.cpp
  lib/Sema/SemaLambda.cpp
  lib/Sema/SemaTemplateInstantiateDecl.cpp
  test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp
  test/SemaCXX/vartemplate-lambda.cpp

Index: test/SemaCXX/vartemplate-lambda.cpp
===================================================================
--- /dev/null
+++ test/SemaCXX/vartemplate-lambda.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify %s
+// expected-no-diagnostics
+
+template <class> auto fn0 = [] {};
+template <typename> void foo0() { fn0<char>(); }
+
+template<typename T> auto fn1 = [](auto a) { return a + T(1); };
+
+template <typename X>
+int foo2() {
+  X a = 0x61;
+  fn1<char>(a);
+  return 0;
+}
+
+int main() {
+  foo2<int>();
+}
Index: test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp
===================================================================
--- test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp
+++ test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp
@@ -195,7 +195,7 @@
 namespace default_args {
 #ifdef CPP11ONLY
 namespace lambdas {
-template<int I = ([] { return 5; }())> //expected-error 2{{constant expression}} expected-note{{constant expression}}
+template<int I = ([] { return 5; }())> //expected-error {{constant expression}}
 int f();
 }
 #endif // CPP11ONLY
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -3907,9 +3907,14 @@
       PushExpressionEvaluationContext(Sema::PotentiallyEvaluated, OldVar);
 
     // Instantiate the initializer.
-    ExprResult Init =
-        SubstInitializer(OldVar->getInit(), TemplateArgs,
-                         OldVar->getInitStyle() == VarDecl::CallInit);
+    ExprResult Init;
+
+    {
+      ContextRAII SwitchContext(*this, Var->getDeclContext());
+      Init = SubstInitializer(OldVar->getInit(), TemplateArgs,
+                              OldVar->getInitStyle() == VarDecl::CallInit);
+    }
+
     if (!Init.isInvalid()) {
       bool TypeMayContainAuto = true;
       Expr *InitExpr = Init.get();
Index: lib/Sema/SemaLambda.cpp
===================================================================
--- lib/Sema/SemaLambda.cpp
+++ lib/Sema/SemaLambda.cpp
@@ -815,7 +815,7 @@
   // semantic context isn't, if it appears within a default argument of a
   // function template.
   if (Scope *TmplScope = CurScope->getTemplateParamParent())
-    if (!TmplScope->decl_empty())
+    if (TmplScope->isTemplateParamScope())
       KnownDependent = true;
 
   // Determine the signature of the call operator.
Index: lib/Parse/ParseTemplate.cpp
===================================================================
--- lib/Parse/ParseTemplate.cpp
+++ lib/Parse/ParseTemplate.cpp
@@ -67,6 +67,7 @@
 
   // Enter template-parameter scope.
   ParseScope TemplateParmScope(this, Scope::TemplateParamScope);
+  Scope *TemplateParmScopePtr = getCurScope();
 
   // Tell the action that names should be checked in the context of
   // the declaration to come.
@@ -147,6 +148,10 @@
     }
   } while (Tok.isOneOf(tok::kw_export, tok::kw_template));
 
+  if (isSpecialization)
+    TemplateParmScopePtr->setFlags(TemplateParmScopePtr->getFlags() ^
+                                   Scope::TemplateParamScope);
+
   // Parse the actual template declaration.
   return ParseSingleDeclarationAfterTemplate(Context,
                                              ParsedTemplateInfo(&ParamLists,


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D19175.55356.patch
Type: text/x-patch
Size: 3306 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20160428/f7830552/attachment-0001.bin>


More information about the cfe-commits mailing list