History

TLC for C99 inline implementation

there's no need for two new flags in type.t . We just can't use VT_EXTERN as marker if functions are defined or not (like we can for objects), and then can simply implement the rules of C99/C11 by not overwriting VT_STATIC/VT_EXTERN at all but rather only look at them. A function already on the inline list can be forced by removing the VT_INLINE flag, and then linkage follows from some combination of VT_STATIC, VT_EXTERN and VT_INLINE.

Michael Matz committed 7 years ago

Commit cb8bbf11 parent 4dfc27b3 files · +28 −61Browse files

Unified · Split

3 files
  1. tcc.h +2 −4
  2. tccgen.c +23 −57
  3. tests/tcctest.c +3 −0
tcc.h+2−4
@@ -886,9 +886,7 @@ struct filespec { · 885 unmodified lines
886886 #define VT_STATIC 0x00002000 /* static variable */
887887 #define VT_TYPEDEF 0x00004000 /* typedef definition */
888888 #define VT_INLINE 0x00008000 /* inline definition */
889−#define VT_INSTINL 0x00010000 /* the inline should be visibly instantiated */
890−#define VT_FAKESTC 0x00020000 /* is marked static because it's inline */
891−/* currently unused: 0x000[48]0000 */
889+/* currently unused: 0x000[1248]0000 */
892890
893891 #define VT_STRUCT_SHIFT 20 /* shift for bitfield shift values (32 - 2*6) */
894892 #define VT_STRUCT_MASK (((1 << (6+6)) - 1) << VT_STRUCT_SHIFT | VT_BITFIELD)
@@ -904,7 +902,7 @@ struct filespec { · 9 unmodified lines
904902 #define IS_UNION(t) ((t & (VT_STRUCT_MASK|VT_BTYPE)) == VT_UNION)
905903
906904 /* type mask (except storage) */
907−#define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE | VT_INSTINL | VT_FAKESTC )
905+#define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE)
908906 #define VT_TYPE (~(VT_STORAGE|VT_STRUCT_MASK))
909907
910908 /* symbol was created by tccasm.c first */
tccgen.c+23−57
@@ -325,7 +325,8 @@ ST_FUNC void update_storage(Sym *sym) · 324 unmodified lines
325325 esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1))
326326 | sym->a.visibility;
327327
328− if (sym->type.t & VT_STATIC)
328+ if ((sym->type.t & VT_STATIC)
329+ || (sym->type.t & (VT_EXTERN | VT_INLINE)) == VT_INLINE)
329330 sym_bind = STB_LOCAL;
330331 else if (sym->a.weak)
331332 sym_bind = STB_WEAK;
@@ -407,7 +408,7 @@ ST_FUNC void put_extern_sym2(Sym *sym, int sh_num, · 75 unmodified lines
407408 } else {
408409 sym_type = STT_OBJECT;
409410 }
410− if (t & VT_STATIC)
411+ if ((t & VT_STATIC) || (t & (VT_EXTERN | VT_INLINE)) == VT_INLINE)
411412 sym_bind = STB_LOCAL;
412413 else
413414 sym_bind = STB_GLOBAL;
@@ -926,7 +927,8 @@ static void merge_attr(AttributeDef *ad, AttributeDef *ad1) · 512 unmodified lines
926927 /* Merge some type attributes. */
927928 static void patch_type(Sym *sym, CType *type)
928929 {
929− if (!(type->t & VT_EXTERN) || IS_ENUM_VAL(sym->type.t)) {
930+ if ((!(type->t & VT_EXTERN) || IS_ENUM_VAL(sym->type.t))
931+ && (type->t & VT_BTYPE) != VT_FUNC) {
930932 if (!(sym->type.t & VT_EXTERN))
931933 tcc_error("redefinition of '%s'", get_tok_str(sym->v, NULL));
932934 sym->type.t &= ~VT_EXTERN;
@@ -945,18 +947,22 @@ static void patch_type(Sym *sym, CType *type) · 12 unmodified lines
945947 } else if ((sym->type.t & VT_BTYPE) == VT_FUNC) {
946948 int static_proto = sym->type.t & VT_STATIC;
947949 /* warn if static follows non-static function declaration */
948− if ((type->t & VT_STATIC) && !static_proto && !((type->t|sym->type.t) & VT_INLINE))
950+ if ((type->t & VT_STATIC) && !static_proto)
949951 tcc_warning("static storage ignored for redefinition of '%s'",
950952 get_tok_str(sym->v, NULL));
951953
954+ /* Force external definition if unequal inline specifier
955+ or an explicit extern one. */
956+ if ((type->t & VT_INLINE) != (sym->type.t & VT_INLINE)
957+ || (type->t | sym->type.t) & VT_EXTERN) {
958+ type->t &= ~VT_INLINE;
959+ sym->type.t &= ~VT_INLINE;
960+ }
952961 if (0 == (type->t & VT_EXTERN)) {
953962 /* put complete type, use static from prototype */
954963 sym->type.t = (type->t & ~VT_STATIC) | static_proto;
955− if (type->t & VT_INLINE)
956− sym->type.t = type->t;
957964 sym->type.ref = type->ref;
958965 }
959−
960966 } else {
961967 if ((sym->type.t & VT_ARRAY) && type->ref->c >= 0) {
962968 /* set array size if it was omitted in extern declaration */
@@ -7411,17 +7417,12 @@ static void gen_inline_functions(TCCState *s) · 6448 unmodified lines
74117417 for (i = 0; i < s->nb_inline_fns; ++i) {
74127418 fn = s->inline_fns[i];
74137419 sym = fn->sym;
7414− if (sym && (sym->c || (sym->type.t&VT_INSTINL) )){
7415− /* the function was used: generate its code and
7420+ if (sym && (sym->c || !(sym->type.t & VT_INLINE) )){
7421+ /* the function was used or forced: generate its code and
74167422 convert it to a normal function */
74177423 fn->sym = NULL;
74187424 if (file)
74197425 pstrcpy(file->filename, sizeof file->filename, fn->filename);
7420− sym->type.t &= ~VT_INLINE;
7421−
7422− if (sym->type.t&VT_INSTINL)
7423− sym->type.t &= ~VT_STATIC;
7424−
74257426 begin_macro(fn->func_str, 1);
74267427 next();
74277428 cur_text_section = text_section;
@@ -7574,46 +7575,17 @@ static int decl0(int l, int is_for_loop_init, Sym *func_sym) · 146 unmodified lines
75747575 if (sym->type.t == VT_VOID)
75757576 sym->type = int_type;
75767577 }
7577− sym = type.ref;
7578− sym = sym_find(v);
7579− /* temporarily convert even extern inlines to statics */
7580− if (!sym){
7581− if( (type.t & VT_EXTERN) && (type.t & VT_INLINE) ){
7582− type.t |= VT_INSTINL;
7583− type.t = (type.t & ~VT_EXTERN) | VT_STATIC | VT_FAKESTC;
7584− }else if ( type.t & VT_INLINE ){
7585− if(!(type.t&VT_STATIC)) type.t |= VT_FAKESTC;
7586− type.t = (type.t & ~VT_EXTERN) | VT_STATIC;
7587− }
7588− }else{
7589− if ( !(type.t & VT_STATIC) && !(sym->type.t & VT_STATIC) ){
7590− if(
7591− ((type.t & VT_INLINE) != (sym->type.t & VT_INLINE)) ||
7592− ( (type.t & VT_INLINE) && (type.t & VT_EXTERN) )
7593− ){
7594− /* noninline decl + inline def OR inline decl + noinline def OR
7595− inline explicitly extern def ALL instantiate the inline */
7596− type.t |= sym->type.t | VT_INSTINL;
7597− type.t = (type.t & ~VT_EXTERN) | VT_STATIC;
7598− }
7599− }else{
7600− /*(extern on nonstatic defs following static decls are turned into true static defs)*/
7601− }
7602− if ( sym->type.t & VT_INLINE ){
7603− if(!(type.t&VT_STATIC)) type.t |= VT_FAKESTC;
7604− type.t |= sym->type.t;
7605− type.t = (type.t & ~VT_EXTERN) | VT_STATIC;
7606− }
7607− }
76087578
76097579 /* put function symbol */
76107580 sym = external_sym(v, &type, 0, &ad);
7581+ if (sym->c && elfsym(sym)->st_shndx != SHN_UNDEF
7582+ && !(elfsym(sym)->st_other & ST_ASM_SET))
7583+ tcc_error("redefinition of '%s'", get_tok_str(sym->v, NULL));
76117584
76127585 /* static inline functions are just recorded as a kind
76137586 of macro. Their code will be emitted at the end of
76147587 the compilation unit only if they are used */
7615− if ((sym->type.t & (VT_INLINE | VT_STATIC)) ==
7616− (VT_INLINE | VT_STATIC)) {
7588+ if ((sym->type.t & (VT_INLINE | VT_EXTERN)) == VT_INLINE) {
76177589 struct InlineFunc *fn;
76187590 const char *filename;
76197591
@@ -7688,16 +7660,9 @@ found: · 68 unmodified lines
76887660 /* NOTE: as GCC, uninitialized global static
76897661 arrays of null size are considered as
76907662 extern */
7691− int t = type.t;
7692− type.t |= VT_EXTERN;
7663+ if ((type.t & VT_BTYPE) != VT_FUNC)
7664+ type.t |= VT_EXTERN;
76937665 sym = external_sym(v, &type, r, &ad);
7694−
7695− if ( (!(sym->type.t&VT_STATIC) || sym->type.t&VT_FAKESTC ) &&
7696− ( ((sym->type.t&VT_INLINE)!=(t&VT_INLINE)) ||
7697− ( (t&VT_INLINE) && (t&VT_EXTERN) ) )
7698− ){
7699− sym->type.t |= VT_INSTINL;
7700− }
77017666 if (ad.alias_target) {
77027667 ElfSym *esym;
77037668 Sym *alias_target;
@@ -7717,7 +7682,8 @@ found: · 13 unmodified lines
77177682 r |= l;
77187683 if (has_init)
77197684 next();
7720− else if (l == VT_CONST)
7685+ else if (l == VT_CONST
7686+ && (type.t & VT_BTYPE) != VT_FUNC)
77217687 /* uninitialized global variables may be overridden */
77227688 type.t |= VT_EXTERN;
77237689 decl_initializer_alloc(&type, &ad, r, has_init, v, l);
tests/tcctest.c+3−0
@@ -1455,6 +1455,9 @@ int defined_function(void) · 1454 unmodified lines
14551455 static int tab_reinit[];
14561456 static int tab_reinit[10];
14571457
1458+static int tentative_ar[];
1459+static int tentative_ar[] = {1,2,3};
1460+
14581461 //int cinit1; /* a global variable can be defined several times without error ! */
14591462 int cinit1;
14601463 int cinit1;

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t