diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -1297,6 +1297,11 @@ 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, @@ -1304,7 +1309,8 @@ 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 || @@ -1318,7 +1324,13 @@ } bool isImmediateFunctionContext() const { - return Context == ExpressionEvaluationContext::ImmediateFunctionContext; + return Context == ExpressionEvaluationContext::ImmediateFunctionContext || + InImmediateFunctionContext; + } + + bool isDiscardedStatementContext() const { + return Context == ExpressionEvaluationContext::DiscardedStatement || + InDiscardedStatement; } }; @@ -9140,14 +9152,7 @@ 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 diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -16567,6 +16567,17 @@ 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); @@ -18956,6 +18967,10 @@ /// during overload resolution or within sizeof/alignof/typeof/typeid. bool Sema::DiagRuntimeBehavior(SourceLocation Loc, ArrayRef Stmts, const PartialDiagnostic &PD) { + + if (ExprEvalContexts.back().isDiscardedStatementContext()) + return false; + switch (ExprEvalContexts.back().Context) { case ExpressionEvaluationContext::Unevaluated: case ExpressionEvaluationContext::UnevaluatedList: diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -3563,8 +3563,7 @@ bool HasDeducedReturnType = CurLambda && hasDeducedReturnType(CurLambda->CallOperator); - if (ExprEvalContexts.back().Context == - ExpressionEvaluationContext::DiscardedStatement && + if (ExprEvalContexts.back().isDiscardedStatementContext() && (HasDeducedReturnType || CurCap->HasImplicitReturnType)) { if (RetValExp) { ExprResult ER = @@ -3880,8 +3879,7 @@ 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 = @@ -3966,8 +3964,7 @@ // 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 = diff --git a/clang/test/SemaCXX/cxx2b-consteval-if.cpp b/clang/test/SemaCXX/cxx2b-consteval-if.cpp --- a/clang/test/SemaCXX/cxx2b-consteval-if.cpp +++ b/clang/test/SemaCXX/cxx2b-consteval-if.cpp @@ -52,6 +52,5 @@ 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; }