[Sema] Fix an assert when a block captures a constexpr local

MarkVarDeclODRUsed indirectly calls captureInBlock, which creates a copy
expression. The copy expression is insulated in it's own
ExpressionEvaluationContext, so it saves, mutates, and restores MaybeODRUseExprs
as CleanupVarDeclMarking is iterating through it, leading to a crash. Fix this
by iterating through a local copy of MaybeODRUseExprs.

rdar://47493525

https://reviews.llvm.org/D59670

llvm-svn: 357040
This commit is contained in:
Erik Pilkington 2019-03-26 23:21:19 +00:00
parent e6eef49f05
commit 14f6d1527c
3 changed files with 24 additions and 11 deletions

View File

@ -587,13 +587,13 @@ public:
/// element type here is ExprWithCleanups::Object.
SmallVector<BlockDecl*, 8> ExprCleanupObjects;
/// Store a list of either DeclRefExprs or MemberExprs
/// that contain a reference to a variable (constant) that may or may not
/// be odr-used in this Expr, and we won't know until all lvalue-to-rvalue
/// and discarded value conversions have been applied to all subexpressions
/// of the enclosing full expression. This is cleared at the end of each
/// full expression.
llvm::SmallPtrSet<Expr*, 2> MaybeODRUseExprs;
/// Store a set of either DeclRefExprs or MemberExprs that contain a reference
/// to a variable (constant) that may or may not be odr-used in this Expr, and
/// we won't know until all lvalue-to-rvalue and discarded value conversions
/// have been applied to all subexpressions of the enclosing full expression.
/// This is cleared at the end of each full expression.
using MaybeODRUseExprSet = llvm::SmallPtrSet<Expr *, 2>;
MaybeODRUseExprSet MaybeODRUseExprs;
std::unique_ptr<sema::FunctionScopeInfo> PreallocatedFunctionScope;
@ -1029,7 +1029,7 @@ public:
/// context (i.e. the number of TypoExprs created).
unsigned NumTypos;
llvm::SmallPtrSet<Expr*, 2> SavedMaybeODRUseExprs;
MaybeODRUseExprSet SavedMaybeODRUseExprs;
/// The lambdas that are present within this context, if it
/// is indeed an unevaluated context.

View File

@ -15690,7 +15690,12 @@ ExprResult Sema::ActOnConstantExpression(ExprResult Res) {
}
void Sema::CleanupVarDeclMarking() {
for (Expr *E : MaybeODRUseExprs) {
// Iterate through a local copy in case MarkVarDeclODRUsed makes a recursive
// call.
MaybeODRUseExprSet LocalMaybeODRUseExprs;
std::swap(LocalMaybeODRUseExprs, MaybeODRUseExprs);
for (Expr *E : LocalMaybeODRUseExprs) {
VarDecl *Var;
SourceLocation Loc;
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
@ -15707,10 +15712,10 @@ void Sema::CleanupVarDeclMarking() {
/*MaxFunctionScopeIndex Pointer*/ nullptr);
}
MaybeODRUseExprs.clear();
assert(MaybeODRUseExprs.empty() &&
"MarkVarDeclODRUsed failed to cleanup MaybeODRUseExprs?");
}
static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
VarDecl *Var, Expr *E) {
assert((!E || isa<DeclRefExpr>(E) || isa<MemberExpr>(E)) &&

View File

@ -145,3 +145,11 @@ namespace test6c {
A::foo(); });
}
}
namespace test7 {
struct S {};
void f() {
constexpr S s;
auto some_block = ^{ (void)s; };
}
}