diff --git a/acinclude.m4 b/acinclude.m4 index d7f27a62a..8a0750400 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -2,6 +2,7 @@ m4_include([m4.include/ac_onceonly.m4]) m4_include([m4.include/ax_path_lib_pcre.m4]) m4_include([m4.include/dx_doxygen.m4]) m4_include([m4.include/mc-cflags.m4]) +m4_include([m4.include/ax_gcc_func_attribute.m4]) m4_include([m4.include/mc-check-search-type.m4]) m4_include([m4.include/mode_t.m4]) m4_include([m4.include/stat-size.m4]) diff --git a/configure.ac b/configure.ac index 65618d5e7..bf2e98b2a 100644 --- a/configure.ac +++ b/configure.ac @@ -45,6 +45,8 @@ if test "x$enable_werror" = xyes; then mc_CHECK_ONE_CFLAG([-Werror]) fi +AX_GCC_FUNC_ATTRIBUTE([fallthrough]) + AC_PROG_LIBTOOL diff --git a/lib/global.h b/lib/global.h index 8f32c946f..1ab3ee0ef 100644 --- a/lib/global.h +++ b/lib/global.h @@ -27,6 +27,12 @@ /* for sig_atomic_t */ #include +#ifdef HAVE_FUNC_ATTRIBUTE_FALLTHROUGH +#define MC_FALLTHROUGH __attribute__((fallthrough)) +#else +#define MC_FALLTHROUGH +#endif + /*** typedefs(not structures) and defined constants **********************************************/ /* The O_BINARY definition was taken from gettext */ diff --git a/lib/search/normal.c b/lib/search/normal.c index d074be71f..a2fa0d022 100644 --- a/lib/search/normal.c +++ b/lib/search/normal.c @@ -71,7 +71,7 @@ mc_search__normal_translate_to_regex (const GString * astr) case '-': case '|': g_string_append_c (buff, '\\'); - /* fall through */ + MC_FALLTHROUGH; default: g_string_append_c (buff, str[loop]); break; diff --git a/lib/widget/input_complete.c b/lib/widget/input_complete.c index fc6406792..046ab7cc5 100644 --- a/lib/widget/input_complete.c +++ b/lib/widget/input_complete.c @@ -641,7 +641,7 @@ command_completion_function (const char *text, int state, input_complete_t flags } phase++; words = bash_builtins; - /* fallthrough */ + MC_FALLTHROUGH; case 1: /* Builtin commands */ for (; *words != NULL; words++) if (strncmp (*words, u_text, text_len) == 0) @@ -654,7 +654,7 @@ command_completion_function (const char *text, int state, input_complete_t flags break; cur_path = path; cur_word = NULL; - /* fallthrough */ + MC_FALLTHROUGH; case 2: /* And looking through the $PATH */ while (found == NULL) { @@ -675,7 +675,7 @@ command_completion_function (const char *text, int state, input_complete_t flags if (found == NULL) MC_PTR_FREE (cur_word); } - /* fallthrough */ + MC_FALLTHROUGH; default: break; } @@ -1107,7 +1107,7 @@ query_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *d { case -1: bl = 0; - /* fallthrough */ + MC_FALLTHROUGH; case -2: return MSG_HANDLED; default: diff --git a/lib/widget/quick.c b/lib/widget/quick.c index 0e834ed7b..52e4c061b 100644 --- a/lib/widget/quick.c +++ b/lib/widget/quick.c @@ -441,7 +441,7 @@ quick_dialog_skip (quick_dialog_t * quick_dlg, int nskip) break; } } - /* fall through */ + MC_FALLTHROUGH; case quick_checkbox: case quick_radio: if (item->widget->x != x1) diff --git a/lib/widget/wtools.c b/lib/widget/wtools.c index e1e0534f6..4e3a2fade 100644 --- a/lib/widget/wtools.c +++ b/lib/widget/wtools.c @@ -105,7 +105,7 @@ query_default_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, return MSG_HANDLED; } - /* fallthrough */ + MC_FALLTHROUGH; default: return dlg_default_callback (w, sender, msg, parm, data); diff --git a/m4.include/ax_gcc_func_attribute.m4 b/m4.include/ax_gcc_func_attribute.m4 new file mode 100644 index 000000000..098c9aadf --- /dev/null +++ b/m4.include/ax_gcc_func_attribute.m4 @@ -0,0 +1,238 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_gcc_func_attribute.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_GCC_FUNC_ATTRIBUTE(ATTRIBUTE) +# +# DESCRIPTION +# +# This macro checks if the compiler supports one of GCC's function +# attributes; many other compilers also provide function attributes with +# the same syntax. Compiler warnings are used to detect supported +# attributes as unsupported ones are ignored by default so quieting +# warnings when using this macro will yield false positives. +# +# The ATTRIBUTE parameter holds the name of the attribute to be checked. +# +# If ATTRIBUTE is supported define HAVE_FUNC_ATTRIBUTE_. +# +# The macro caches its result in the ax_cv_have_func_attribute_ +# variable. +# +# The macro currently supports the following function attributes: +# +# alias +# aligned +# alloc_size +# always_inline +# artificial +# cold +# const +# constructor +# constructor_priority for constructor attribute with priority +# deprecated +# destructor +# dllexport +# dllimport +# error +# externally_visible +# fallthrough +# flatten +# format +# format_arg +# gnu_inline +# hot +# ifunc +# leaf +# malloc +# noclone +# noinline +# nonnull +# noreturn +# nothrow +# optimize +# pure +# sentinel +# sentinel_position +# unused +# used +# visibility +# warning +# warn_unused_result +# weak +# weakref +# +# Unsupported function attributes will be tested with a prototype +# returning an int and not accepting any arguments and the result of the +# check might be wrong or meaningless so use with care. +# +# LICENSE +# +# Copyright (c) 2013 Gabriele Svelto +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 9 + +AC_DEFUN([AX_GCC_FUNC_ATTRIBUTE], [ + AS_VAR_PUSHDEF([ac_var], [ax_cv_have_func_attribute_$1]) + + AC_CACHE_CHECK([for __attribute__(($1))], [ac_var], [ + AC_LINK_IFELSE([AC_LANG_PROGRAM([ + m4_case([$1], + [alias], [ + int foo( void ) { return 0; } + int bar( void ) __attribute__(($1("foo"))); + ], + [aligned], [ + int foo( void ) __attribute__(($1(32))); + ], + [alloc_size], [ + void *foo(int a) __attribute__(($1(1))); + ], + [always_inline], [ + inline __attribute__(($1)) int foo( void ) { return 0; } + ], + [artificial], [ + inline __attribute__(($1)) int foo( void ) { return 0; } + ], + [cold], [ + int foo( void ) __attribute__(($1)); + ], + [const], [ + int foo( void ) __attribute__(($1)); + ], + [constructor_priority], [ + int foo( void ) __attribute__((__constructor__(65535/2))); + ], + [constructor], [ + int foo( void ) __attribute__(($1)); + ], + [deprecated], [ + int foo( void ) __attribute__(($1(""))); + ], + [destructor], [ + int foo( void ) __attribute__(($1)); + ], + [dllexport], [ + __attribute__(($1)) int foo( void ) { return 0; } + ], + [dllimport], [ + int foo( void ) __attribute__(($1)); + ], + [error], [ + int foo( void ) __attribute__(($1(""))); + ], + [externally_visible], [ + int foo( void ) __attribute__(($1)); + ], + [fallthrough], [ + int foo( void ) {switch (0) { case 1: __attribute__(($1)); case 2: break ; }}; + ], + [flatten], [ + int foo( void ) __attribute__(($1)); + ], + [format], [ + int foo(const char *p, ...) __attribute__(($1(printf, 1, 2))); + ], + [format_arg], [ + char *foo(const char *p) __attribute__(($1(1))); + ], + [gnu_inline], [ + inline __attribute__(($1)) int foo( void ) { return 0; } + ], + [hot], [ + int foo( void ) __attribute__(($1)); + ], + [ifunc], [ + int my_foo( void ) { return 0; } + static int (*resolve_foo(void))(void) { return my_foo; } + int foo( void ) __attribute__(($1("resolve_foo"))); + ], + [leaf], [ + __attribute__(($1)) int foo( void ) { return 0; } + ], + [malloc], [ + void *foo( void ) __attribute__(($1)); + ], + [noclone], [ + int foo( void ) __attribute__(($1)); + ], + [noinline], [ + __attribute__(($1)) int foo( void ) { return 0; } + ], + [nonnull], [ + int foo(char *p) __attribute__(($1(1))); + ], + [noreturn], [ + void foo( void ) __attribute__(($1)); + ], + [nothrow], [ + int foo( void ) __attribute__(($1)); + ], + [optimize], [ + __attribute__(($1(3))) int foo( void ) { return 0; } + ], + [pure], [ + int foo( void ) __attribute__(($1)); + ], + [sentinel], [ + int foo(void *p, ...) __attribute__(($1)); + ], + [sentinel_position], [ + int foo(void *p, ...) __attribute__(($1(1))); + ], + [returns_nonnull], [ + void *foo( void ) __attribute__(($1)); + ], + [unused], [ + int foo( void ) __attribute__(($1)); + ], + [used], [ + int foo( void ) __attribute__(($1)); + ], + [visibility], [ + int foo_def( void ) __attribute__(($1("default"))); + int foo_hid( void ) __attribute__(($1("hidden"))); + int foo_int( void ) __attribute__(($1("internal"))); + int foo_pro( void ) __attribute__(($1("protected"))); + ], + [warning], [ + int foo( void ) __attribute__(($1(""))); + ], + [warn_unused_result], [ + int foo( void ) __attribute__(($1)); + ], + [weak], [ + int foo( void ) __attribute__(($1)); + ], + [weakref], [ + static int foo( void ) { return 0; } + static int bar( void ) __attribute__(($1("foo"))); + ], + [ + m4_warn([syntax], [Unsupported attribute $1, the test may fail]) + int foo( void ) __attribute__(($1)); + ] + )], []) + ], + dnl GCC doesn't exit with an error if an unknown attribute is + dnl provided but only outputs a warning, so accept the attribute + dnl only if no warning were issued. + [AS_IF([test -s conftest.err], + [AS_VAR_SET([ac_var], [no])], + [AS_VAR_SET([ac_var], [yes])])], + [AS_VAR_SET([ac_var], [no])]) + ]) + + AS_IF([test yes = AS_VAR_GET([ac_var])], + [AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_FUNC_ATTRIBUTE_$1), 1, + [Define to 1 if the system has the `$1' function attribute])], []) + + AS_VAR_POPDEF([ac_var]) +]) diff --git a/m4.include/mc-cflags.m4 b/m4.include/mc-cflags.m4 index af692c79b..9faac606a 100644 --- a/m4.include/mc-cflags.m4 +++ b/m4.include/mc-cflags.m4 @@ -63,6 +63,7 @@ dnl Sorted -W options: mc_CHECK_ONE_CFLAG([-Wformat-security]) mc_CHECK_ONE_CFLAG([-Wformat-signedness]) mc_CHECK_ONE_CFLAG([-Wimplicit]) + mc_CHECK_ONE_CFLAG([-Wimplicit-fallthrough]) mc_CHECK_ONE_CFLAG([-Wignored-qualifiers]) mc_CHECK_ONE_CFLAG([-Wlogical-not-parentheses]) mc_CHECK_ONE_CFLAG([-Wmaybe-uninitialized]) diff --git a/src/args.c b/src/args.c index a9c71a09c..bcb97f723 100644 --- a/src/args.c +++ b/src/args.c @@ -831,7 +831,7 @@ mc_setup_by_args (int argc, char **argv, GError ** mcerror) _("Two files are required to envoke the diffviewer.")); return FALSE; } - /* fallthrough */ + MC_FALLTHROUGH; #endif /* USE_DIFF_VIEW */ case MC_RUN_FULL: diff --git a/src/diffviewer/ydiff.c b/src/diffviewer/ydiff.c index fa073693b..8ccf40aff 100644 --- a/src/diffviewer/ydiff.c +++ b/src/diffviewer/ydiff.c @@ -3106,7 +3106,7 @@ dview_ok_to_exit (WDiff * dview) res = mc_util_unlink_backup_if_possible (dview->file[DIFF_LEFT], "~~~"); if (mc_util_restore_from_backup_if_possible (dview->file[DIFF_RIGHT], "~~~")) res = mc_util_unlink_backup_if_possible (dview->file[DIFF_RIGHT], "~~~"); - /* fall through */ + MC_FALLTHROUGH; default: res = TRUE; break; diff --git a/src/editor/editcmd.c b/src/editor/editcmd.c index 4e1101db8..7bd64eb17 100644 --- a/src/editor/editcmd.c +++ b/src/editor/editcmd.c @@ -233,7 +233,7 @@ edit_save_file (WEdit * edit, const vfs_path_t * filename_vpath) { case 0: this_save_mode = EDIT_SAFE_SAVE; - /* fallthrough */ + MC_FALLTHROUGH; case 1: edit->skip_detach_prompt = 1; break; @@ -1777,7 +1777,7 @@ edit_save_as_cmd (WEdit * edit) return TRUE; default: edit_error_dialog (_("Save as"), get_sys_error (_("Cannot save file"))); - /* fallthrough */ + MC_FALLTHROUGH; case -1: /* Failed, so maintain modify (not save) lock */ if (save_lock) diff --git a/src/editor/editdraw.c b/src/editor/editdraw.c index 31af144c2..831fadf3b 100644 --- a/src/editor/editdraw.c +++ b/src/editor/editdraw.c @@ -731,7 +731,7 @@ edit_draw_this_line (WEdit * edit, off_t b, long row, long start_col, long end_c col++; break; } - /* fallthrough */ + MC_FALLTHROUGH; default: #ifdef HAVE_CHARSET if (mc_global.utf8_display) diff --git a/src/editor/editwidget.c b/src/editor/editwidget.c index 21d843d58..5d870b1de 100644 --- a/src/editor/editwidget.c +++ b/src/editor/editwidget.c @@ -1115,7 +1115,7 @@ edit_mouse_callback (Widget * w, mouse_msg_t msg, mouse_event_t * event) } } - /* fall through to start/stop text selection */ + MC_FALLTHROUGH; /* to start/stop text selection */ case MSG_MOUSE_UP: edit_update_cursor (edit, event); diff --git a/src/filemanager/achown.c b/src/filemanager/achown.c index 3a9f11b2f..284c4e2ec 100644 --- a/src/filemanager/achown.c +++ b/src/filemanager/achown.c @@ -358,7 +358,7 @@ perm_button_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, v { case '*': parm = '='; - /* fallthrough */ + MC_FALLTHROUGH; case '-': case '=': @@ -393,15 +393,15 @@ perm_button_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, v case 'x': i++; - /* fallthrough */ + MC_FALLTHROUGH; case 'w': i++; - /* fallthrough */ + MC_FALLTHROUGH; case 'r': b->hotpos = i; - /* fallthrough */ + MC_FALLTHROUGH; case ' ': i = b->hotpos; @@ -416,11 +416,11 @@ perm_button_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, v case '4': i++; - /* fallthrough */ + MC_FALLTHROUGH; case '2': i++; - /* fallthrough */ + MC_FALLTHROUGH; case '1': b->hotpos = i; @@ -450,7 +450,7 @@ perm_button_mouse_callback (Widget * w, mouse_msg_t msg, mouse_event_t * event) case MSG_MOUSE_DOWN: /* place cursor on flag that is being modified */ BUTTON (w)->hotpos = CLAMP (event->x - 1, 0, 2); - /* fallthrough */ + MC_FALLTHROUGH; default: button_mouse_default_callback (w, msg, event); @@ -672,11 +672,11 @@ advanced_chown_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm { case ALT ('x'): i++; - /* fallthrough */ + MC_FALLTHROUGH; case ALT ('w'): i++; - /* fallthrough */ + MC_FALLTHROUGH; case ALT ('r'): parm = i + 3; @@ -689,11 +689,11 @@ advanced_chown_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm case XCTRL ('x'): i++; - /* fallthrough */ + MC_FALLTHROUGH; case XCTRL ('w'): i++; - /* fallthrough */ + MC_FALLTHROUGH; case XCTRL ('r'): parm = i; diff --git a/src/filemanager/command.c b/src/filemanager/command.c index e2fba4952..aac32d984 100644 --- a/src/filemanager/command.c +++ b/src/filemanager/command.c @@ -351,7 +351,7 @@ command_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void /* Special case: we handle the enter key */ if (parm == '\n') return enter (INPUT (w)); - /* fall through */ + MC_FALLTHROUGH; default: return input_callback (w, sender, msg, parm, data); diff --git a/src/filemanager/filegui.c b/src/filemanager/filegui.c index d6e4d39a6..7b3ddd13d 100644 --- a/src/filemanager/filegui.c +++ b/src/filemanager/filegui.c @@ -702,7 +702,7 @@ check_progress_buttons (file_op_context_t * ctx) ctx->suspended = !ctx->suspended; place_progress_buttons (ui->op_dlg, ctx->suspended); dlg_redraw (ui->op_dlg); - /* fallthrough */ + MC_FALLTHROUGH; default: if (ctx->suspended) goto get_event; @@ -1143,9 +1143,11 @@ file_progress_real_query_replace (file_op_context_t * ctx, case REPLACE_REGET: /* Careful: we fall through and set do_append */ ctx->do_reget = _d_stat->st_size; + MC_FALLTHROUGH; case REPLACE_APPEND: ctx->do_append = TRUE; + MC_FALLTHROUGH; case REPLACE_YES: case REPLACE_ALWAYS: diff --git a/src/filemanager/find.c b/src/filemanager/find.c index 01b0a4bf7..c9a4e38a6 100644 --- a/src/filemanager/find.c +++ b/src/filemanager/find.c @@ -540,7 +540,7 @@ find_parm_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, voi } first_draw = FALSE; - /* fall through to call MSG_DRAW default handler */ + MC_FALLTHROUGH; /* to call MSG_DRAW default handler */ default: return dlg_default_callback (w, sender, msg, parm, data); diff --git a/src/filemanager/hotlist.c b/src/filemanager/hotlist.c index ce3becff0..d647fdf05 100644 --- a/src/filemanager/hotlist.c +++ b/src/filemanager/hotlist.c @@ -449,9 +449,9 @@ hotlist_run_cmd (int action) fill_listbox (list); return 0; } - /* Fall through - go up */ + MC_FALLTHROUGH; /* go up */ } - /* Fall through if list empty - just go up */ + MC_FALLTHROUGH; /* if list empty - just go up */ case B_UP_GROUP: { @@ -466,7 +466,7 @@ hotlist_run_cmd (int action) #ifdef ENABLE_VFS case B_FREE_ALL_VFS: vfs_expire (TRUE); - /* fall through */ + MC_FALLTHROUGH; case B_REFRESH_VFS: listbox_remove_list (l_hotlist); @@ -1289,7 +1289,7 @@ hot_next_token (void) if (c == '\n') goto again; - /* fall through; it is taken as normal character */ + MC_FALLTHROUGH; /* it is taken as normal character */ default: do diff --git a/src/filemanager/panel.c b/src/filemanager/panel.c index f4dcb42a8..e1cb0ec66 100644 --- a/src/filemanager/panel.c +++ b/src/filemanager/panel.c @@ -3873,7 +3873,7 @@ panel_mouse_callback (Widget * w, mouse_msg_t msg, mouse_event_t * event) if (!is_active) change_panel (); - /* fall through */ + MC_FALLTHROUGH; case MSG_MOUSE_DRAG: { diff --git a/src/usermenu.c b/src/usermenu.c index 26fe21f80..858d7a3ef 100644 --- a/src/usermenu.c +++ b/src/usermenu.c @@ -883,7 +883,7 @@ expand_format (const WEdit * edit_widget, char c, gboolean do_quote) goto ret; } - /* Fall through */ + MC_FALLTHROUGH; case 't': case 'u': diff --git a/src/vfs/ftpfs/ftpfs.c b/src/vfs/ftpfs/ftpfs.c index a6ebc05b9..ff1da8999 100644 --- a/src/vfs/ftpfs/ftpfs.c +++ b/src/vfs/ftpfs/ftpfs.c @@ -687,7 +687,7 @@ ftpfs_login_server (struct vfs_class *me, struct vfs_s_super *super, const char } if (code != COMPLETE) break; - /* fall through */ + MC_FALLTHROUGH; case COMPLETE: vfs_print_message ("%s", _("ftpfs: logged in")); diff --git a/src/vfs/tar/tar.c b/src/vfs/tar/tar.c index 7a5be43db..2c7708b9d 100644 --- a/src/vfs/tar/tar.c +++ b/src/vfs/tar/tar.c @@ -817,7 +817,7 @@ tar_open_archive (struct vfs_s_super *archive, const vfs_path_t * vpath, { message (D_ERROR, MSG_ERROR, _("%s\ndoesn't look like a tar archive."), vfs_path_as_str (vpath)); - /* FALL THRU */ + MC_FALLTHROUGH; /* Error after header rec */ } @@ -836,7 +836,7 @@ tar_open_archive (struct vfs_s_super *archive, const vfs_path_t * vpath, /* Record of zeroes */ case STATUS_EOFMARK: /* If error after 0's */ - /* FALL THRU */ + MC_FALLTHROUGH; /* exit from loop */ case STATUS_EOF: /* End of archive */ break; diff --git a/src/viewer/mcviewer.c b/src/viewer/mcviewer.c index 111fafb27..ff71132fe 100644 --- a/src/viewer/mcviewer.c +++ b/src/viewer/mcviewer.c @@ -106,7 +106,7 @@ mcview_mouse_callback (Widget * w, mouse_msg_t msg, mouse_event_t * event) change_panel (); } } - /* fall through */ + MC_FALLTHROUGH; case MSG_MOUSE_CLICK: if (!view->text_wrap_mode)