EK_Decltype, EK_TemplateArgument, EK_Other
} ExprContext;
+ // A context can be nested in both a discarded statement context and
+ // an immediate function context, so they need to be tracked independently.
+ bool InDiscardedStatement;
+ bool InImmediateFunctionContext;
+
ExpressionEvaluationContextRecord(ExpressionEvaluationContext Context,
unsigned NumCleanupObjects,
CleanupInfo ParentCleanup,
ExpressionKind ExprContext)
: Context(Context), ParentCleanup(ParentCleanup),
NumCleanupObjects(NumCleanupObjects), NumTypos(0),
- ManglingContextDecl(ManglingContextDecl), ExprContext(ExprContext) {}
+ ManglingContextDecl(ManglingContextDecl), ExprContext(ExprContext),
+ InDiscardedStatement(false), InImmediateFunctionContext(false) {}
bool isUnevaluated() const {
return Context == ExpressionEvaluationContext::Unevaluated ||
}
bool isImmediateFunctionContext() const {
- return Context == ExpressionEvaluationContext::ImmediateFunctionContext;
+ return Context == ExpressionEvaluationContext::ImmediateFunctionContext ||
+ InImmediateFunctionContext;
+ }
+
+ bool isDiscardedStatementContext() const {
+ return Context == ExpressionEvaluationContext::DiscardedStatement ||
+ InDiscardedStatement;
}
};
bool isImmediateFunctionContext() const {
assert(!ExprEvalContexts.empty() &&
"Must be in an expression evaluation context");
- for (const ExpressionEvaluationContextRecord &context :
- llvm::reverse(ExprEvalContexts)) {
- if (context.isImmediateFunctionContext())
- return true;
- if (context.isUnevaluated())
- return false;
- }
- return false;
+ return ExprEvalContexts.back().isImmediateFunctionContext();
}
/// RAII class used to determine whether SFINAE has
ExpressionEvaluationContextRecord::ExpressionKind ExprContext) {
ExprEvalContexts.emplace_back(NewContext, ExprCleanupObjects.size(), Cleanup,
LambdaContextDecl, ExprContext);
+
+ // Discarded statements and immediate contexts nested in other
+ // discarded statements or immediate context are themselves
+ // a discarded statement or an immediate context, respectively.
+ ExprEvalContexts.back().InDiscardedStatement =
+ ExprEvalContexts[ExprEvalContexts.size() - 2]
+ .isDiscardedStatementContext();
+ ExprEvalContexts.back().InImmediateFunctionContext =
+ ExprEvalContexts[ExprEvalContexts.size() - 2]
+ .isImmediateFunctionContext();
+
Cleanup.reset();
if (!MaybeODRUseExprs.empty())
std::swap(MaybeODRUseExprs, ExprEvalContexts.back().SavedMaybeODRUseExprs);
/// during overload resolution or within sizeof/alignof/typeof/typeid.
bool Sema::DiagRuntimeBehavior(SourceLocation Loc, ArrayRef<const Stmt*> Stmts,
const PartialDiagnostic &PD) {
+
+ if (ExprEvalContexts.back().isDiscardedStatementContext())
+ return false;
+
switch (ExprEvalContexts.back().Context) {
case ExpressionEvaluationContext::Unevaluated:
case ExpressionEvaluationContext::UnevaluatedList:
bool HasDeducedReturnType =
CurLambda && hasDeducedReturnType(CurLambda->CallOperator);
- if (ExprEvalContexts.back().Context ==
- ExpressionEvaluationContext::DiscardedStatement &&
+ if (ExprEvalContexts.back().isDiscardedStatementContext() &&
(HasDeducedReturnType || CurCap->HasImplicitReturnType)) {
if (RetValExp) {
ExprResult ER =
if (RetVal.isInvalid())
return StmtError();
StmtResult R = BuildReturnStmt(ReturnLoc, RetVal.get());
- if (R.isInvalid() || ExprEvalContexts.back().Context ==
- ExpressionEvaluationContext::DiscardedStatement)
+ if (R.isInvalid() || ExprEvalContexts.back().isDiscardedStatementContext())
return R;
if (VarDecl *VD =
// C++1z: discarded return statements are not considered when deducing a
// return type.
- if (ExprEvalContexts.back().Context ==
- ExpressionEvaluationContext::DiscardedStatement &&
+ if (ExprEvalContexts.back().isDiscardedStatementContext() &&
FnRetType->getContainedAutoType()) {
if (RetValExp) {
ExprResult ER =
return 0;
}
}
- // FIXME: this error should not happen.
- return 0.0; // expected-error {{'auto' in return type deduced as 'double' here but deduced as 'int' in earlier return statement}}
+ return 0.0;
}