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,
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,
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits