diff --git a/src/ansi-c/ansi_c_convert_type.cpp b/src/ansi-c/ansi_c_convert_type.cpp index 618568bd5da..e35aa32d9b6 100644 --- a/src/ansi-c/ansi_c_convert_type.cpp +++ b/src/ansi-c/ansi_c_convert_type.cpp @@ -229,6 +229,10 @@ void ansi_c_convert_typet::read_rec(const typet &type) } else if(type.id()==ID_noreturn) c_qualifiers.is_noreturn=true; + else if(type.id()==ID_constructor) + constructor=true; + else if(type.id()==ID_destructor) + destructor=true; else other.push_back(type); } @@ -274,6 +278,33 @@ void ansi_c_convert_typet::write(typet &type) } type.swap(other.front()); + + if(constructor || destructor) + { + if(constructor && destructor) + { + err_location(source_location); + str << "combining constructor and destructor not supported"; + error_msg(); + throw 0; + } + else if(type.id()!=ID_empty) + { + err_location(source_location); + str << "constructor and destructor required to be type void"; + error_msg(); + throw 0; + } + + type.id(constructor ? ID_constructor : ID_destructor); + } + } + else if(constructor || destructor) + { + err_location(source_location); + str << "constructor and destructor required to be type void"; + error_msg(); + throw 0; } else if(gcc_float128_cnt) { diff --git a/src/ansi-c/ansi_c_convert_type.h b/src/ansi-c/ansi_c_convert_type.h index eff7353dffd..a40d3f3549e 100644 --- a/src/ansi-c/ansi_c_convert_type.h +++ b/src/ansi-c/ansi_c_convert_type.h @@ -34,6 +34,7 @@ class ansi_c_convert_typet:public message_streamt bool packed, aligned; exprt vector_size, alignment, bv_width, fraction_width; exprt msc_based; // this is Visual Studio + bool constructor, destructor; // storage spec c_storage_spect c_storage_spec; @@ -67,7 +68,7 @@ class ansi_c_convert_typet:public message_streamt msc_based.make_nil(); gcc_attribute_mode.make_nil(); - packed=aligned=false; + packed=aligned=constructor=destructor=false; other.clear(); c_storage_spec.clear(); diff --git a/src/ansi-c/expr2c.cpp b/src/ansi-c/expr2c.cpp index f4dcac5616a..c8797e8c726 100644 --- a/src/ansi-c/expr2c.cpp +++ b/src/ansi-c/expr2c.cpp @@ -694,6 +694,11 @@ std::string expr2ct::convert_rec( { return q+"__builtin_va_list"+d; } + else if(src.id()==ID_constructor || + src.id()==ID_destructor) + { + return q+"__attribute__(("+id2string(src.id())+")) void"+d; + } { lispexprt lisp; diff --git a/src/ansi-c/parser.y b/src/ansi-c/parser.y index 4e404c94a3a..a933daafe29 100644 --- a/src/ansi-c/parser.y +++ b/src/ansi-c/parser.y @@ -133,6 +133,8 @@ extern char *yyansi_ctext; %token TOK_GCC_ATTRIBUTE_GNU_INLINE "__gnu_inline__" %token TOK_GCC_ATTRIBUTE_WEAK "weak" %token TOK_GCC_ATTRIBUTE_NORETURN "noreturn" +%token TOK_GCC_ATTRIBUTE_CONSTRUCTOR "constructor" +%token TOK_GCC_ATTRIBUTE_DESTRUCTOR "destructor" %token TOK_GCC_ATTRIBUTE_END ")" %token TOK_GCC_LABEL "__label__" %token TOK_MSC_ASM "__asm" @@ -1566,6 +1568,10 @@ gcc_type_attribute: { $$=$1; set($$, ID_noreturn); } | TOK_GCC_ATTRIBUTE_NORETURN TOK_GCC_ATTRIBUTE_END { $$=$1; set($$, ID_noreturn); } + | TOK_GCC_ATTRIBUTE_CONSTRUCTOR TOK_GCC_ATTRIBUTE_END + { $$=$1; set($$, ID_constructor); } + | TOK_GCC_ATTRIBUTE_DESTRUCTOR TOK_GCC_ATTRIBUTE_END + { $$=$1; set($$, ID_destructor); } | gcc_attribute_specifier ; diff --git a/src/ansi-c/scanner.l b/src/ansi-c/scanner.l index 977f428231e..fa9284bc888 100644 --- a/src/ansi-c/scanner.l +++ b/src/ansi-c/scanner.l @@ -1378,6 +1378,12 @@ __decltype { if(PARSER.cpp98 && PARSER.mode==ansi_c_parsert::GCC) "noreturn" | "__noreturn__" { BEGIN(GCC_ATTRIBUTE3); loc(); return TOK_GCC_ATTRIBUTE_NORETURN; } +"constructor" | +"__constructor__" { BEGIN(GCC_ATTRIBUTE3); loc(); return TOK_GCC_ATTRIBUTE_CONSTRUCTOR; } + +"destructor" | +"__destructor__" { BEGIN(GCC_ATTRIBUTE3); loc(); return TOK_GCC_ATTRIBUTE_DESTRUCTOR; } + {ws} { /* ignore */ } {newline} { /* ignore */ } {identifier} { BEGIN(GCC_ATTRIBUTE4); } diff --git a/src/cpp/cpp_typecheck.cpp b/src/cpp/cpp_typecheck.cpp index 232b494849b..73230c0723a 100644 --- a/src/cpp/cpp_typecheck.cpp +++ b/src/cpp/cpp_typecheck.cpp @@ -301,8 +301,7 @@ void cpp_typecheckt::static_and_dynamic_initialization() init_symbol.mode=ID_cpp; init_symbol.module=module; init_symbol.type=code_typet(); - init_symbol.type.add(ID_return_type)=typet(ID_empty); - init_symbol.type.set("initialization", true); + init_symbol.type.add(ID_return_type)=typet(ID_constructor); init_symbol.is_type=false; init_symbol.is_macro=false; diff --git a/src/linking/remove_internal_symbols.cpp b/src/linking/remove_internal_symbols.cpp index 71c801254ce..cdb59b3baa9 100644 --- a/src/linking/remove_internal_symbols.cpp +++ b/src/linking/remove_internal_symbols.cpp @@ -132,6 +132,15 @@ void remove_internal_symbols( symbol.value.is_not_nil() && !symbol.value.get_bool(ID_C_zero_initializer); + // __attribute__((constructor)), __attribute__((destructor)) + if(symbol.mode==ID_C && is_function && is_file_local) + { + const code_typet &code_type=to_code_type(symbol.type); + if(code_type.return_type().id()==ID_constructor || + code_type.return_type().id()==ID_destructor) + is_file_local=false; + } + if(is_type) { // never EXPORTED by itself diff --git a/src/linking/static_lifetime_init.cpp b/src/linking/static_lifetime_init.cpp index 6c909e19d11..096a4e7f749 100644 --- a/src/linking/static_lifetime_init.cpp +++ b/src/linking/static_lifetime_init.cpp @@ -160,8 +160,8 @@ bool static_lifetime_init( { const symbolt &symbol=ns.lookup(id); - if(symbol.type.get_bool("initialization") && - symbol.type.id()==ID_code) + if(symbol.type.id()==ID_code && + to_code_type(symbol.type).return_type().id()==ID_constructor) { code_function_callt function_call; function_call.function()=symbol.symbol_expr();