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
886#define VT_STATIC 0x00002000 /* static variable */886#define VT_STATIC 0x00002000 /* static variable */
887#define VT_TYPEDEF 0x00004000 /* typedef definition */887#define VT_TYPEDEF 0x00004000 /* typedef definition */
888#define VT_INLINE 0x00008000 /* inline definition */888#define VT_INLINE 0x00008000 /* inline definition */
889#define VT_INSTINL 0x00010000 /* the inline should be visibly instantiated */889/* currently unused: 0x000[1248]0000 */
890#define VT_FAKESTC 0x00020000 /* is marked static because it's inline */
891/* currently unused: 0x000[48]0000 */
892 890
893#define VT_STRUCT_SHIFT 20 /* shift for bitfield shift values (32 - 2*6) */891#define VT_STRUCT_SHIFT 20 /* shift for bitfield shift values (32 - 2*6) */
894#define VT_STRUCT_MASK (((1 << (6+6)) - 1) << VT_STRUCT_SHIFT | VT_BITFIELD)892#define VT_STRUCT_MASK (((1 << (6+6)) - 1) << VT_STRUCT_SHIFT | VT_BITFIELD)
@@ -904,7 +902,7 @@ struct filespec { · 9 unmodified lines
904#define IS_UNION(t) ((t & (VT_STRUCT_MASK|VT_BTYPE)) == VT_UNION)902#define IS_UNION(t) ((t & (VT_STRUCT_MASK|VT_BTYPE)) == VT_UNION)
905 903
906/* type mask (except storage) */904/* 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)
908#define VT_TYPE (~(VT_STORAGE|VT_STRUCT_MASK))906#define VT_TYPE (~(VT_STORAGE|VT_STRUCT_MASK))
909 907
910/* symbol was created by tccasm.c first */908/* 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
325 esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1))325 esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1))
326 | sym->a.visibility;326 | sym->a.visibility;
327 327
328 if (sym->type.t & VT_STATIC)328 if ((sym->type.t & VT_STATIC)
329 || (sym->type.t & (VT_EXTERN | VT_INLINE)) == VT_INLINE)
329 sym_bind = STB_LOCAL;330 sym_bind = STB_LOCAL;
330 else if (sym->a.weak)331 else if (sym->a.weak)
331 sym_bind = STB_WEAK;332 sym_bind = STB_WEAK;
@@ -407,7 +408,7 @@ ST_FUNC void put_extern_sym2(Sym *sym, int sh_num, · 75 unmodified lines
407 } else {408 } else {
408 sym_type = STT_OBJECT;409 sym_type = STT_OBJECT;
409 }410 }
410 if (t & VT_STATIC)411 if ((t & VT_STATIC) || (t & (VT_EXTERN | VT_INLINE)) == VT_INLINE)
411 sym_bind = STB_LOCAL;412 sym_bind = STB_LOCAL;
412 else413 else
413 sym_bind = STB_GLOBAL;414 sym_bind = STB_GLOBAL;
@@ -926,7 +927,8 @@ static void merge_attr(AttributeDef *ad, AttributeDef *ad1) · 512 unmodified lines
926/* Merge some type attributes. */927/* Merge some type attributes. */
927static void patch_type(Sym *sym, CType *type)928static void patch_type(Sym *sym, CType *type)
928{929{
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) {
930 if (!(sym->type.t & VT_EXTERN))932 if (!(sym->type.t & VT_EXTERN))
931 tcc_error("redefinition of '%s'", get_tok_str(sym->v, NULL));933 tcc_error("redefinition of '%s'", get_tok_str(sym->v, NULL));
932 sym->type.t &= ~VT_EXTERN;934 sym->type.t &= ~VT_EXTERN;
@@ -945,18 +947,22 @@ static void patch_type(Sym *sym, CType *type) · 12 unmodified lines
945 } else if ((sym->type.t & VT_BTYPE) == VT_FUNC) {947 } else if ((sym->type.t & VT_BTYPE) == VT_FUNC) {
946 int static_proto = sym->type.t & VT_STATIC;948 int static_proto = sym->type.t & VT_STATIC;
947 /* warn if static follows non-static function declaration */949 /* 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)
949 tcc_warning("static storage ignored for redefinition of '%s'",951 tcc_warning("static storage ignored for redefinition of '%s'",
950 get_tok_str(sym->v, NULL));952 get_tok_str(sym->v, NULL));
951 953
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 }
952 if (0 == (type->t & VT_EXTERN)) {961 if (0 == (type->t & VT_EXTERN)) {
953 /* put complete type, use static from prototype */962 /* put complete type, use static from prototype */
954 sym->type.t = (type->t & ~VT_STATIC) | static_proto;963 sym->type.t = (type->t & ~VT_STATIC) | static_proto;
955 if (type->t & VT_INLINE)
956 sym->type.t = type->t;
957 sym->type.ref = type->ref;964 sym->type.ref = type->ref;
958 }965 }
959
960 } else {966 } else {
961 if ((sym->type.t & VT_ARRAY) && type->ref->c >= 0) {967 if ((sym->type.t & VT_ARRAY) && type->ref->c >= 0) {
962 /* set array size if it was omitted in extern declaration */968 /* set array size if it was omitted in extern declaration */
@@ -7411,17 +7417,12 @@ static void gen_inline_functions(TCCState *s) · 6448 unmodified lines
7411 for (i = 0; i < s->nb_inline_fns; ++i) {7417 for (i = 0; i < s->nb_inline_fns; ++i) {
7412 fn = s->inline_fns[i];7418 fn = s->inline_fns[i];
7413 sym = fn->sym;7419 sym = fn->sym;
7414 if (sym && (sym->c || (sym->type.t&VT_INSTINL) )){7420 if (sym && (sym->c || !(sym->type.t & VT_INLINE) )){
7415 /* the function was used: generate its code and7421 /* the function was used or forced: generate its code and
7416 convert it to a normal function */7422 convert it to a normal function */
7417 fn->sym = NULL;7423 fn->sym = NULL;
7418 if (file)7424 if (file)
7419 pstrcpy(file->filename, sizeof file->filename, fn->filename);7425 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
7425 begin_macro(fn->func_str, 1);7426 begin_macro(fn->func_str, 1);
7426 next();7427 next();
7427 cur_text_section = text_section;7428 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
7574 if (sym->type.t == VT_VOID)7575 if (sym->type.t == VT_VOID)
7575 sym->type = int_type;7576 sym->type = int_type;
7576 }7577 }
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 }
7608 7578
7609 /* put function symbol */7579 /* put function symbol */
7610 sym = external_sym(v, &type, 0, &ad);7580 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));
7611 7584
7612 /* static inline functions are just recorded as a kind7585 /* static inline functions are just recorded as a kind
7613 of macro. Their code will be emitted at the end of7586 of macro. Their code will be emitted at the end of
7614 the compilation unit only if they are used */7587 the compilation unit only if they are used */
7615 if ((sym->type.t & (VT_INLINE | VT_STATIC)) ==7588 if ((sym->type.t & (VT_INLINE | VT_EXTERN)) == VT_INLINE) {
7616 (VT_INLINE | VT_STATIC)) {
7617 struct InlineFunc *fn;7589 struct InlineFunc *fn;
7618 const char *filename;7590 const char *filename;
7619 7591
@@ -7688,16 +7660,9 @@ found: · 68 unmodified lines
7688 /* NOTE: as GCC, uninitialized global static7660 /* NOTE: as GCC, uninitialized global static
7689 arrays of null size are considered as7661 arrays of null size are considered as
7690 extern */7662 extern */
7691 int t = type.t;7663 if ((type.t & VT_BTYPE) != VT_FUNC)
7692 type.t |= VT_EXTERN;7664 type.t |= VT_EXTERN;
7693 sym = external_sym(v, &type, r, &ad);7665 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 }
7701 if (ad.alias_target) {7666 if (ad.alias_target) {
7702 ElfSym *esym;7667 ElfSym *esym;
7703 Sym *alias_target;7668 Sym *alias_target;
@@ -7717,7 +7682,8 @@ found: · 13 unmodified lines
7717 r |= l;7682 r |= l;
7718 if (has_init)7683 if (has_init)
7719 next();7684 next();
7720 else if (l == VT_CONST)7685 else if (l == VT_CONST
7686 && (type.t & VT_BTYPE) != VT_FUNC)
7721 /* uninitialized global variables may be overridden */7687 /* uninitialized global variables may be overridden */
7722 type.t |= VT_EXTERN;7688 type.t |= VT_EXTERN;
7723 decl_initializer_alloc(&type, &ad, r, has_init, v, l);7689 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
1455static int tab_reinit[];1455static int tab_reinit[];
1456static int tab_reinit[10];1456static int tab_reinit[10];
1457 1457
1458static int tentative_ar[];
1459static int tentative_ar[] = {1,2,3};
1460
1458//int cinit1; /* a global variable can be defined several times without error ! */1461//int cinit1; /* a global variable can be defined several times without error ! */
1459int cinit1; 1462int cinit1;
1460int cinit1; 1463int 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