This is an archive of the discontinued LLVM Phabricator instance.

Fix PR25627: Certain constant local variables must be usable as template arguments (without being odr-used)
ClosedPublic

Authored by faisalv on Apr 2 2017, 6:12 PM.

Details

Summary

This patch ensures that clang processes the expression-nodes that are generated when disambiguating between types and expressions within template arguments, as if they were truly constant-expressions. Currently, trunk correctly disambiguates, and identifies the expression as an expression - and while it annotates the token with the expression - it fails to complete the odr-use processing (specifically, failing to trigger Sema::UpdateMarkingForLValueToRValue as is done so for all Constant Expressions, which removes it from being considered odr-used).

For e.g:
template<int> struct X { };
void f() {

const int N = 10;
X<N> x; // should be OK.
[] { return X<N>{}; }; // also OK - no capture.

}
See a related bug: https://bugs.llvm.org//show_bug.cgi?id=25627

The fix is as follows:

  • Remove the EnteredConstantEvaluatedContext action from ParseTemplateArgumentList (relying that ParseTemplateArgument will get it right)
  • Add the EnteredConstantEvaluatedContext action just prior to undergoing the disambiguating parse, and if the parse succeeds for an expression, make sure it doesn't linger within MaybeODRUsedExprs by clearing it (while asserting that it only contains the offending expression)

I need to add some tests... and fix one regression.

Does the approach look sound?
Thanks!

Diff Detail

Event Timeline

faisalv created this revision.Apr 2 2017, 6:12 PM
rsmith added inline comments.Apr 26 2017, 11:37 AM
lib/Parse/ParseTemplate.cpp
1219–1220

Please add a comment here, something like:

isCXXTypeId might look up and annotate an identifier as an id-expression during disambiguation, so enter the appropriate context for a constant expression template argument before trying to disambiguate.

1230–1259

... we shouldn't need to do any of this: instead, keep your ExprEvaluationContext alive through the call to ParseConstantExpression, and tell it to not create its own context in this case.

1250–1253

This doesn't seem right. If the template parameter is of reference type, the named entity should be considered to be odr-used. And likewise just because we stopped disambiguation after finding an id-expression that names a non-type, that does not imply that the overall template argument is the entity named by that id-expression. (Eg, consider X<F()>, where F is a functor whose operator() returns this -- that template argument should be considered to odr-use F.) But...

faisalv updated this revision to Diff 96858.Apr 26 2017, 7:40 PM
faisalv marked 3 inline comments as done.

Updated the patch following Richard's feedback:

  • teach ParseConstantExpression to create its own ExpressionEvaluationContext only if asked to.
faisalv updated this revision to Diff 96861.Apr 26 2017, 7:49 PM

Fixed a regression test that should have passed without emitting error diagnostics - and now does.

*ping*
*ping*

rsmith added inline comments.May 16 2017, 1:57 PM
lib/Parse/ParseExpr.cpp
203–222

This seems more complexity than we need. How about factoring out a ParseConstantExpressionInExprEvalContext function that doesn't create a context, and then calling it from this function after creating the context?

lib/Parse/ParseTemplate.cpp
1208–1233

There's a bunch of whitespace changes here. I have no objection to them but they should be handled separately rather than mixed into this change.

This revision is now accepted and ready to land.May 20 2017, 5:09 PM