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
886886 #define VT_STATIC 0x00002000 /* static variable */
887887 #define VT_TYPEDEF 0x00004000 /* typedef definition */
888888 #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 */
890892
891893 #define VT_STRUCT_SHIFT 20 /* shift for bitfield shift values (32 - 2*6) */
892894 #define VT_STRUCT_MASK (((1 << (6+6)) - 1) << VT_STRUCT_SHIFT | VT_BITFIELD)
@@ -902,7 +904,7 @@ struct filespec { · 9 unmodified lines
902904 #define IS_UNION(t) ((t & (VT_STRUCT_MASK|VT_BTYPE)) == VT_UNION)
903905
904906 /* 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 )
906908 #define VT_TYPE (~(VT_STORAGE|VT_STRUCT_MASK))
907909
908910 /* 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
945945 } else if ((sym->type.t & VT_BTYPE) == VT_FUNC) {
946946 int static_proto = sym->type.t & VT_STATIC;
947947 /* 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))
949949 tcc_warning("static storage ignored for redefinition of '%s'",
950950 get_tok_str(sym->v, NULL));
951951
@@ -7411,7 +7411,7 @@ static void gen_inline_functions(TCCState *s) · 6459 unmodified lines
74117411 for (i = 0; i < s->nb_inline_fns; ++i) {
74127412 fn = s->inline_fns[i];
74137413 sym = fn->sym;
7414− if (sym && sym->c) {
7414+ if (sym && (sym->c || (sym->type.t&VT_INSTINL) )){
74157415 /* the function was used: generate its code and
74167416 convert it to a normal function */
74177417 fn->sym = NULL;
@@ -7419,6 +7419,9 @@ static void gen_inline_functions(TCCState *s) · 1 unmodified line
74197419 pstrcpy(file->filename, sizeof file->filename, fn->filename);
74207420 sym->type.t &= ~VT_INLINE;
74217421
7422+ if (sym->type.t&VT_INSTINL)
7423+ sym->type.t &= ~VT_STATIC;
7424+
74227425 begin_macro(fn->func_str, 1);
74237426 next();
74247427 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
75637566 expect("function definition");
75647567
75657568 /* 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 */
75677570 sym = type.ref;
75687571 while ((sym = sym->next) != NULL) {
75697572 if (!(sym->v & ~SYM_FIELD))
75707573 expect("identifier");
7571− if (sym->type.t == VT_VOID)
7572− sym->type = int_type;
7573− }
7574−
7575− /* XXX: cannot do better now: convert extern line to static inline */
7576− if ((type.t & (VT_EXTERN | VT_INLINE)) == (VT_EXTERN | VT_INLINE))
7577− type.t = (type.t & ~VT_EXTERN) | VT_STATIC;
7574+ if (sym->type.t == VT_VOID)
7575+ sym->type = int_type;
7576+ }
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+ }
75787608
75797609 /* put function symbol */
75807610 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
75827612 /* static inline functions are just recorded as a kind
75837613 of macro. Their code will be emitted at the end of
75847614 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)) ==
75867616 (VT_INLINE | VT_STATIC)) {
75877617 struct InlineFunc *fn;
75887618 const char *filename;
@@ -7658,8 +7688,16 @@ found: · 69 unmodified lines
76587688 /* NOTE: as GCC, uninitialized global static
76597689 arrays of null size are considered as
76607690 extern */
7691+ int t = type.t;
76617692 type.t |= VT_EXTERN;
76627693 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+ }
76637701 if (ad.alias_target) {
76647702 ElfSym *esym;
76657703 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+
6+extern char const cfileContents[];
7+char c[]="/tmp/tcc-XXXXXX.c";
8+char o[]="/tmp/tcc-XXXXXX.o";
9+void rmh(int Sig)
10+{
11+ remove(c);
12+ remove(o);
13+ signal(Sig,SIG_DFL);
14+ raise(Sig);
15+}
16+int 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+}
24+int 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;}
43+out:
44+ remove(c);
45+ remove(o);
46+ return r;
47+}
48+char 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 @@
1+extern_extern_postdeclared
2+extern_extern_postdeclared2
3+extern_extern_predeclared
4+extern_extern_predeclared2
5+extern_extern_prepostdeclared
6+extern_extern_prepostdeclared2
7+extern_extern_undeclared
8+extern_extern_undeclared2
9+extern_postdeclared
10+extern_postdeclared2
11+extern_predeclared
12+extern_predeclared2
13+extern_prepostdeclared
14+extern_undeclared
15+extern_undeclared2
16+inst2_extern_inline_postdeclared
17+inst2_extern_inline_predeclared
18+inst3_extern_inline_predeclared
19+inst_extern_inline_postdeclared
20+inst_extern_inline_predeclared
21+main
22+noinst_extern_inline_func
23+noinst_extern_inline_postdeclared
24+noinst_extern_inline_postdeclared2
25+noinst_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