Skip to content

Commit 03797b8

Browse files
committed
Enable implicit fall-through errors
1 parent 88aae15 commit 03797b8

File tree

4 files changed

+42
-30
lines changed

4 files changed

+42
-30
lines changed

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ FUZZ_OUTPUT_DIR = $(CURDIR)/fuzz/output
1111
SOEXT ?= $(shell ruby -e 'puts RbConfig::CONFIG["SOEXT"]')
1212

1313
CPPFLAGS := -Iinclude $(CPPFLAGS)
14-
CFLAGS := -g -O2 -std=c99 -Wall -Werror -Wextra -Wpedantic -Wundef -Wconversion -Wno-missing-braces -fPIC -fvisibility=hidden $(CFLAGS)
14+
CFLAGS := -g -O2 -std=c99 -Wall -Werror -Wextra -Wpedantic -Wundef -Wconversion -Wno-missing-braces -fPIC -fvisibility=hidden -Wimplicit-fallthrough $(CFLAGS)
1515
CC ?= cc
1616
AR ?= ar
1717
WASI_SDK_PATH := /opt/wasi-sdk

include/prism/defines.h

+12
Original file line numberDiff line numberDiff line change
@@ -240,4 +240,16 @@
240240
#define PRISM_UNLIKELY(x) (x)
241241
#endif
242242

243+
/**
244+
* We use -Wimplicit-fallthrough to guard potentially unintended fall-through between cases of a switch.
245+
* Use PRISM_FALLTHROUGH to explicitly annotate cases where the fallthrough is intentional.
246+
*/
247+
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L // C23 or later
248+
#define PRISM_FALLTHROUGH [[fallthrough]];
249+
#elif defined(__GNUC__) || defined(__clang__)
250+
#define PRISM_FALLTHROUGH __attribute__((fallthrough));
251+
#elif defined(_MSC_VER)
252+
#define PRISM_FALLTHROUGH __fallthrough;
253+
#endif
254+
243255
#endif

src/prism.c

+27-26
Original file line numberDiff line numberDiff line change
@@ -9110,7 +9110,7 @@ lex_global_variable(pm_parser_t *parser) {
91109110
case '-':
91119111
parser->current.end++;
91129112
allow_multiple = false;
9113-
/* fallthrough */
9113+
PRISM_FALLTHROUGH
91149114
default: {
91159115
size_t width;
91169116

@@ -10046,8 +10046,8 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
1004610046
escape_write_byte_encoded(parser, buffer, escape_byte('\n', flags));
1004710047
return;
1004810048
}
10049+
PRISM_FALLTHROUGH
1004910050
}
10050-
/* fallthrough */
1005110051
default: {
1005210052
if (parser->current.end < parser->end) {
1005310053
escape_write_escape_encoded(parser, buffer);
@@ -10750,7 +10750,7 @@ parser_lex(pm_parser_t *parser) {
1075010750

1075110751
lexed_comment = true;
1075210752
}
10753-
/* fallthrough */
10753+
PRISM_FALLTHROUGH
1075410754
case '\r':
1075510755
case '\n': {
1075610756
parser->semantic_token_seen = semantic_token_seen & 0x1;
@@ -10792,7 +10792,7 @@ parser_lex(pm_parser_t *parser) {
1079210792
parser->current.type = PM_TOKEN_NEWLINE;
1079310793
return;
1079410794
}
10795-
/* fallthrough */
10795+
PRISM_FALLTHROUGH
1079610796
case PM_IGNORED_NEWLINE_ALL:
1079710797
if (!lexed_comment) parser_lex_ignored_newline(parser);
1079810798
lexed_comment = false;
@@ -11807,7 +11807,7 @@ parser_lex(pm_parser_t *parser) {
1180711807
PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE, "escaped carriage return");
1180811808
break;
1180911809
}
11810-
/* fallthrough */
11810+
PRISM_FALLTHROUGH
1181111811
default:
1181211812
PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE, "backslash");
1181311813
break;
@@ -12004,7 +12004,7 @@ parser_lex(pm_parser_t *parser) {
1200412004
pm_token_buffer_push_byte(&token_buffer, '\r');
1200512005
break;
1200612006
}
12007-
/* fallthrough */
12007+
PRISM_FALLTHROUGH
1200812008
case '\n':
1200912009
pm_token_buffer_push_byte(&token_buffer, '\n');
1201012010

@@ -12191,7 +12191,7 @@ parser_lex(pm_parser_t *parser) {
1219112191
pm_regexp_token_buffer_escape(parser, &token_buffer);
1219212192
token_buffer.base.cursor = breakpoint;
1219312193

12194-
/* fallthrough */
12194+
PRISM_FALLTHROUGH
1219512195
case '\n':
1219612196
// If we've hit a newline, then we need to track that in
1219712197
// the list of newlines.
@@ -12233,7 +12233,7 @@ parser_lex(pm_parser_t *parser) {
1223312233
pm_token_buffer_push_byte(&token_buffer.base, '\r');
1223412234
break;
1223512235
}
12236-
/* fallthrough */
12236+
PRISM_FALLTHROUGH
1223712237
case '\n':
1223812238
if (parser->heredoc_end) {
1223912239
// ... if we are on the same line as a heredoc,
@@ -12441,7 +12441,7 @@ parser_lex(pm_parser_t *parser) {
1244112441
pm_token_buffer_escape(parser, &token_buffer);
1244212442
token_buffer.cursor = breakpoint;
1244312443

12444-
/* fallthrough */
12444+
PRISM_FALLTHROUGH
1244512445
case '\n':
1244612446
// When we hit a newline, we need to flush any potential
1244712447
// heredocs. Note that this has to happen after we check
@@ -12486,7 +12486,7 @@ parser_lex(pm_parser_t *parser) {
1248612486
pm_token_buffer_push_byte(&token_buffer, '\r');
1248712487
break;
1248812488
}
12489-
/* fallthrough */
12489+
PRISM_FALLTHROUGH
1249012490
case '\n':
1249112491
if (!lex_mode->as.string.interpolation) {
1249212492
pm_token_buffer_push_byte(&token_buffer, '\\');
@@ -12694,7 +12694,7 @@ parser_lex(pm_parser_t *parser) {
1269412694
pm_token_buffer_escape(parser, &token_buffer);
1269512695
token_buffer.cursor = breakpoint;
1269612696

12697-
/* fallthrough */
12697+
PRISM_FALLTHROUGH
1269812698
case '\n': {
1269912699
if (parser->heredoc_end != NULL && (parser->heredoc_end > breakpoint)) {
1270012700
parser_flush_heredoc_end(parser);
@@ -12794,7 +12794,7 @@ parser_lex(pm_parser_t *parser) {
1279412794
pm_token_buffer_push_byte(&token_buffer, '\r');
1279512795
break;
1279612796
}
12797-
/* fallthrough */
12797+
PRISM_FALLTHROUGH
1279812798
case '\n':
1279912799
pm_token_buffer_push_byte(&token_buffer, '\\');
1280012800
pm_token_buffer_push_byte(&token_buffer, '\n');
@@ -12814,7 +12814,7 @@ parser_lex(pm_parser_t *parser) {
1281412814
pm_token_buffer_push_byte(&token_buffer, '\r');
1281512815
break;
1281612816
}
12817-
/* fallthrough */
12817+
PRISM_FALLTHROUGH
1281812818
case '\n':
1281912819
// If we are in a tilde here, we should
1282012820
// break out of the loop and return the
@@ -13536,7 +13536,7 @@ parse_target(pm_parser_t *parser, pm_node_t *target, bool multiple, bool splat_p
1353613536
return (pm_node_t *) pm_index_target_node_create(parser, call);
1353713537
}
1353813538
}
13539-
/* fallthrough */
13539+
PRISM_FALLTHROUGH
1354013540
default:
1354113541
// In this case we have a node that we don't know how to convert
1354213542
// into a target. We need to treat it as an error. For now, we'll
@@ -13618,7 +13618,7 @@ parse_write(pm_parser_t *parser, pm_node_t *target, pm_token_t *operator, pm_nod
1361813618
case PM_BACK_REFERENCE_READ_NODE:
1361913619
case PM_NUMBERED_REFERENCE_READ_NODE:
1362013620
PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
13621-
/* fallthrough */
13621+
PRISM_FALLTHROUGH
1362213622
case PM_GLOBAL_VARIABLE_READ_NODE: {
1362313623
pm_global_variable_write_node_t *node = pm_global_variable_write_node_create(parser, target, operator, value);
1362413624
pm_node_destroy(parser, target);
@@ -13760,7 +13760,7 @@ parse_write(pm_parser_t *parser, pm_node_t *target, pm_token_t *operator, pm_nod
1376013760
// is no way for us to attach it to the tree at this point.
1376113761
pm_node_destroy(parser, value);
1376213762
}
13763-
/* fallthrough */
13763+
PRISM_FALLTHROUGH
1376413764
default:
1376513765
// In this case we have a node that we don't know how to convert into a
1376613766
// target. We need to treat it as an error. For now, we'll mark it as an
@@ -14280,7 +14280,7 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for
1428014280
}
1428114281
}
1428214282
}
14283-
/* fallthrough */
14283+
PRISM_FALLTHROUGH
1428414284
default: {
1428514285
if (argument == NULL) {
1428614286
argument = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, !parsed_first_argument, true, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
@@ -16168,7 +16168,7 @@ parse_operator_symbol_name(const pm_token_t *name) {
1616816168
case PM_TOKEN_TILDE:
1616916169
case PM_TOKEN_BANG:
1617016170
if (name->end[-1] == '@') return name->end - 1;
16171-
/* fallthrough */
16171+
PRISM_FALLTHROUGH
1617216172
default:
1617316173
return name->end;
1617416174
}
@@ -17140,7 +17140,7 @@ parse_pattern_hash(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node
1714017140
break;
1714117141
}
1714217142
}
17143-
/* fallthrough */
17143+
PRISM_FALLTHROUGH
1714417144
default: {
1714517145
// If we get anything else, then this is an error. For this we'll
1714617146
// create a missing node for the value and create an assoc node for
@@ -17636,7 +17636,7 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag
1763617636
break;
1763717637
}
1763817638
}
17639-
/* fallthrough */
17639+
PRISM_FALLTHROUGH
1764017640
default:
1764117641
node = parse_pattern_primitives(parser, captures, NULL, diag_id, (uint16_t) (depth + 1));
1764217642
break;
@@ -18766,7 +18766,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
1876618766
pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
1876718767
}
1876818768
}
18769-
/* fallthrough */
18769+
PRISM_FALLTHROUGH
1877018770
default:
1877118771
return (pm_node_t *) pm_alias_method_node_create(parser, &keyword, new_name, old_name);
1877218772
}
@@ -19294,7 +19294,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
1929419294
case PM_TOKEN_CLASS_VARIABLE:
1929519295
case PM_TOKEN_GLOBAL_VARIABLE:
1929619296
valid_name = false;
19297-
/* fallthrough */
19297+
PRISM_FALLTHROUGH
1929819298
case PM_TOKEN_CONSTANT:
1929919299
case PM_TOKEN_KEYWORD_NIL:
1930019300
case PM_TOKEN_KEYWORD_SELF:
@@ -20964,7 +20964,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
2096420964
pm_parser_local_add_location(parser, call_node->message_loc.start, call_node->message_loc.end, 0);
2096520965
}
2096620966
}
20967-
/* fallthrough */
20967+
PRISM_FALLTHROUGH
2096820968
case PM_CASE_WRITABLE: {
2096920969
parser_lex(parser);
2097020970
pm_node_t *value = parse_assignment_values(parser, previous_binding_power, PM_NODE_TYPE_P(node, PM_MULTI_TARGET_NODE) ? PM_BINDING_POWER_MULTI_ASSIGNMENT + 1 : binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL, (uint16_t) (depth + 1));
@@ -21010,7 +21010,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
2101021010
case PM_BACK_REFERENCE_READ_NODE:
2101121011
case PM_NUMBERED_REFERENCE_READ_NODE:
2101221012
PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21013-
/* fallthrough */
21013+
PRISM_FALLTHROUGH
2101421014
case PM_GLOBAL_VARIABLE_READ_NODE: {
2101521015
parser_lex(parser);
2101621016

@@ -21128,7 +21128,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
2112821128
case PM_BACK_REFERENCE_READ_NODE:
2112921129
case PM_NUMBERED_REFERENCE_READ_NODE:
2113021130
PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21131-
/* fallthrough */
21131+
PRISM_FALLTHROUGH
2113221132
case PM_GLOBAL_VARIABLE_READ_NODE: {
2113321133
parser_lex(parser);
2113421134

@@ -21256,7 +21256,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
2125621256
case PM_BACK_REFERENCE_READ_NODE:
2125721257
case PM_NUMBERED_REFERENCE_READ_NODE:
2125821258
PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21259-
/* fallthrough */
21259+
PRISM_FALLTHROUGH
2126021260
case PM_GLOBAL_VARIABLE_READ_NODE: {
2126121261
parser_lex(parser);
2126221262

@@ -21893,6 +21893,7 @@ parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool acc
2189321893
if (pm_symbol_node_label_p(node)) {
2189421894
return node;
2189521895
}
21896+
break;
2189621897
default:
2189721898
break;
2189821899
}

src/regexp.c

+2-3
Original file line numberDiff line numberDiff line change
@@ -599,8 +599,7 @@ pm_regexp_parse_group(pm_regexp_parser_t *parser, uint16_t depth) {
599599
// If we hit a -, then we're done parsing options.
600600
if (*parser->cursor != '-') break;
601601

602-
// Otherwise, fallthrough to the - case.
603-
/* fallthrough */
602+
PRISM_FALLTHROUGH
604603
case '-':
605604
parser->cursor++;
606605
while (!pm_regexp_char_is_eof(parser) && *parser->cursor != ':' && *parser->cursor != ')') {
@@ -712,7 +711,7 @@ pm_regexp_parse_item(pm_regexp_parser_t *parser, uint16_t depth) {
712711
if (!pm_regexp_char_find(parser, '\n')) parser->cursor = parser->end;
713712
return true;
714713
}
715-
/* fallthrough */
714+
PRISM_FALLTHROUGH
716715
default: {
717716
size_t width;
718717
if (!parser->encoding_changed) {

0 commit comments

Comments
 (0)