Skip to content

Commit 5d6cdac

Browse files
committed
[clang][sema]: Error when SEH __try is used in a function with C++ dtors
SEH __try is not allowed in a function with C++ objects that have non-trivial destructors.
1 parent cf50936 commit 5d6cdac

File tree

3 files changed

+65
-0
lines changed

3 files changed

+65
-0
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8264,6 +8264,8 @@ def err_mixing_cxx_try_seh_try : Error<
82648264
"in the same function as SEH '__try'">;
82658265
def err_seh_try_unsupported : Error<
82668266
"SEH '__try' is not supported on this target">;
8267+
def err_seh_try_dtor : Error<"cannot use C++ object with a destructor "
8268+
"in the same function as SEH '__try'">;
82678269
def note_conflicting_try_here : Note<
82688270
"conflicting %0 here">;
82698271
def warn_jump_out_of_seh_finally : Warning<

clang/lib/Sema/AnalysisBasedWarnings.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,47 @@ static bool isNoexcept(const FunctionDecl *FD) {
399399
return false;
400400
}
401401

402+
//===----------------------------------------------------------------------===//
403+
// Check for SEH __try in a function with C++ objects that have destructors.
404+
//===----------------------------------------------------------------------===//
405+
406+
static void emitDiagForSehTryUnwind(Sema &S, CFGElement &E) {
407+
if (auto AD = E.getAs<CFGAutomaticObjDtor>()) {
408+
const auto *VD = AD->getVarDecl();
409+
S.Diag(VD->getLocation(), diag::err_seh_try_dtor);
410+
} else if (auto TD = E.getAs<CFGTemporaryDtor>()) {
411+
const auto *E = TD->getBindTemporaryExpr();
412+
S.Diag(E->getBeginLoc(), diag::err_seh_try_dtor);
413+
} else
414+
llvm_unreachable("emitDiagForSehTryUnwind should only be used with "
415+
"AutomaticObjectDtor or TemporaryDtor");
416+
}
417+
418+
static void checkSehTryNeedsUnwind(Sema &S, const FunctionDecl *FD,
419+
AnalysisDeclContext &AC) {
420+
if (!FD->usesSEHTry())
421+
return;
422+
CFG *BodyCFG = AC.getCFG();
423+
if (!BodyCFG)
424+
return;
425+
if (BodyCFG->getExit().pred_empty())
426+
return;
427+
428+
llvm::BitVector Reachable(BodyCFG->getNumBlockIDs());
429+
clang::reachable_code::ScanReachableFromBlock(&BodyCFG->getEntry(),
430+
Reachable);
431+
for (CFGBlock *B : *BodyCFG) {
432+
if (!Reachable[B->getBlockID()])
433+
continue;
434+
for (CFGElement &E : *B) {
435+
auto Kind = E.getKind();
436+
if (Kind == CFGElement::AutomaticObjectDtor ||
437+
Kind == CFGElement::TemporaryDtor)
438+
emitDiagForSehTryUnwind(S, E);
439+
}
440+
}
441+
}
442+
402443
//===----------------------------------------------------------------------===//
403444
// Check for missing return value.
404445
//===----------------------------------------------------------------------===//
@@ -2821,6 +2862,10 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
28212862
if (S.getLangOpts().CPlusPlus && !fscope->isCoroutine() && isNoexcept(FD))
28222863
checkThrowInNonThrowingFunc(S, FD, AC);
28232864

2865+
if (S.getLangOpts().CPlusPlus)
2866+
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
2867+
checkSehTryNeedsUnwind(S, FD, AC);
2868+
28242869
// If none of the previous checks caused a CFG build, trigger one here
28252870
// for the logical error handler.
28262871
if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->getBeginLoc())) {

clang/test/Sema/seh-cxx-dtors.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fsyntax-only -fms-extensions -verify %s
2+
3+
struct Foo {
4+
~Foo() {}
5+
};
6+
7+
// These need '-fms-extensions'
8+
void f1() {
9+
Foo foo {}; // expected-error {{destructor}}
10+
__try {} __except (1) {}
11+
}
12+
13+
void bar(Foo foo);
14+
15+
void f2() {
16+
bar(Foo {}); // expected-error {{destructor}}
17+
__try {} __except (1) {}
18+
}

0 commit comments

Comments
 (0)