steakhal created this revision.
steakhal added reviewers: NoQ, xazax.hun, aaron.ballman.
Herald added subscribers: martong, rnkovacs.
Herald added a reviewer: Szelethus.
Herald added a project: All.
steakhal requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
Previously, only `void` returning functions were considered for `noreturn`
attribute candidates. This patch removes this artificial restriction.
Notice the zero-initializations of the `CheckFallThroughDiagnostics`
objects. In some cases, such as inside `MakeForCoroutine()`, some struct
members were left uninitialized (probably by accident).
This way all the fields will be zero-initialized, preventing accidental
uninitialized reads during diagnostics construction.
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D139195
Files:
clang/lib/Sema/AnalysisBasedWarnings.cpp
clang/test/SemaCXX/return-noreturn.cpp
clang/test/SemaObjC/return.m
Index: clang/test/SemaObjC/return.m
===================================================================
--- clang/test/SemaObjC/return.m
+++ clang/test/SemaObjC/return.m
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wmissing-noreturn -fobjc-exceptions -Wno-objc-root-class %s
-int test1(void) {
+__attribute__((noreturn)) int test1(void) {
id a;
@throw a;
}
Index: clang/test/SemaCXX/return-noreturn.cpp
===================================================================
--- clang/test/SemaCXX/return-noreturn.cpp
+++ clang/test/SemaCXX/return-noreturn.cpp
@@ -15,28 +15,28 @@
// the presence of switches, case statements, labels, and blocks. These tests
// try to cover bugs reported in both PR6884 and PR10063.
namespace abort_struct_complex_cfgs {
- int basic(int x) {
+ __attribute__((noreturn)) int basic(int x) {
switch (x) { default: pr6884_abort(); }
}
- int f1(int x) {
+ __attribute__((noreturn)) int f1(int x) {
switch (x) default: pr6884_abort_struct();
}
- int f2(int x) {
+ __attribute__((noreturn)) int f2(int x) {
switch (x) { default: pr6884_abort_struct(); }
}
int f2_positive(int x) {
switch (x) { default: ; }
} // expected-warning {{non-void function does not return a value}}
- int f3(int x) {
+ __attribute__((noreturn)) int f3(int x) {
switch (x) { default: { pr6884_abort_struct(); } }
}
- int f4(int x) {
+ __attribute__((noreturn)) int f4(int x) {
switch (x) default: L1: L2: case 4: pr6884_abort_struct();
}
- int f5(int x) {
+ __attribute__((noreturn)) int f5(int x) {
switch (x) default: L1: { L2: case 4: pr6884_abort_struct(); }
}
- int f6(int x) {
+ __attribute__((noreturn)) int f6(int x) {
switch (x) default: L1: L2: case 4: { pr6884_abort_struct(); }
}
@@ -50,11 +50,11 @@
// Test that these constructs work even when extraneous blocks are created
// before and after the switch due to implicit destructors.
- int g1(int x) {
+ __attribute__((noreturn)) int g1(int x) {
other o;
switch (x) default: pr6884_abort_struct();
}
- int g2(int x) {
+ __attribute__((noreturn)) int g2(int x) {
other o;
switch (x) { default: pr6884_abort_struct(); }
}
@@ -62,46 +62,46 @@
other o;
switch (x) { default: ; }
} // expected-warning {{non-void function does not return a value}}
- int g3(int x) {
+ __attribute__((noreturn)) int g3(int x) {
other o;
switch (x) { default: { pr6884_abort_struct(); } }
}
- int g4(int x) {
+ __attribute__((noreturn)) int g4(int x) {
other o;
switch (x) default: L1: L2: case 4: pr6884_abort_struct();
}
- int g5(int x) {
+ __attribute__((noreturn)) int g5(int x) {
other o;
switch (x) default: L1: { L2: case 4: pr6884_abort_struct(); }
}
- int g6(int x) {
+ __attribute__((noreturn)) int g6(int x) {
other o;
switch (x) default: L1: L2: case 4: { pr6884_abort_struct(); }
}
// Test that these constructs work even with variables carrying the no-return
// destructor instead of temporaries.
- int h1(int x) {
+ __attribute__((noreturn)) int h1(int x) {
other o;
switch (x) default: pr6884_abort_struct a;
}
- int h2(int x) {
+ __attribute__((noreturn)) int h2(int x) {
other o;
switch (x) { default: pr6884_abort_struct a; }
}
- int h3(int x) {
+ __attribute__((noreturn)) int h3(int x) {
other o;
switch (x) { default: { pr6884_abort_struct a; } }
}
- int h4(int x) {
+ __attribute__((noreturn)) int h4(int x) {
other o;
switch (x) default: L1: L2: case 4: pr6884_abort_struct a;
}
- int h5(int x) {
+ __attribute__((noreturn)) int h5(int x) {
other o;
switch (x) default: L1: { L2: case 4: pr6884_abort_struct a; }
}
- int h6(int x) {
+ __attribute__((noreturn)) int h6(int x) {
other o;
switch (x) default: L1: L2: case 4: { pr6884_abort_struct a; }
}
@@ -155,11 +155,11 @@
operator bool() const;
};
-int testTernaryUnconditionalNoreturn() {
+__attribute__((noreturn)) int testTernaryUnconditionalNoreturn() {
true ? NoReturn() : NoReturn();
}
-int testTernaryStaticallyConditionalNoretrunOnTrue() {
+__attribute__((noreturn)) int testTernaryStaticallyConditionalNoretrunOnTrue() {
true ? NoReturn() : Return();
}
@@ -167,7 +167,7 @@
true ? Return() : NoReturn();
} // expected-warning {{non-void function does not return a value}}
-int testTernaryStaticallyConditionalNoretrunOnFalse() {
+__attribute__((noreturn)) int testTernaryStaticallyConditionalNoretrunOnFalse() {
false ? Return() : NoReturn();
}
@@ -191,11 +191,11 @@
value || (false ? true : NoReturn());
} // expected-warning {{non-void function does not return a value in all control paths}}
-int testStaticallyExecutedLogicalOrBranch() {
+__attribute__((noreturn)) int testStaticallyExecutedLogicalOrBranch() {
false || NoReturn();
}
-int testStaticallyExecutedLogicalAndBranch() {
+__attribute__((noreturn)) int testStaticallyExecutedLogicalAndBranch() {
true && NoReturn();
}
@@ -215,11 +215,11 @@
(true && value) || (true && NoReturn());
} // expected-warning {{non-void function does not return a value in all control paths}}
-int testConditionallyExecutedComplexLogicalBranch3(bool value) {
+__attribute__((noreturn)) int testConditionallyExecutedComplexLogicalBranch3(bool value) {
(false && (Return() || true)) || (true && NoReturn());
}
-int testConditionallyExecutedComplexLogicalBranch4(bool value) {
+__attribute__((noreturn)) int testConditionallyExecutedComplexLogicalBranch4(bool value) {
false || ((Return() || true) && (true && NoReturn()));
}
@@ -238,7 +238,7 @@
foo();
} // expected-warning {{non-void function does not return a value}}
- int baz() {
+ __attribute__((noreturn)) int baz() {
FatalCopy fc;
X work([fc](){});
foo();
Index: clang/lib/Sema/AnalysisBasedWarnings.cpp
===================================================================
--- clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -520,11 +520,11 @@
namespace {
struct CheckFallThroughDiagnostics {
- unsigned diag_MaybeFallThrough_HasNoReturn;
- unsigned diag_MaybeFallThrough_ReturnsNonVoid;
- unsigned diag_AlwaysFallThrough_HasNoReturn;
- unsigned diag_AlwaysFallThrough_ReturnsNonVoid;
- unsigned diag_NeverFallThroughOrReturn;
+ unsigned diag_MaybeFallThrough_HasNoReturn = 0;
+ unsigned diag_MaybeFallThrough_ReturnsNonVoid = 0;
+ unsigned diag_AlwaysFallThrough_HasNoReturn = 0;
+ unsigned diag_AlwaysFallThrough_ReturnsNonVoid = 0;
+ unsigned diag_NeverFallThroughOrReturn = 0;
enum { Function, Block, Lambda, Coroutine } funMode;
SourceLocation FuncLoc;
@@ -554,8 +554,6 @@
if (!isVirtualMethod && !isTemplateInstantiation)
D.diag_NeverFallThroughOrReturn =
diag::warn_suggest_noreturn_function;
- else
- D.diag_NeverFallThroughOrReturn = 0;
D.funMode = Function;
return D;
@@ -564,10 +562,8 @@
static CheckFallThroughDiagnostics MakeForCoroutine(const Decl *Func) {
CheckFallThroughDiagnostics D;
D.FuncLoc = Func->getLocation();
- D.diag_MaybeFallThrough_HasNoReturn = 0;
D.diag_MaybeFallThrough_ReturnsNonVoid =
diag::warn_maybe_falloff_nonvoid_coroutine;
- D.diag_AlwaysFallThrough_HasNoReturn = 0;
D.diag_AlwaysFallThrough_ReturnsNonVoid =
diag::warn_falloff_nonvoid_coroutine;
D.funMode = Coroutine;
@@ -584,7 +580,6 @@
diag::err_noreturn_block_has_return_expr;
D.diag_AlwaysFallThrough_ReturnsNonVoid =
diag::err_falloff_nonvoid_block;
- D.diag_NeverFallThroughOrReturn = 0;
D.funMode = Block;
return D;
}
@@ -599,7 +594,6 @@
diag::err_noreturn_lambda_has_return_expr;
D.diag_AlwaysFallThrough_ReturnsNonVoid =
diag::warn_falloff_nonvoid_lambda;
- D.diag_NeverFallThroughOrReturn = 0;
D.funMode = Lambda;
return D;
}
@@ -700,7 +694,7 @@
EmitDiag(RBrace, CD.diag_AlwaysFallThrough_ReturnsNonVoid);
break;
case NeverFallThroughOrReturn:
- if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) {
+ if (!HasNoReturn && CD.diag_NeverFallThroughOrReturn) {
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
S.Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 0 << FD;
} else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits