diff --git a/regression/ansi-c/forceinline1/main.i b/regression/ansi-c/forceinline1/main.i new file mode 100644 index 00000000000..266e273a973 --- /dev/null +++ b/regression/ansi-c/forceinline1/main.i @@ -0,0 +1,15 @@ +#line 1 "test.c" + +__inline int foo() +{ + return 0; +} + +__forceinline int foo() +{ + return 1; +} + +int main() +{ +} diff --git a/regression/ansi-c/forceinline1/test.desc b/regression/ansi-c/forceinline1/test.desc new file mode 100644 index 00000000000..711d5e29a2b --- /dev/null +++ b/regression/ansi-c/forceinline1/test.desc @@ -0,0 +1,8 @@ +CORE +main.i +--i386-win32 +^EXIT=0$ +^SIGNAL=0$ +-- +^warning: ignoring +^CONVERSION ERROR$ diff --git a/src/ansi-c/c_typecheck_base.cpp b/src/ansi-c/c_typecheck_base.cpp index ae3d38921f2..aeddbf14a0a 100644 --- a/src/ansi-c/c_typecheck_base.cpp +++ b/src/ansi-c/c_typecheck_base.cpp @@ -333,10 +333,12 @@ void c_typecheck_baset::typecheck_redefinition_non_type( // gcc allows re-definition if the first // definition is marked as "extern inline" - if(old_symbol.type.get_bool(ID_C_inlined) && - (config.ansi_c.mode==configt::ansi_ct::flavourt::GCC || - config.ansi_c.mode==configt::ansi_ct::flavourt::APPLE || - config.ansi_c.mode==configt::ansi_ct::flavourt::ARM)) + if( + old_symbol.type.get_bool(ID_C_inlined) && + (config.ansi_c.mode == configt::ansi_ct::flavourt::GCC || + config.ansi_c.mode == configt::ansi_ct::flavourt::APPLE || + config.ansi_c.mode == configt::ansi_ct::flavourt::ARM || + config.ansi_c.mode == configt::ansi_ct::flavourt::VISUAL_STUDIO)) { // overwrite "extern inline" properties old_symbol.is_extern=new_symbol.is_extern; diff --git a/src/ansi-c/parser.y b/src/ansi-c/parser.y index 636bb7330b2..c7601ad4bd0 100644 --- a/src/ansi-c/parser.y +++ b/src/ansi-c/parser.y @@ -164,6 +164,7 @@ extern char *yyansi_ctext; %token TOK_MSC_EXCEPT "__except" %token TOK_MSC_LEAVE "__leave" %token TOK_MSC_DECLSPEC "__declspec" +%token TOK_MSC_FORCEINLINE "__forceinline" %token TOK_INTERFACE "__interface" %token TOK_CDECL "__cdecl" %token TOK_STDCALL "__stdcall" @@ -1384,6 +1385,25 @@ storage_class: | TOK_THREAD_LOCAL { $$=$1; set($$, ID_thread_local); } | TOK_GCC_ASM { $$=$1; set($$, ID_asm); } | msc_declspec { $$=$1; } + | TOK_MSC_FORCEINLINE + { + // equivalent to always_inline, and seemingly also has the semantics + // of extern inline in that multiple definitions can be provided in + // the same translation unit + init($$); + set($$, ID_static); + set($1, ID_inline); + #if 0 + // enable once always_inline support is reinstantiated + $1=merge($1, $$); + + init($$); + set($$, ID_always_inline); + $$=merge($1, $$); + #else + $$=merge($1, $$); + #endif + } ; basic_type_name: diff --git a/src/ansi-c/scanner.l b/src/ansi-c/scanner.l index 765a30fbf0f..cafb78a652b 100644 --- a/src/ansi-c/scanner.l +++ b/src/ansi-c/scanner.l @@ -1138,7 +1138,7 @@ __decltype { if(PARSER.cpp98 && "__forceinline" { if(PARSER.mode==configt::ansi_ct::flavourt::VISUAL_STUDIO || PARSER.mode==configt::ansi_ct::flavourt::ARM) - { loc(); return TOK_INLINE; } + { loc(); return TOK_MSC_FORCEINLINE; } else return make_identifier(); } diff --git a/src/cpp/parse.cpp b/src/cpp/parse.cpp index 8e6ba81ee0f..bae7366f9a0 100644 --- a/src/cpp/parse.cpp +++ b/src/cpp/parse.cpp @@ -1952,14 +1952,19 @@ bool Parser::optMemberSpec(cpp_member_spect &member_spec) int t=lex.LookAhead(0); - while(t==TOK_FRIEND || t==TOK_INLINE || t==TOK_VIRTUAL || t==TOK_EXPLICIT) + while( + t == TOK_FRIEND || t == TOK_INLINE || t == TOK_VIRTUAL || + t == TOK_EXPLICIT || t == TOK_MSC_FORCEINLINE) { cpp_tokent tk; lex.get_token(tk); switch(t) { - case TOK_INLINE: member_spec.set_inline(true); break; + case TOK_INLINE: + case TOK_MSC_FORCEINLINE: + member_spec.set_inline(true); + break; case TOK_VIRTUAL: member_spec.set_virtual(true); break; case TOK_FRIEND: member_spec.set_friend(true); break; case TOK_EXPLICIT: member_spec.set_explicit(true); break;