Skip to content
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: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ FUZZ_OUTPUT_DIR = $(CURDIR)/fuzz/output
SOEXT ?= $(shell ruby -e 'puts RbConfig::CONFIG["SOEXT"]')

CPPFLAGS := -Iinclude $(CPPFLAGS)
CFLAGS := -g -O2 -std=c99 -Wall -Werror -Wextra -Wpedantic -Wundef -Wconversion -Wno-missing-braces -fPIC -fvisibility=hidden $(CFLAGS)
CFLAGS := -g -O2 -std=c99 -Wall -Werror -Wextra -Wpedantic -Wundef -Wconversion -Wno-missing-braces -fPIC -fvisibility=hidden -Wimplicit-fallthrough $(CFLAGS)
CC ?= cc
AR ?= ar
WASI_SDK_PATH := /opt/wasi-sdk
Expand Down
12 changes: 12 additions & 0 deletions include/prism/defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -240,4 +240,16 @@
#define PRISM_UNLIKELY(x) (x)
#endif

/**
* We use -Wimplicit-fallthrough to guard potentially unintended fall-through between cases of a switch.
* Use PRISM_FALLTHROUGH to explicitly annotate cases where the fallthrough is intentional.
*/
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L // C23 or later
#define PRISM_FALLTHROUGH [[fallthrough]];
#elif defined(__GNUC__) || defined(__clang__)
#define PRISM_FALLTHROUGH __attribute__((fallthrough));
#elif defined(_MSC_VER)
#define PRISM_FALLTHROUGH __fallthrough;
#endif

#endif
53 changes: 27 additions & 26 deletions src/prism.c
Original file line number Diff line number Diff line change
Expand Up @@ -9110,7 +9110,7 @@ lex_global_variable(pm_parser_t *parser) {
case '-':
parser->current.end++;
allow_multiple = false;
/* fallthrough */
PRISM_FALLTHROUGH
default: {
size_t width;

Expand Down Expand Up @@ -10046,8 +10046,8 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
escape_write_byte_encoded(parser, buffer, escape_byte('\n', flags));
return;
}
PRISM_FALLTHROUGH
}
/* fallthrough */
default: {
if (parser->current.end < parser->end) {
escape_write_escape_encoded(parser, buffer);
Expand Down Expand Up @@ -10750,7 +10750,7 @@ parser_lex(pm_parser_t *parser) {

lexed_comment = true;
}
/* fallthrough */
PRISM_FALLTHROUGH
case '\r':
case '\n': {
parser->semantic_token_seen = semantic_token_seen & 0x1;
Expand Down Expand Up @@ -10792,7 +10792,7 @@ parser_lex(pm_parser_t *parser) {
parser->current.type = PM_TOKEN_NEWLINE;
return;
}
/* fallthrough */
PRISM_FALLTHROUGH
case PM_IGNORED_NEWLINE_ALL:
if (!lexed_comment) parser_lex_ignored_newline(parser);
lexed_comment = false;
Expand Down Expand Up @@ -11807,7 +11807,7 @@ parser_lex(pm_parser_t *parser) {
PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE, "escaped carriage return");
break;
}
/* fallthrough */
PRISM_FALLTHROUGH
default:
PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE, "backslash");
break;
Expand Down Expand Up @@ -12004,7 +12004,7 @@ parser_lex(pm_parser_t *parser) {
pm_token_buffer_push_byte(&token_buffer, '\r');
break;
}
/* fallthrough */
PRISM_FALLTHROUGH
case '\n':
pm_token_buffer_push_byte(&token_buffer, '\n');

Expand Down Expand Up @@ -12191,7 +12191,7 @@ parser_lex(pm_parser_t *parser) {
pm_regexp_token_buffer_escape(parser, &token_buffer);
token_buffer.base.cursor = breakpoint;

/* fallthrough */
PRISM_FALLTHROUGH
case '\n':
// If we've hit a newline, then we need to track that in
// the list of newlines.
Expand Down Expand Up @@ -12233,7 +12233,7 @@ parser_lex(pm_parser_t *parser) {
pm_token_buffer_push_byte(&token_buffer.base, '\r');
break;
}
/* fallthrough */
PRISM_FALLTHROUGH
case '\n':
if (parser->heredoc_end) {
// ... if we are on the same line as a heredoc,
Expand Down Expand Up @@ -12441,7 +12441,7 @@ parser_lex(pm_parser_t *parser) {
pm_token_buffer_escape(parser, &token_buffer);
token_buffer.cursor = breakpoint;

/* fallthrough */
PRISM_FALLTHROUGH
case '\n':
// When we hit a newline, we need to flush any potential
// heredocs. Note that this has to happen after we check
Expand Down Expand Up @@ -12486,7 +12486,7 @@ parser_lex(pm_parser_t *parser) {
pm_token_buffer_push_byte(&token_buffer, '\r');
break;
}
/* fallthrough */
PRISM_FALLTHROUGH
case '\n':
if (!lex_mode->as.string.interpolation) {
pm_token_buffer_push_byte(&token_buffer, '\\');
Expand Down Expand Up @@ -12694,7 +12694,7 @@ parser_lex(pm_parser_t *parser) {
pm_token_buffer_escape(parser, &token_buffer);
token_buffer.cursor = breakpoint;

/* fallthrough */
PRISM_FALLTHROUGH
case '\n': {
if (parser->heredoc_end != NULL && (parser->heredoc_end > breakpoint)) {
parser_flush_heredoc_end(parser);
Expand Down Expand Up @@ -12794,7 +12794,7 @@ parser_lex(pm_parser_t *parser) {
pm_token_buffer_push_byte(&token_buffer, '\r');
break;
}
/* fallthrough */
PRISM_FALLTHROUGH
case '\n':
pm_token_buffer_push_byte(&token_buffer, '\\');
pm_token_buffer_push_byte(&token_buffer, '\n');
Expand All @@ -12814,7 +12814,7 @@ parser_lex(pm_parser_t *parser) {
pm_token_buffer_push_byte(&token_buffer, '\r');
break;
}
/* fallthrough */
PRISM_FALLTHROUGH
case '\n':
// If we are in a tilde here, we should
// break out of the loop and return the
Expand Down Expand Up @@ -13536,7 +13536,7 @@ parse_target(pm_parser_t *parser, pm_node_t *target, bool multiple, bool splat_p
return (pm_node_t *) pm_index_target_node_create(parser, call);
}
}
/* fallthrough */
PRISM_FALLTHROUGH
default:
// In this case we have a node that we don't know how to convert
// into a target. We need to treat it as an error. For now, we'll
Expand Down Expand Up @@ -13618,7 +13618,7 @@ parse_write(pm_parser_t *parser, pm_node_t *target, pm_token_t *operator, pm_nod
case PM_BACK_REFERENCE_READ_NODE:
case PM_NUMBERED_REFERENCE_READ_NODE:
PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
/* fallthrough */
PRISM_FALLTHROUGH
case PM_GLOBAL_VARIABLE_READ_NODE: {
pm_global_variable_write_node_t *node = pm_global_variable_write_node_create(parser, target, operator, value);
pm_node_destroy(parser, target);
Expand Down Expand Up @@ -13760,7 +13760,7 @@ parse_write(pm_parser_t *parser, pm_node_t *target, pm_token_t *operator, pm_nod
// is no way for us to attach it to the tree at this point.
pm_node_destroy(parser, value);
}
/* fallthrough */
PRISM_FALLTHROUGH
default:
// In this case we have a node that we don't know how to convert into a
// target. We need to treat it as an error. For now, we'll mark it as an
Expand Down Expand Up @@ -14280,7 +14280,7 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for
}
}
}
/* fallthrough */
PRISM_FALLTHROUGH
default: {
if (argument == NULL) {
argument = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, !parsed_first_argument, true, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
Expand Down Expand Up @@ -16168,7 +16168,7 @@ parse_operator_symbol_name(const pm_token_t *name) {
case PM_TOKEN_TILDE:
case PM_TOKEN_BANG:
if (name->end[-1] == '@') return name->end - 1;
/* fallthrough */
PRISM_FALLTHROUGH
default:
return name->end;
}
Expand Down Expand Up @@ -17140,7 +17140,7 @@ parse_pattern_hash(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node
break;
}
}
/* fallthrough */
PRISM_FALLTHROUGH
default: {
// If we get anything else, then this is an error. For this we'll
// create a missing node for the value and create an assoc node for
Expand Down Expand Up @@ -17636,7 +17636,7 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag
break;
}
}
/* fallthrough */
PRISM_FALLTHROUGH
default:
node = parse_pattern_primitives(parser, captures, NULL, diag_id, (uint16_t) (depth + 1));
break;
Expand Down Expand Up @@ -18766,7 +18766,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
}
}
/* fallthrough */
PRISM_FALLTHROUGH
default:
return (pm_node_t *) pm_alias_method_node_create(parser, &keyword, new_name, old_name);
}
Expand Down Expand Up @@ -19294,7 +19294,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
case PM_TOKEN_CLASS_VARIABLE:
case PM_TOKEN_GLOBAL_VARIABLE:
valid_name = false;
/* fallthrough */
PRISM_FALLTHROUGH
case PM_TOKEN_CONSTANT:
case PM_TOKEN_KEYWORD_NIL:
case PM_TOKEN_KEYWORD_SELF:
Expand Down Expand Up @@ -20964,7 +20964,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
pm_parser_local_add_location(parser, call_node->message_loc.start, call_node->message_loc.end, 0);
}
}
/* fallthrough */
PRISM_FALLTHROUGH
case PM_CASE_WRITABLE: {
parser_lex(parser);
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));
Expand Down Expand Up @@ -21010,7 +21010,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
case PM_BACK_REFERENCE_READ_NODE:
case PM_NUMBERED_REFERENCE_READ_NODE:
PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
/* fallthrough */
PRISM_FALLTHROUGH
case PM_GLOBAL_VARIABLE_READ_NODE: {
parser_lex(parser);

Expand Down Expand Up @@ -21128,7 +21128,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
case PM_BACK_REFERENCE_READ_NODE:
case PM_NUMBERED_REFERENCE_READ_NODE:
PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
/* fallthrough */
PRISM_FALLTHROUGH
case PM_GLOBAL_VARIABLE_READ_NODE: {
parser_lex(parser);

Expand Down Expand Up @@ -21256,7 +21256,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
case PM_BACK_REFERENCE_READ_NODE:
case PM_NUMBERED_REFERENCE_READ_NODE:
PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
/* fallthrough */
PRISM_FALLTHROUGH
case PM_GLOBAL_VARIABLE_READ_NODE: {
parser_lex(parser);

Expand Down Expand Up @@ -21893,6 +21893,7 @@ parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool acc
if (pm_symbol_node_label_p(node)) {
return node;
}
break;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one had an implicit fall-through that wasn't annotated.

Since the default case it falls into only does a break, I just added its own break instead of PRISM_FALLTHROUGH.

default:
break;
}
Expand Down
5 changes: 2 additions & 3 deletions src/regexp.c
Original file line number Diff line number Diff line change
Expand Up @@ -599,8 +599,7 @@ pm_regexp_parse_group(pm_regexp_parser_t *parser, uint16_t depth) {
// If we hit a -, then we're done parsing options.
if (*parser->cursor != '-') break;

// Otherwise, fallthrough to the - case.
/* fallthrough */
PRISM_FALLTHROUGH
case '-':
parser->cursor++;
while (!pm_regexp_char_is_eof(parser) && *parser->cursor != ':' && *parser->cursor != ')') {
Expand Down Expand Up @@ -712,7 +711,7 @@ pm_regexp_parse_item(pm_regexp_parser_t *parser, uint16_t depth) {
if (!pm_regexp_char_find(parser, '\n')) parser->cursor = parser->end;
return true;
}
/* fallthrough */
PRISM_FALLTHROUGH
default: {
size_t width;
if (!parser->encoding_changed) {
Expand Down
Loading