Hi,
when writing macros that are intended to be used as if they were single
statements, there are a couple of common problems:
1. Ending in semicolon
...
#define foo stmt;
...
This works fine if we use it like:
...
void
bar (void)
{
foo;
}
...
but we get an "else without a previous if" error when we use it like:
...
void
bar (void)
{
if (1)
foo;
else
{}
}
...
2. Using if-then-else without wrapping in "do {} while (0)"
...
#define foo if (1) stmt; else {}
...
Again this works fine if we use it like:
...
void
bar (void)
{
foo;
}
...
but we get an "suggest explicit braces to avoid ambiguous else
[-Wparentheses]" warning when we use it like:
...
void
bar (void)
{
if (1)
foo;
}
...
3. Multi statement without wrapping it in "do {} while (0)"
...
#define foo stmt; stmt
...
Again this works fine if we use it like:
...
void
bar (void)
{
foo;
}
...
but we get a "macro expands to multiple statements
[-Wmultistatement-macros]" warning when we use it like:
...
void
bar (void)
{
if (1)
foo;
}
...
I've written a macro SAFE_MACRO_STMT that triggers these three
situations for a macro, but does not change the semantics:
...
#define SAFE_MACRO_STMT(stmt) \
do { \
stmt; \
if (0) \
stmt; \
else \
{} \
if (0) \
stmt; \
} while (0)
...
In other words, by wrapping the macro usage in SAFE_MACRO_STMT, we
trigger an error or warning if the macro body contains any of the problems:
...
void
bar (void)
{
SAFE_MACRO_STMT (foo);
}
...
The first demonstrator patch applies this strategy to
ASM_OUTPUT_ADDR_VEC_ELT. This smokes out a type 1 error in the ft32
definition of ASM_OUTPUT_ADDR_VEC_ELT, which is fixed by the second patch.
Any comments on this approach?
Thanks,
- Tom
Use SAFE_MACRO_STMT for ASM_OUTPUT_ADDR_VEC_ELT
---
gcc/final.c | 17 +++++++++++++++--
1 file changed, 15 insertions(+), 2 deletions(-)
diff --git a/gcc/final.c b/gcc/final.c
index 672c5bb..17c1c12 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -2169,6 +2169,17 @@ asm_show_source (const char *filename, int linenum)
fputc ('\n', asm_out_file);
}
+#define SAFE_MACRO_STMT(stmt) \
+ do { \
+ stmt; \
+ if (0) \
+ stmt; \
+ else \
+ {} \
+ if (0) \
+ stmt; \
+ } while (0)
+
/* The final scan for one insn, INSN.
Args are same as in `final', except that INSN
is the insn being scanned.
@@ -2562,8 +2573,10 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
if (GET_CODE (body) == ADDR_VEC)
{
#ifdef ASM_OUTPUT_ADDR_VEC_ELT
- ASM_OUTPUT_ADDR_VEC_ELT
- (file, CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 0, idx), 0)));
+ SAFE_MACRO_STMT
+ (ASM_OUTPUT_ADDR_VEC_ELT
+ (file,
+ CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 0, idx), 0))));
#else
gcc_unreachable ();
#endif
[ft32] Remove semicolon after ASM_OUTPUT_ADDR_VEC_ELT
---
gcc/config/ft32/ft32.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/gcc/config/ft32/ft32.h b/gcc/config/ft32/ft32.h
index b276f25..c32db40 100644
--- a/gcc/config/ft32/ft32.h
+++ b/gcc/config/ft32/ft32.h
@@ -205,7 +205,7 @@ enum reg_class
/* This is how to output an element of a case-vector that is absolute. */
#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \
- fprintf (FILE, "\t.long\t.L%d\n", VALUE); \
+ fprintf (FILE, "\t.long\t.L%d\n", VALUE) \
/* Passing Arguments in Registers */