[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