Fix compiler crash when an expression parsed in the tentative parsing and must be...
authorAlexey Bataev <a.bataev@hotmail.com>
Fri, 29 May 2020 21:56:07 +0000 (17:56 -0400)
committerAlexey Bataev <a.bataev@hotmail.com>
Tue, 2 Jun 2020 18:27:33 +0000 (14:27 -0400)
Summary:
Clang crashes when trying to finish function body. MaybeODRUseExprs is
not empty because of const static data member parsed in outer evaluation
context, upon call for isTypeIdInParens() function. It builds
annot_primary_expr, later parsed in ParseConstantExpression() in
inner constant expression evaluation context.

Reviewers: rjmccall, rsmith

Subscribers: cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D80925

clang/include/clang/Basic/TokenKinds.def
clang/lib/Parse/ParseExpr.cpp
clang/lib/Parse/ParseTentative.cpp
clang/lib/Parse/Parser.cpp
clang/test/AST/alignas_maybe_odr_cleanup.cpp [new file with mode: 0644]

index 919c51f..876f53c 100644 (file)
@@ -742,6 +742,9 @@ ANNOTATION(non_type_undeclared) // annotation for an undeclared identifier that
 ANNOTATION(non_type_dependent)  // annotation for an assumed non-type member of
                                 // a dependent base class
 ANNOTATION(primary_expr) // annotation for a primary expression
+ANNOTATION(
+    uneval_primary_expr) // annotation for a primary expression which should be
+                         // transformed to potentially evaluated
 ANNOTATION(decltype)     // annotation for a decltype expression,
                          // e.g., "decltype(foo.bar())"
 
index 544fe61..1ef352e 100644 (file)
@@ -998,8 +998,23 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
     Diag(Tok, diag::warn_cxx98_compat_nullptr);
     return Actions.ActOnCXXNullPtrLiteral(ConsumeToken());
 
+  case tok::annot_uneval_primary_expr:
   case tok::annot_primary_expr:
     Res = getExprAnnotation(Tok);
+    if (SavedKind == tok::annot_uneval_primary_expr) {
+      if (Expr *E = Res.get()) {
+        if (!E->isTypeDependent() && !E->containsErrors()) {
+          // TransformToPotentiallyEvaluated expects that it will still be in a
+          // (temporary) unevaluated context and then looks through that context
+          // to build it in the surrounding context. So we need to push an
+          // unevaluated context to balance things out.
+          EnterExpressionEvaluationContext Unevaluated(
+              Actions, Sema::ExpressionEvaluationContext::Unevaluated,
+              Sema::ReuseLambdaContextDecl);
+          Res = Actions.TransformToPotentiallyEvaluated(Res.get());
+        }
+      }
+    }
     ConsumeAnnotationToken();
     if (!Res.isInvalid() && Tok.is(tok::less))
       checkPotentialAngleBracket(Res);
index ff941cf..9179cc9 100644 (file)
@@ -1275,6 +1275,15 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
       // this is ambiguous. Typo-correct to type and expression keywords and
       // to types and identifiers, in order to try to recover from errors.
       TentativeParseCCC CCC(Next);
+      // Tentative parsing may not be done in the right evaluation context
+      // for the ultimate expression.  Enter an unevaluated context to prevent
+      // Sema from immediately e.g. treating this lookup as a potential ODR-use.
+      // If we generate an expression annotation token and the parser actually
+      // claims it as an expression, we'll transform the expression to a
+      // potentially-evaluated one then.
+      EnterExpressionEvaluationContext Unevaluated(
+          Actions, Sema::ExpressionEvaluationContext::Unevaluated,
+          Sema::ReuseLambdaContextDecl);
       switch (TryAnnotateName(&CCC)) {
       case ANK_Error:
         return TPResult::Error;
index de809b9..2cea730 100644 (file)
@@ -1694,7 +1694,8 @@ Parser::TryAnnotateName(CorrectionCandidateCallback *CCC) {
   }
 
   case Sema::NC_ContextIndependentExpr:
-    Tok.setKind(tok::annot_primary_expr);
+    Tok.setKind(Actions.isUnevaluatedContext() ? tok::annot_uneval_primary_expr
+                                               : tok::annot_primary_expr);
     setExprAnnotation(Tok, Classification.getExpression());
     Tok.setAnnotationEndLoc(NameLoc);
     if (SS.isNotEmpty())
diff --git a/clang/test/AST/alignas_maybe_odr_cleanup.cpp b/clang/test/AST/alignas_maybe_odr_cleanup.cpp
new file mode 100644 (file)
index 0000000..ebc0908
--- /dev/null
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fsyntax-only %s -ast-dump | FileCheck %s
+
+struct FOO {
+  static const int vec_align_bytes = 32;
+  void foo() {
+    double a alignas(vec_align_bytes);
+    ;
+  }
+};
+
+// CHECK: AlignedAttr {{.*}} alignas
+// CHECK: ConstantExpr {{.+}} 'int' Int: 32
+// CHECK: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK: DeclRefExpr {{.*}} 'const int' lvalue Var {{.*}} 'vec_align_bytes' 'const int' non_odr_use_constant
+// CHECK: NullStmt