faisalv created this revision.

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!


Repository:
  rL LLVM

https://reviews.llvm.org/D31588

Files:
  lib/Parse/ParseTemplate.cpp

Index: lib/Parse/ParseTemplate.cpp
===================================================================
--- lib/Parse/ParseTemplate.cpp
+++ lib/Parse/ParseTemplate.cpp
@@ -1198,42 +1198,73 @@
   //   expression is resolved to a type-id, regardless of the form of
   //   the corresponding template-parameter.
   //
-  // Therefore, we initially try to parse a type-id.  
-  if (isCXXTypeId(TypeIdAsTemplateArgument)) {
-    SourceLocation Loc = Tok.getLocation();
-    TypeResult TypeArg = ParseTypeName(/*Range=*/nullptr,
-                                       Declarator::TemplateTypeArgContext);
-    if (TypeArg.isInvalid())
-      return ParsedTemplateArgument();
-    
-    return ParsedTemplateArgument(ParsedTemplateArgument::Type,
-                                  TypeArg.get().getAsOpaquePtr(), 
-                                  Loc);
-  }
-  
+  // Therefore, we initially try to parse a type-id.
+  {
+    EnterExpressionEvaluationContext EnterConstantEvaluated(
+        Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+    if (isCXXTypeId(TypeIdAsTemplateArgument)) {
+      SourceLocation Loc = Tok.getLocation();
+      TypeResult TypeArg =
+          ParseTypeName(/*Range=*/nullptr, Declarator::TemplateTypeArgContext);
+      if (TypeArg.isInvalid())
+        return ParsedTemplateArgument();
+
+      return ParsedTemplateArgument(ParsedTemplateArgument::Type,
+                                    TypeArg.get().getAsOpaquePtr(), Loc);
+    } else {
+      // If we disambiguated as an expression that we identified as potentially
+      // not being odr-used (consistent with a template argument context), and
+      // annotated our token as that expression, then remove it from the
+      // MaybeODRUsedExprs so that it doesn't trigger a false error, since it
+      // would otherwise have been removed when completing processing of a
+      // constant expression.
+      if (Actions.MaybeODRUseExprs.size()) {
+        assert(Actions.MaybeODRUseExprs.size() == 1 &&
+               "we should only need to parse one expression to determine an "
+               "error or typeid");
+        assert(Tok.getKind() == tok::annot_primary_expr &&
+               getExprAnnotation(Tok).get() ==
+                   *Actions.MaybeODRUseExprs.begin() &&
+               "The expression (DeclRefExpr or MemExpr) stored within "
+               "MaybeODRUseExprs for later checking whether we perform an "
+               "lvalue-to-rvalue conversion before determining odr-use must be "
+               "the same as the annotated token during ambiguity resolution");
+        // We clear this state, since this lingering partially processed
+        // expression should not trigger an error now and we don't need to save
+        // it for later since we can be certain that this expression would
+        // eventually have been removed during ActOnConstantExpression called
+        // from ParseConstantExpression when parsing the non-type template
+        // argument below.  Eitherway, the appropriate checking for an
+        // appropriate constant-expression that matches the
+        // non-type-template-parameter occurs later in CheckTemplateArgument.
+        Actions.MaybeODRUseExprs.clear();
+      }
+    }
+  } // End ExpressionEvaluationContext
+
   // Try to parse a template template argument.
   {
     TentativeParsingAction TPA(*this);
 
-    ParsedTemplateArgument TemplateTemplateArgument
-      = ParseTemplateTemplateArgument();
+    ParsedTemplateArgument TemplateTemplateArgument =
+        ParseTemplateTemplateArgument();
     if (!TemplateTemplateArgument.isInvalid()) {
       TPA.Commit();
       return TemplateTemplateArgument;
     }
-    
+
     // Revert this tentative parse to parse a non-type template argument.
     TPA.Revert();
   }
-  
-  // Parse a non-type template argument. 
+
+  // Parse a non-type template argument.
   SourceLocation Loc = Tok.getLocation();
   ExprResult ExprArg = ParseConstantExpression(MaybeTypeCast);
   if (ExprArg.isInvalid() || !ExprArg.get())
     return ParsedTemplateArgument();
 
-  return ParsedTemplateArgument(ParsedTemplateArgument::NonType, 
-                                ExprArg.get(), Loc);
+  return ParsedTemplateArgument(ParsedTemplateArgument::NonType, ExprArg.get(),
+                                Loc);
 }
 
 /// \brief Determine whether the current tokens can only be parsed as a 
@@ -1274,16 +1305,16 @@
 ///         template-argument-list ',' template-argument
 bool
 Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) {
-  // Template argument lists are constant-evaluation contexts.
-  EnterExpressionEvaluationContext EvalContext(
-      Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+  
   ColonProtectionRAIIObject ColonProtection(*this, false);
 
   do {
     ParsedTemplateArgument Arg = ParseTemplateArgument();
     SourceLocation EllipsisLoc;
-    if (TryConsumeToken(tok::ellipsis, EllipsisLoc))
+    if (TryConsumeToken(tok::ellipsis, EllipsisLoc)) {
+      // FIXME: Do we need need to enter a constant evaluation context here?
       Arg = Actions.ActOnPackExpansion(Arg, EllipsisLoc);
+    }
 
     if (Arg.isInvalid()) {
       SkipUntil(tok::comma, tok::greater, StopAtSemi | StopBeforeMatch);
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to