Skip to content

Commit dedc820

Browse files
ilazaricdaveedvdv-nvidia
authored andcommitted
Suppress noreturn_function_does_return warning if noreturn constructor or destructor is called [GH edgcpp#218]
1 parent ed0a9ef commit dedc820

8 files changed

Lines changed: 75 additions & 186 deletions

File tree

‎src/Changes‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,20 @@
11
Version 7.1
22

3+
10/19/26 [GH #218]
4+
Reachability after a temporary with a "noreturn" constructor or destructor
5+
6+
An expression statement that constructs a temporary of a class type whose
7+
constructor or destructor is declared "noreturn" was not recognized as not
8+
returning. Consequently, a spurious warning could be issued when control
9+
reached the end of an enclosing "noreturn" or non-void function. That is now
10+
fixed. For example, with --c++11:
11+
12+
struct A { [[noreturn]] A(); };
13+
struct B { [[noreturn]] ~B(); };
14+
[[noreturn]] void f() { A{}; } // Previously warned that f returns.
15+
int g() { B{}; } // Previously warned about missing return.
16+
17+
318
10/15/26 [GH #309]
419
Position of (lowered) cleanups at the end of a function body
520

‎src/statements.c‎

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -175,11 +175,13 @@ suppress warnings that might otherwise be issued later.
175175

176176
static void check_reachability_following_expression(an_expr_node_ptr node)
177177
/*
178-
If the indicated expression node represents a throw or a call of a function
178+
If the indicated expression node represents a throw or calls a function
179179
that may not return, update the current "reachability" to indicate that the
180180
code directly following the expression is (or may be) unreachable.
181181
*/
182182
{
183+
a_boolean does_not_return = FALSE;
184+
183185
if (node->kind == (an_expr_node_kind)enk_object_lifetime) {
184186
node = node->variant.object_lifetime.expr;
185187
} /* if */
@@ -196,29 +198,39 @@ code directly following the expression is (or may be) unreachable.
196198
(throw c, y)
197199
but it doesn't seem worth it. */
198200
set_unreachable(curr_reachability);
199-
} else {
200-
if (is_call_node(node)) {
201-
a_boolean call_does_not_return = FALSE;
202-
a_type_ptr routine_type;
203-
node = node->variant.operation.operands;
204-
routine_type = node->type;
205-
if (is_pointer_type(routine_type)) {
206-
/* Possibly a call through a function pointer. */
207-
routine_type = type_pointed_to(routine_type);
208-
} /* if */
209-
if (is_function_type(routine_type)) {
210-
call_does_not_return = skip_typerefs(routine_type)
211-
->variant.routine.extra_info
212-
->does_not_return;
201+
} else if (node_is(node, enk_temp_init)) {
202+
a_dynamic_init_ptr dip = node->variant.init.dynamic_init;
203+
if (dip) {
204+
a_routine_ptr rp = dip->destructor;
205+
if (rp && routine_does_not_return(rp)) {
206+
does_not_return = TRUE;
213207
} /* if */
214-
if (call_does_not_return) {
215-
/* The statement is a call of a routine that is marked as not
216-
returning. Treat this like a lint notreached comment -- i.e.,
217-
as a hint to the compiler but not something we know for sure. */
218-
curr_reachability.reachable_considering_hints = FALSE;
219-
curr_reachability.suppress_unreachable_warning = TRUE;
208+
} /* if */
209+
if (dip && dyn_init_is(dip, dik_constructor)) {
210+
a_routine_ptr rp = dip->variant.constructor.ptr;
211+
if (rp && routine_does_not_return(rp)) {
212+
does_not_return = TRUE;
220213
} /* if */
221214
} /* if */
215+
} else if (is_call_node(node)) {
216+
a_type_ptr routine_type;
217+
node = node->variant.operation.operands;
218+
routine_type = node->type;
219+
if (is_pointer_type(routine_type)) {
220+
/* Possibly a call through a function pointer. */
221+
routine_type = type_pointed_to(routine_type);
222+
} /* if */
223+
if (is_function_type(routine_type)) {
224+
does_not_return |= skip_typerefs(routine_type)
225+
->variant.routine.extra_info->does_not_return;
226+
} /* if */
227+
} /* if */
228+
if (does_not_return) {
229+
/* The statement calls a routine that is marked as not returning.
230+
Treat this like a lint notreached comment -- i.e., as a hint
231+
to the compiler but not something we know for sure. */
232+
curr_reachability.reachable_considering_hints = FALSE;
233+
curr_reachability.suppress_unreachable_warning = TRUE;
222234
} /* if */
223235
} /* check_reachability_following_expression */
224236

@@ -5409,7 +5421,7 @@ the statement was preceded by the GNU C __extension__ keyword.
54095421
} /* if */
54105422
if (expr != NULL) {
54115423
sp->expr = expr;
5412-
/* If the expression is a throw expression or the call of a function that
5424+
/* If the expression is a throw expression or calls a function that
54135425
is known not to return, the code following is unreachable. */
54145426
check_reachability_following_expression(expr);
54155427
} else {
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
fe_only -DTEST_NUMBER=1 --c++11 --diag_error noreturn_function_does_return Test_name.c

‎tests/tests/changes/gh-218.sft.cpp‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//type:fp
2+
//options_all:--c++11 --diag_error noreturn_function_does_return
3+
4+
// Do not warn that a noreturn function actually returns
5+
// if it invokes a noreturn constructor or destructor.
6+
7+
struct C {
8+
[[noreturn]] C() { throw 123; }
9+
};
10+
11+
struct D {
12+
[[noreturn]] ~D() { throw 456; }
13+
};
14+
15+
[[noreturn]] void fC() { C{}; } // Previously warned. Now no diagnostic issued.
16+
17+
[[noreturn]] void fD() { D{}; } // Previously warned. Now no diagnostic issued.
18+
19+
struct SC {
20+
[[noreturn]] SC() { C{}; } // Previously warned. Now no diagnostic issued.
21+
};
22+
23+
struct SD {
24+
[[noreturn]] SD() { D{}; } // Previously warned. Now no diagnostic issued.
25+
};

‎tests/tests/imported/clang/cpp/CXX/dcl.dcl/dcl.attr/dcl.attr.noreturn/.p1.rto/default.1.1.txt‎

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,6 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
2727
[[noreturn]] int f(); // expected-error {{'noreturn' attribute does not appear on the first declaration}}
2828
^
2929

30-
"Test_name.c", line 63: warning: missing return statement at end of non-void function "GH63009::test_no_return_constructor"
31-
int test_no_return_constructor() { S1(); } // ok
32-
^
33-
34-
"Test_name.c", line 64: warning: missing return statement at end of non-void function "GH63009::test_no_return_destructor"
35-
int test_no_return_destructor() { S2(); } // ok
36-
^
37-
3830
"Test_name.c", line 69: warning: missing return statement at end of non-void function "GH63009::main"
3931
}
4032
^

‎tests/tests/imported/clang/cpp/SemaCXX/.return-noreturn.rto/default.1.1.txt‎

Lines changed: 0 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,8 @@
11
fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_version 999999 --exceptions --exceptions --c++11 Test_name.c
2-
"Test_name.c", line 25: warning: missing return statement at end of non-void function "abort_struct_complex_cfgs::f1"
3-
}
4-
^
5-
6-
"Test_name.c", line 28: warning: missing return statement at end of non-void function "abort_struct_complex_cfgs::f2"
7-
}
8-
^
9-
102
"Test_name.c", line 31: warning: missing return statement at end of non-void function "abort_struct_complex_cfgs::f2_positive"
113
} // expected-warning {{non-void function does not return a value}}
124
^
135

14-
"Test_name.c", line 34: warning: missing return statement at end of non-void function "abort_struct_complex_cfgs::f3"
15-
}
16-
^
17-
18-
"Test_name.c", line 37: warning: missing return statement at end of non-void function "abort_struct_complex_cfgs::f4"
19-
}
20-
^
21-
226
"Test_name.c", line 36: warning: label "L1" was declared but never referenced
237
switch (x) default: L1: L2: case 4: pr6884_abort_struct();
248
^
@@ -27,10 +11,6 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
2711
switch (x) default: L1: L2: case 4: pr6884_abort_struct();
2812
^
2913

30-
"Test_name.c", line 40: warning: missing return statement at end of non-void function "abort_struct_complex_cfgs::f5"
31-
}
32-
^
33-
3414
"Test_name.c", line 39: warning: label "L1" was declared but never referenced
3515
switch (x) default: L1: { L2: case 4: pr6884_abort_struct(); }
3616
^
@@ -39,10 +19,6 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
3919
switch (x) default: L1: { L2: case 4: pr6884_abort_struct(); }
4020
^
4121

42-
"Test_name.c", line 43: warning: missing return statement at end of non-void function "abort_struct_complex_cfgs::f6"
43-
}
44-
^
45-
4622
"Test_name.c", line 42: warning: label "L1" was declared but never referenced
4723
switch (x) default: L1: L2: case 4: { pr6884_abort_struct(); }
4824
^
@@ -63,26 +39,10 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
6339
switch (x) default: L1: L2: case 4: {
6440
^
6541

66-
"Test_name.c", line 58: warning: missing return statement at end of non-void function "abort_struct_complex_cfgs::g1"
67-
}
68-
^
69-
70-
"Test_name.c", line 62: warning: missing return statement at end of non-void function "abort_struct_complex_cfgs::g2"
71-
}
72-
^
73-
7442
"Test_name.c", line 66: warning: missing return statement at end of non-void function "abort_struct_complex_cfgs::g2_positive"
7543
} // expected-warning {{non-void function does not return a value}}
7644
^
7745

78-
"Test_name.c", line 70: warning: missing return statement at end of non-void function "abort_struct_complex_cfgs::g3"
79-
}
80-
^
81-
82-
"Test_name.c", line 74: warning: missing return statement at end of non-void function "abort_struct_complex_cfgs::g4"
83-
}
84-
^
85-
8646
"Test_name.c", line 73: warning: label "L1" was declared but never referenced
8747
switch (x) default: L1: L2: case 4: pr6884_abort_struct();
8848
^
@@ -91,10 +51,6 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
9151
switch (x) default: L1: L2: case 4: pr6884_abort_struct();
9252
^
9353

94-
"Test_name.c", line 78: warning: missing return statement at end of non-void function "abort_struct_complex_cfgs::g5"
95-
}
96-
^
97-
9854
"Test_name.c", line 77: warning: label "L1" was declared but never referenced
9955
switch (x) default: L1: { L2: case 4: pr6884_abort_struct(); }
10056
^
@@ -103,10 +59,6 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
10359
switch (x) default: L1: { L2: case 4: pr6884_abort_struct(); }
10460
^
10561

106-
"Test_name.c", line 82: warning: missing return statement at end of non-void function "abort_struct_complex_cfgs::g6"
107-
}
108-
^
109-
11062
"Test_name.c", line 81: warning: label "L1" was declared but never referenced
11163
switch (x) default: L1: L2: case 4: { pr6884_abort_struct(); }
11264
^
@@ -163,10 +115,6 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
163115
switch (x) default: L1: L2: case 4: { pr6884_abort_struct a; }
164116
^
165117

166-
"Test_name.c", line 162: warning: missing return statement at end of non-void function "testTernaryUnconditionalNoreturn"
167-
}
168-
^
169-
170118
"Test_name.c", line 166: warning: missing return statement at end of non-void function "testTernaryStaticallyConditionalNoretrunOnTrue"
171119
}
172120
^

‎tests/tests/imported/clang/cpp/SemaCXX/.return-noreturn.rto/edg_x86_32_cp.1.1.txt‎

Lines changed: 0 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,8 @@
11
fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_version 999999 --exceptions --exceptions --c++11 Test_name.c
2-
"Test_name.c", line 25: warning: missing return statement at end of non-void function "abort_struct_complex_cfgs::f1"
3-
}
4-
^
5-
6-
"Test_name.c", line 28: warning: missing return statement at end of non-void function "abort_struct_complex_cfgs::f2"
7-
}
8-
^
9-
102
"Test_name.c", line 31: warning: missing return statement at end of non-void function "abort_struct_complex_cfgs::f2_positive"
113
} // expected-warning {{non-void function does not return a value}}
124
^
135

14-
"Test_name.c", line 34: warning: missing return statement at end of non-void function "abort_struct_complex_cfgs::f3"
15-
}
16-
^
17-
18-
"Test_name.c", line 37: warning: missing return statement at end of non-void function "abort_struct_complex_cfgs::f4"
19-
}
20-
^
21-
226
"Test_name.c", line 36: warning: label "L1" was declared but never referenced
237
switch (x) default: L1: L2: case 4: pr6884_abort_struct();
248
^
@@ -27,10 +11,6 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
2711
switch (x) default: L1: L2: case 4: pr6884_abort_struct();
2812
^
2913

30-
"Test_name.c", line 40: warning: missing return statement at end of non-void function "abort_struct_complex_cfgs::f5"
31-
}
32-
^
33-
3414
"Test_name.c", line 39: warning: label "L1" was declared but never referenced
3515
switch (x) default: L1: { L2: case 4: pr6884_abort_struct(); }
3616
^
@@ -39,10 +19,6 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
3919
switch (x) default: L1: { L2: case 4: pr6884_abort_struct(); }
4020
^
4121

42-
"Test_name.c", line 43: warning: missing return statement at end of non-void function "abort_struct_complex_cfgs::f6"
43-
}
44-
^
45-
4622
"Test_name.c", line 42: warning: label "L1" was declared but never referenced
4723
switch (x) default: L1: L2: case 4: { pr6884_abort_struct(); }
4824
^
@@ -63,26 +39,10 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
6339
switch (x) default: L1: L2: case 4: {
6440
^
6541

66-
"Test_name.c", line 58: warning: missing return statement at end of non-void function "abort_struct_complex_cfgs::g1"
67-
}
68-
^
69-
70-
"Test_name.c", line 62: warning: missing return statement at end of non-void function "abort_struct_complex_cfgs::g2"
71-
}
72-
^
73-
7442
"Test_name.c", line 66: warning: missing return statement at end of non-void function "abort_struct_complex_cfgs::g2_positive"
7543
} // expected-warning {{non-void function does not return a value}}
7644
^
7745

78-
"Test_name.c", line 70: warning: missing return statement at end of non-void function "abort_struct_complex_cfgs::g3"
79-
}
80-
^
81-
82-
"Test_name.c", line 74: warning: missing return statement at end of non-void function "abort_struct_complex_cfgs::g4"
83-
}
84-
^
85-
8646
"Test_name.c", line 73: warning: label "L1" was declared but never referenced
8747
switch (x) default: L1: L2: case 4: pr6884_abort_struct();
8848
^
@@ -91,10 +51,6 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
9151
switch (x) default: L1: L2: case 4: pr6884_abort_struct();
9252
^
9353

94-
"Test_name.c", line 78: warning: missing return statement at end of non-void function "abort_struct_complex_cfgs::g5"
95-
}
96-
^
97-
9854
"Test_name.c", line 77: warning: label "L1" was declared but never referenced
9955
switch (x) default: L1: { L2: case 4: pr6884_abort_struct(); }
10056
^
@@ -103,10 +59,6 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
10359
switch (x) default: L1: { L2: case 4: pr6884_abort_struct(); }
10460
^
10561

106-
"Test_name.c", line 82: warning: missing return statement at end of non-void function "abort_struct_complex_cfgs::g6"
107-
}
108-
^
109-
11062
"Test_name.c", line 81: warning: label "L1" was declared but never referenced
11163
switch (x) default: L1: L2: case 4: { pr6884_abort_struct(); }
11264
^
@@ -167,10 +119,6 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
167119
} // expected-warning {{non-void function does not return a value}}
168120
^
169121

170-
"Test_name.c", line 162: warning: missing return statement at end of non-void function "testTernaryUnconditionalNoreturn"
171-
}
172-
^
173-
174122
"Test_name.c", line 166: warning: missing return statement at end of non-void function "testTernaryStaticallyConditionalNoretrunOnTrue"
175123
}
176124
^

0 commit comments

Comments
 (0)