From f18f8651599e1162c87b809d5c262b618dea4a9e Mon Sep 17 00:00:00 2001 From: Michael Matz Date: Fri, 22 May 2020 05:17:02 +0200 Subject: [PATCH] Handle always_inline as GNU inline this is needed for multi-file testcases using stdio.h, as the __sputc function is implemented as a extern inline function (with gnu_inline attribute, but we don't support that for now). Without this change that leads to multiply defined symbols when using multiple units including stdio.h. It also has an always_inline attribute, which we can use to guide our behaviour, as in ISO-C an always_inline can't be defined with ISO 'extern inline' semantics. This is the minimal change and not a full implementation of GNU inline semantics, which would require thorough testcases. If __clang__ would be defined the header would make use of C99 semantics, which would work for us. It would also do that if _GNUC_ wouldn't be defined. But we can't do the latter (as the whole MacOSX SDK refuses to be compiled with anything not defining that). I haven't tested defining __clang__, but suspect that's going to be problematic. --- tcc.h | 4 +++- tccgen.c | 22 ++++++++++++++++++---- tcctok.h | 2 ++ 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/tcc.h b/tcc.h index c00c7a15..d74d918a 100644 --- a/tcc.h +++ b/tcc.h @@ -494,7 +494,9 @@ struct FuncAttr { func_noreturn : 1, /* attribute((noreturn)) */ func_ctor : 1, /* attribute((constructor)) */ func_dtor : 1, /* attribute((destructor)) */ - func_args : 8; /* PE __stdcall args */ + func_args : 8, /* PE __stdcall args */ + func_alwinl : 1, /* always_inline */ + xxxx :15; }; /* symbol management */ diff --git a/tccgen.c b/tccgen.c index 88145abf..e49407dd 100644 --- a/tccgen.c +++ b/tccgen.c @@ -4075,14 +4075,18 @@ redo: skip(')'); break; } - case TOK_CONSTRUCTOR1: - case TOK_CONSTRUCTOR2: + case TOK_CONSTRUCTOR1: + case TOK_CONSTRUCTOR2: ad->f.func_ctor = 1; break; - case TOK_DESTRUCTOR1: - case TOK_DESTRUCTOR2: + case TOK_DESTRUCTOR1: + case TOK_DESTRUCTOR2: ad->f.func_dtor = 1; break; + case TOK_ALWAYS_INLINE1: + case TOK_ALWAYS_INLINE2: + ad->f.func_alwinl = 1; + break; case TOK_SECTION1: case TOK_SECTION2: skip('('); @@ -8225,6 +8229,16 @@ static int decl0(int l, int is_for_loop_init, Sym *func_sym) sym = type.ref; if (sym->f.func_type == FUNC_OLD && l == VT_CONST) decl0(VT_CMP, 0, sym); + if (sym->f.func_alwinl + && ((type.t & (VT_EXTERN | VT_INLINE)) + == (VT_EXTERN | VT_INLINE))) { + /* always_inline functions must be handled as if they + don't generate multiple global defs, even if extern + inline, i.e. GNU inline semantics for those. Rewrite + them into static inline. */ + type.t &= ~VT_EXTERN; + type.t |= VT_STATIC; + } /* always compile 'extern inline' */ if (type.t & VT_EXTERN) type.t &= ~VT_INLINE; diff --git a/tcctok.h b/tcctok.h index ee18462d..54a778b0 100644 --- a/tcctok.h +++ b/tcctok.h @@ -132,6 +132,8 @@ DEF(TOK_CONSTRUCTOR2, "__constructor__") DEF(TOK_DESTRUCTOR1, "destructor") DEF(TOK_DESTRUCTOR2, "__destructor__") + DEF(TOK_ALWAYS_INLINE1, "always_inline") + DEF(TOK_ALWAYS_INLINE2, "__always_inline__") DEF(TOK_MODE, "__mode__") DEF(TOK_MODE_QI, "__QI__")