Skip to content

[clang][Sema] Diagnose exceptions only in non-dependent context in discarded try/catch/throw blocks #139859

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -11154,6 +11154,8 @@ class Sema final : public SemaBase {
StmtResult ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock,
ArrayRef<Stmt *> Handlers);

void DiagnoseExceptionUse(SourceLocation Loc, bool IsTry);

StmtResult ActOnSEHTryBlock(bool IsCXXTry, // try (true) or __try (false) ?
SourceLocation TryLoc, Stmt *TryBlock,
Stmt *Handler);
Expand Down
9 changes: 2 additions & 7 deletions clang/lib/Sema/SemaExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -851,13 +851,8 @@ ExprResult Sema::BuildCXXThrow(SourceLocation OpLoc, Expr *Ex,
const llvm::Triple &T = Context.getTargetInfo().getTriple();
const bool IsOpenMPGPUTarget =
getLangOpts().OpenMPIsTargetDevice && (T.isNVPTX() || T.isAMDGCN());
// Don't report an error if 'throw' is used in system headers or in an OpenMP
// target region compiled for a GPU architecture.
if (!IsOpenMPGPUTarget && !getLangOpts().CXXExceptions &&
!getSourceManager().isInSystemHeader(OpLoc) && !getLangOpts().CUDA) {
// Delay error emission for the OpenMP device code.
targetDiag(OpLoc, diag::err_exceptions_disabled) << "throw";
}

DiagnoseExceptionUse(OpLoc, /* IsTry= */ false);

// In OpenMP target regions, we replace 'throw' with a trap on GPU targets.
if (IsOpenMPGPUTarget)
Expand Down
26 changes: 19 additions & 7 deletions clang/lib/Sema/SemaStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4302,13 +4302,8 @@ StmtResult Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock,
const llvm::Triple &T = Context.getTargetInfo().getTriple();
const bool IsOpenMPGPUTarget =
getLangOpts().OpenMPIsTargetDevice && (T.isNVPTX() || T.isAMDGCN());
// Don't report an error if 'try' is used in system headers or in an OpenMP
// target region compiled for a GPU architecture.
if (!IsOpenMPGPUTarget && !getLangOpts().CXXExceptions &&
!getSourceManager().isInSystemHeader(TryLoc) && !getLangOpts().CUDA) {
// Delay error emission for the OpenMP device code.
targetDiag(TryLoc, diag::err_exceptions_disabled) << "try";
}

DiagnoseExceptionUse(TryLoc, /* IsTry= */ true);

// In OpenMP target regions, we assume that catch is never reached on GPU
// targets.
Expand Down Expand Up @@ -4410,6 +4405,23 @@ StmtResult Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock,
Handlers);
}

void Sema::DiagnoseExceptionUse(SourceLocation Loc, bool IsTry) {
const llvm::Triple &T = Context.getTargetInfo().getTriple();
const bool IsOpenMPGPUTarget =
getLangOpts().OpenMPIsTargetDevice && (T.isNVPTX() || T.isAMDGCN());

// Don't report an error if 'try' is used in system headers or in an OpenMP
// target region compiled for a GPU architecture.
if (IsOpenMPGPUTarget || getLangOpts().CUDA)
// Delay error emission for the OpenMP device code.
return;

if (!getLangOpts().CXXExceptions &&
!getSourceManager().isInSystemHeader(Loc) &&
!CurContext->isDependentContext())
targetDiag(Loc, diag::err_exceptions_disabled) << (IsTry ? "try" : "throw");
}

StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, SourceLocation TryLoc,
Stmt *TryBlock, Stmt *Handler) {
assert(TryBlock && Handler);
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -9162,6 +9162,8 @@ StmtResult TreeTransform<Derived>::TransformCXXTryStmt(CXXTryStmt *S) {
Handlers.push_back(Handler.getAs<Stmt>());
}

getSema().DiagnoseExceptionUse(S->getTryLoc(), /* IsTry= */ true);

if (!getDerived().AlwaysRebuild() && TryBlock.get() == S->getTryBlock() &&
!HandlerChanged)
return S;
Expand Down Expand Up @@ -14384,6 +14386,8 @@ TreeTransform<Derived>::TransformCXXThrowExpr(CXXThrowExpr *E) {
if (SubExpr.isInvalid())
return ExprError();

getSema().DiagnoseExceptionUse(E->getThrowLoc(), /* IsTry= */ false);

if (!getDerived().AlwaysRebuild() &&
SubExpr.get() == E->getSubExpr())
return E;
Expand Down
25 changes: 24 additions & 1 deletion clang/test/SemaCXX/no-exceptions.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s

// Various tests for -fno-exceptions

Expand Down Expand Up @@ -30,5 +30,28 @@ void g() {
} catch (...) {
}
}
}

namespace test2 {
template <auto enable> void foo(auto &&Fnc) {
if constexpr (enable)
try {
Fnc();
} catch (...) {
}
else
Fnc();
}

void bar1() {
foo<false>([] {});
}

template <typename T> void foo() {
try { // expected-error {{cannot use 'try' with exceptions disabled}}
} catch (...) {
}
throw 1; // expected-error {{cannot use 'throw' with exceptions disabled}}
}
void bar2() { foo<int>(); } // expected-note {{in instantiation of function template specialization 'test2::foo<int>' requested here}}
}
Loading