Fix compiler crash when an expression parsed in the tentative parsing and must be claimed in the another evaluation context.

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
This commit is contained in:
Alexey Bataev 2020-05-29 17:56:07 -04:00
parent b78b98491a
commit 2f7269b677
5 changed files with 44 additions and 1 deletions

View 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())"

View 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);

View 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;

View 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())

View File

@ -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