History

standard conformant inline functions

- add tests for standard conformant inline functions - implement it The old tinycc failed to provide a conforming implementation of non-static inlines. It would expose external symbols where it shouldn't and hide them where it should expose them. This commit provides a hopefully comprehensive test suite for how things should be done. The .expect file can be obtained by compiling the example c file (embedded in the test) with a conforming compiler such as gcc, clang or icc and then printing the exported symbols (e.g., with nm+awk+sort). (The implementation currently reserves two new VT_ flags. If anyone can provide an implementation without reserving two extra flags, please replace mine.)

Petr Skocik committed 7 years ago

Commit 587e1f51 parent f2fd56a4 files · +259 −13Browse files

Unified · Split

4 files
  1. tcc.h +4 −2
  2. tccgen.c +49 −11
  3. tests/tests2/104_inline_test.c +181 −0
  4. tests/tests2/104_inline_test.expect +25 −0
tcc.h+4−2
@@ -886,7 +886,9 @@ 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/* currently unused: 0x000[1248]0000 */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 */
890 892
891#define VT_STRUCT_SHIFT 20 /* shift for bitfield shift values (32 - 2*6) */893#define VT_STRUCT_SHIFT 20 /* shift for bitfield shift values (32 - 2*6) */
892#define VT_STRUCT_MASK (((1 << (6+6)) - 1) << VT_STRUCT_SHIFT | VT_BITFIELD)894#define VT_STRUCT_MASK (((1 << (6+6)) - 1) << VT_STRUCT_SHIFT | VT_BITFIELD)
@@ -902,7 +904,7 @@ struct filespec { · 9 unmodified lines
902#define IS_UNION(t) ((t & (VT_STRUCT_MASK|VT_BTYPE)) == VT_UNION)904#define IS_UNION(t) ((t & (VT_STRUCT_MASK|VT_BTYPE)) == VT_UNION)
903 905
904/* type mask (except storage) */906/* type mask (except storage) */
905#define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE)907#define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE | VT_INSTINL | VT_FAKESTC )
906#define VT_TYPE (~(VT_STORAGE|VT_STRUCT_MASK))908#define VT_TYPE (~(VT_STORAGE|VT_STRUCT_MASK))
907 909
908/* symbol was created by tccasm.c first */910/* symbol was created by tccasm.c first */
tccgen.c+49−11
@@ -945,7 +945,7 @@ static void patch_type(Sym *sym, CType *type) · 944 unmodified lines
945 } else if ((sym->type.t & VT_BTYPE) == VT_FUNC) {945 } else if ((sym->type.t & VT_BTYPE) == VT_FUNC) {
946 int static_proto = sym->type.t & VT_STATIC;946 int static_proto = sym->type.t & VT_STATIC;
947 /* warn if static follows non-static function declaration */947 /* warn if static follows non-static function declaration */
948 if ((type->t & VT_STATIC) && !static_proto && !(type->t & VT_INLINE))948 if ((type->t & VT_STATIC) && !static_proto && !((type->t|sym->type.t) & VT_INLINE))
949 tcc_warning("static storage ignored for redefinition of '%s'",949 tcc_warning("static storage ignored for redefinition of '%s'",
950 get_tok_str(sym->v, NULL));950 get_tok_str(sym->v, NULL));
951 951
@@ -7411,7 +7411,7 @@ static void gen_inline_functions(TCCState *s) · 6459 unmodified lines
7411 for (i = 0; i < s->nb_inline_fns; ++i) {7411 for (i = 0; i < s->nb_inline_fns; ++i) {
7412 fn = s->inline_fns[i];7412 fn = s->inline_fns[i];
7413 sym = fn->sym;7413 sym = fn->sym;
7414 if (sym && sym->c) {7414 if (sym && (sym->c || (sym->type.t&VT_INSTINL) )){
7415 /* the function was used: generate its code and7415 /* the function was used: generate its code and
7416 convert it to a normal function */7416 convert it to a normal function */
7417 fn->sym = NULL;7417 fn->sym = NULL;
@@ -7419,6 +7419,9 @@ static void gen_inline_functions(TCCState *s) · 1 unmodified line
7419 pstrcpy(file->filename, sizeof file->filename, fn->filename);7419 pstrcpy(file->filename, sizeof file->filename, fn->filename);
7420 sym->type.t &= ~VT_INLINE;7420 sym->type.t &= ~VT_INLINE;
7421 7421
7422 if (sym->type.t&VT_INSTINL)
7423 sym->type.t &= ~VT_STATIC;
7424
7422 begin_macro(fn->func_str, 1);7425 begin_macro(fn->func_str, 1);
7423 next();7426 next();
7424 cur_text_section = text_section;7427 cur_text_section = text_section;
@@ -7563,18 +7566,45 @@ static int decl0(int l, int is_for_loop_init, Sym *func_sym) · 138 unmodified lines
7563 expect("function definition");7566 expect("function definition");
7564 7567
7565 /* reject abstract declarators in function definition7568 /* reject abstract declarators in function definition
7566 make old style params without decl have int type */7569 make old style params without decl have int type */
7567 sym = type.ref;7570 sym = type.ref;
7568 while ((sym = sym->next) != NULL) {7571 while ((sym = sym->next) != NULL) {
7569 if (!(sym->v & ~SYM_FIELD))7572 if (!(sym->v & ~SYM_FIELD))
7570 expect("identifier");7573 expect("identifier");
7571 if (sym->type.t == VT_VOID)7574 if (sym->type.t == VT_VOID)
7572 sym->type = int_type;7575 sym->type = int_type;
7573 }7576 }
7574 7577 sym = type.ref;
7575 /* XXX: cannot do better now: convert extern line to static inline */7578 sym = sym_find(v);
7576 if ((type.t & (VT_EXTERN | VT_INLINE)) == (VT_EXTERN | VT_INLINE))7579 /* temporarily convert even extern inlines to statics */
7577 type.t = (type.t & ~VT_EXTERN) | VT_STATIC;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 }
7578 7608
7579 /* put function symbol */7609 /* put function symbol */
7580 sym = external_sym(v, &type, 0, &ad);7610 sym = external_sym(v, &type, 0, &ad);
@@ -7582,7 +7612,7 @@ static int decl0(int l, int is_for_loop_init, Sym *func_sym) · 1 unmodified line
7582 /* static inline functions are just recorded as a kind7612 /* static inline functions are just recorded as a kind
7583 of macro. Their code will be emitted at the end of7613 of macro. Their code will be emitted at the end of
7584 the compilation unit only if they are used */7614 the compilation unit only if they are used */
7585 if ((type.t & (VT_INLINE | VT_STATIC)) ==7615 if ((sym->type.t & (VT_INLINE | VT_STATIC)) ==
7586 (VT_INLINE | VT_STATIC)) {7616 (VT_INLINE | VT_STATIC)) {
7587 struct InlineFunc *fn;7617 struct InlineFunc *fn;
7588 const char *filename;7618 const char *filename;
@@ -7658,8 +7688,16 @@ found: · 69 unmodified lines
7658 /* NOTE: as GCC, uninitialized global static7688 /* NOTE: as GCC, uninitialized global static
7659 arrays of null size are considered as7689 arrays of null size are considered as
7660 extern */7690 extern */
7691 int t = type.t;
7661 type.t |= VT_EXTERN;7692 type.t |= VT_EXTERN;
7662 sym = external_sym(v, &type, r, &ad);7693 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 }
7663 if (ad.alias_target) {7701 if (ad.alias_target) {
7664 ElfSym *esym;7702 ElfSym *esym;
7665 Sym *alias_target;7703 Sym *alias_target;
tests/tests2/104_inline_test.c+181−0
@@ -0,0 +1,181 @@
1#include <stdio.h>
2#include <stdlib.h>
3#include <signal.h>
4#include <errno.h>
5
6extern char const cfileContents[];
7char c[]="/tmp/tcc-XXXXXX.c";
8char o[]="/tmp/tcc-XXXXXX.o";
9void rmh(int Sig)
10{
11 remove(c);
12 remove(o);
13 signal(Sig,SIG_DFL);
14 raise(Sig);
15}
16int str2file(char const *fnm, char const *str)
17{
18 FILE *f;
19 if(0==(f=fopen(fnm,"w"))) return -1;
20 if(0>fputs(str,f)) return -1;
21 if(0>fclose(f)) return -1;
22 return 0;
23}
24int main(int C, char **V)
25{
26 int r=0;
27 if (system("which nm >/dev/null 2>&1")){ return 0; }
28 signal(SIGINT,SIG_IGN);
29 signal(SIGTERM,SIG_IGN);
30 if(0>mkstemps(c,2)) return perror("mkstemps"),1;
31 if(0>mkstemps(o,2)){
32 if(0>remove(c)) perror("remove");
33 return perror("mkstemps"),1;
34 }
35 signal(SIGINT,rmh);
36 signal(SIGTERM,rmh);
37 if(0>str2file(c, cfileContents)) { perror("write");r=1;goto out;}
38 char buf[1024];
39 sprintf(buf, "%s -c %s -o %s", V[1]?V[1]:"../../tcc", c, o); if(0!=system(buf)){ r=1;goto out;}
40 sprintf(buf, "nm -Ptx %s > %s", o, c); if(system(buf)) {r=1;goto out;}
41 sprintf(buf, "awk '{ if($2 == \"T\") print $1 }' %s > %s", c, o); if(system(buf)) {r=1;goto out;}
42 sprintf(buf, "sort %s", o); if(system(buf)) {r=1;goto out;}
43out:
44 remove(c);
45 remove(o);
46 return r;
47}
48char const cfileContents[]=
49"inline void inline_inline_2decl_only(void);\n"
50"inline void inline_inline_2decl_only(void);\n"
51"\n"
52"inline void inline_inline_undeclared(void){}\n"
53"\n"
54"inline void inline_inline_predeclared(void);\n"
55"inline void inline_inline_predeclared(void){}\n"
56"\n"
57"inline void inline_inline_postdeclared(void){}\n"
58"inline void inline_inline_postdeclared(void);\n"
59"\n"
60"inline void inline_inline_prepostdeclared(void);\n"
61"inline void inline_inline_prepostdeclared(void){}\n"
62"inline void inline_inline_prepostdeclared(void);\n"
63"\n"
64"inline void inline_inline_undeclared2(void){}\n"
65"\n"
66"inline void inline_inline_predeclared2(void);\n"
67"inline void inline_inline_predeclared2(void);\n"
68"inline void inline_inline_predeclared2(void){}\n"
69"\n"
70"inline void inline_inline_postdeclared2(void){}\n"
71"inline void inline_inline_postdeclared2(void);\n"
72"inline void inline_inline_postdeclared2(void);\n"
73"\n"
74"inline void inline_inline_prepostdeclared2(void);\n"
75"inline void inline_inline_prepostdeclared2(void);\n"
76"inline void inline_inline_prepostdeclared2(void){}\n"
77"inline void inline_inline_prepostdeclared2(void);\n"
78"inline void inline_inline_prepostdeclared2(void);\n"
79"\n"
80"extern void extern_extern_undeclared(void){}\n"
81"\n"
82"extern void extern_extern_predeclared(void);\n"
83"extern void extern_extern_predeclared(void){}\n"
84"\n"
85"extern void extern_extern_postdeclared(void){}\n"
86"extern void extern_extern_postdeclared(void);\n"
87"\n"
88"extern void extern_extern_prepostdeclared(void);\n"
89"extern void extern_extern_prepostdeclared(void){}\n"
90"extern void extern_extern_prepostdeclared(void);\n"
91"\n"
92"extern void extern_extern_undeclared2(void){}\n"
93"\n"
94"extern void extern_extern_predeclared2(void);\n"
95"extern void extern_extern_predeclared2(void);\n"
96"extern void extern_extern_predeclared2(void){}\n"
97"\n"
98"extern void extern_extern_postdeclared2(void){}\n"
99"extern void extern_extern_postdeclared2(void);\n"
100"extern void extern_extern_postdeclared2(void);\n"
101"\n"
102"extern void extern_extern_prepostdeclared2(void);\n"
103"extern void extern_extern_prepostdeclared2(void);\n"
104"extern void extern_extern_prepostdeclared2(void){}\n"
105"extern void extern_extern_prepostdeclared2(void);\n"
106"extern void extern_extern_prepostdeclared2(void);\n"
107"\n"
108"void extern_undeclared(void){}\n"
109"\n"
110"void extern_predeclared(void);\n"
111"void extern_predeclared(void){}\n"
112"\n"
113"void extern_postdeclared(void){}\n"
114"void extern_postdeclared(void);\n"
115"\n"
116"void extern_prepostdeclared(void);\n"
117"void extern_prepostdeclared(void){}\n"
118"void extern_prepostdeclared(void);\n"
119"\n"
120"void extern_undeclared2(void){}\n"
121"\n"
122"void extern_predeclared2(void);\n"
123"void extern_predeclared2(void);\n"
124"void extern_predeclared2(void){}\n"
125"\n"
126"void extern_postdeclared2(void){}\n"
127"void extern_postdeclared2(void);\n"
128"void extern_postdeclared2(void);\n"
129"\n"
130"\n"
131"extern inline void noinst_extern_inline_undeclared(void){}\n"
132"\n"
133"extern inline void noinst_extern_inline_postdeclared(void){}\n"
134"inline void noinst_extern_inline_postdeclared(void);\n"
135"\n"
136"extern inline void noinst_extern_inline_postdeclared2(void){}\n"
137"inline void noinst_extern_inline_postdeclared2(void);\n"
138"inline void noinst_extern_inline_postdeclared2(void);\n"
139"\n"
140"extern inline void inst_extern_inline_postdeclared(void){}\n"
141"extern inline void inst_extern_inline_postdeclared(void);\n"
142"inline void inst2_extern_inline_postdeclared(void){}\n"
143"void inst2_extern_inline_postdeclared(void);\n"
144"\n"
145"void inst_extern_inline_predeclared(void);\n"
146"extern inline void inst_extern_inline_predeclared(void){}\n"
147"void inst2_extern_inline_predeclared(void);\n"
148"inline void inst2_extern_inline_predeclared(void){}\n"
149"extern inline void inst3_extern_inline_predeclared(void);\n"
150"inline void inst3_extern_inline_predeclared(void){}\n"
151"\n"
152"static inline void noinst_static_inline_postdeclared(void){}\n"
153"static inline void noinst_static_inline_postdeclared(void);\n"
154"static inline void noinst2_static_inline_postdeclared(void){}\n"
155"static void noinst2_static_inline_postdeclared(void);\n"
156"\n"
157"static void noinst_static_inline_predeclared(void);\n"
158"static inline void noinst_static_inline_predeclared(void){}\n"
159"static void noinst2_static_inline_predeclared(void);\n"
160"static inline void noinst2_static_inline_predeclared(void){}\n"
161"\n"
162"static void static_func(void);\n"
163"void static_func(void) { }\n"
164"\n"
165"inline void noinst_extern_inline_func(void);\n"
166"void noinst_extern_inline_func(void) { }\n"
167"int main()\n"
168"{\n"
169" inline_inline_undeclared(); inline_inline_predeclared(); inline_inline_postdeclared();\n"
170" inline_inline_undeclared2(); inline_inline_predeclared2(); inline_inline_postdeclared2();\n"
171" noinst_extern_inline_undeclared();\n"
172" noinst_extern_inline_postdeclared();\n"
173" noinst_extern_inline_postdeclared2();\n"
174" noinst_static_inline_predeclared();\n"
175" noinst2_static_inline_predeclared();\n"
176" noinst_static_inline_predeclared();\n"
177" noinst2_static_inline_predeclared();\n"
178"}\n"
179"\n"
180;
181
tests/tests2/104_inline_test.expect+25−0
@@ -0,0 +1,25 @@
1extern_extern_postdeclared
2extern_extern_postdeclared2
3extern_extern_predeclared
4extern_extern_predeclared2
5extern_extern_prepostdeclared
6extern_extern_prepostdeclared2
7extern_extern_undeclared
8extern_extern_undeclared2
9extern_postdeclared
10extern_postdeclared2
11extern_predeclared
12extern_predeclared2
13extern_prepostdeclared
14extern_undeclared
15extern_undeclared2
16inst2_extern_inline_postdeclared
17inst2_extern_inline_predeclared
18inst3_extern_inline_predeclared
19inst_extern_inline_postdeclared
20inst_extern_inline_predeclared
21main
22noinst_extern_inline_func
23noinst_extern_inline_postdeclared
24noinst_extern_inline_postdeclared2
25noinst_extern_inline_undeclared

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