Potential bug about the order of destructors of static objects and atexit() callbacks in C++?
Hello GCC developers, Reading the ISO C++ standard, > 3.6.4 Termination [basic.start.term] > 3 If the completion of the initialization of an object with > static storage duration is sequenced before a call to std::atexit > (see , 18.5), the call to the function passed to std::atexit > is sequenced before the call to the destructor for the object. ... Notwithstanding the vagueness of 'the completion of the initialization of an object', the following program: #include #include enum class state { null, initialized, destroyed, }; extern void broken_atexit(); struct global_data { state s; global_data() : s(state::null) { std::puts("delegated constructor"); } global_data(int) : global_data() { s = state::initialized; std::atexit(&broken_atexit); std::puts("delegating constructor"); } ~global_data(){ s = state::destroyed; } } data(1); void broken_atexit(){ if(data.s == state::destroyed){ std::puts("attempt to use a destroyed object?"); std::abort(); } std::puts("okay"); } int main(){ } , when compiled with GCC, results in use of a destroyed object: lh_mouse@lhmouse-dev:~$ g++ test.cc -std=c++11 lh_mouse@lhmouse-dev:~$ ./a.out delegated constructor delegating constructor attempt to use a destroyed object? Aborted lh_mouse@lhmouse-dev:~$ The reason of this problem is that GCC front-end registers the dtor after the delegating constructor returns, which is invoked before the other callback registered inside the delegating constructor body. The problem would be gone only if the GCC front-end registers the dtor after the delegated constructor returns. Is this a GCC bug? -- Best regards, lh_mouse 2016-08-01
Re: Potential bug about the order of destructors of static objects and atexit() callbacks in C++?
On 2016.08.01 at 18:16 +0800, lh mouse wrote: > Hello GCC developers, > > Reading the ISO C++ standard, > > 3.6.4 Termination [basic.start.term] > > 3 If the completion of the initialization of an object with > > static storage duration is sequenced before a call to std::atexit > > (see , 18.5), the call to the function passed to std::atexit > > is sequenced before the call to the destructor for the object. ... > > Notwithstanding the vagueness of 'the completion of the initialization of an > object', > the following program: > > #include > #include > > enum class state { > null, > initialized, > destroyed, > }; > > extern void broken_atexit(); > > struct global_data { > state s; > > global_data() > : s(state::null) > { > std::puts("delegated constructor"); > } > global_data(int) > : global_data() > { > s = state::initialized; > std::atexit(&broken_atexit); > std::puts("delegating constructor"); > } > ~global_data(){ > s = state::destroyed; > } > } data(1); > > void broken_atexit(){ > if(data.s == state::destroyed){ > std::puts("attempt to use a destroyed object?"); > std::abort(); > } > std::puts("okay"); > } > > int main(){ > } > > , when compiled with GCC, results in use of a destroyed object: > > lh_mouse@lhmouse-dev:~$ g++ test.cc -std=c++11 > lh_mouse@lhmouse-dev:~$ ./a.out > delegated constructor > delegating constructor > attempt to use a destroyed object? > Aborted > lh_mouse@lhmouse-dev:~$ > > The reason of this problem is that GCC front-end registers the dtor after > the delegating constructor returns, which is invoked before the other > callback registered inside the delegating constructor body. > > The problem would be gone only if the GCC front-end registers the dtor after > the delegated constructor returns. > > Is this a GCC bug? I don't think so. All compilers (clang, icc, visual C++) behave the same. Also these kinds of questions regarding the C++ standard should be asked on a more appropriate forum like stackoverflow.com or the ISO C++ group: https://groups.google.com/a/isocpp.org/forum/?fromgroups#!forum/std-discussion -- Markus
Re: Two suggestions for gcc C compiler to extend C language (by WD Smith)
On 29/07/16 20:54, Warren D Smith wrote: > On 7/29/16, Jonathan Wakely wrote: >> Let's imagine we have a 4-bit type, called nibble. >> >> sizeof(nibble) == 1, because you can't have an object with a smaller size. >> >> nibble a[2]; >> sizeof(a) == 1; >> >> Because otherwise there isn't much benefit. > > --bitsizeof() is required. That would not change how "sizeof" works. > >> So now we have a type which violates one of the core rules of the type >> system. sizeof(nibble[2 * N]) != 2 * sizeof(nibble[N]) > > --by the way, it is spelled "nybble." Just like 8-bit objects > are not called a "bite." If you are reading "bite magazine" you are probably > in a different area. And the reason that commonly-used words > like nybble and byte were coined, is these are common concepts, in common use. > Not an ultra-rare concept hardly ever used, like > some people have utterly ridiculously asserted. Actually, it is almost always spelt "nibble". Some people do spell it "nybble", but "nibble" is the most common. > >> That means any generic code that works with arbitrary types doesn't >> work with this type. > > --But C does not support generic code per se. > >> This also breaks various idioms: >> >> nibble b[3]; >> for(int i=0; i < sizeof(b)/sizeof(b[0]); ++i) >> ... >> >> This loop doesn't visit all the elements. > > --if you want to use stupid idioms, you will have bugs. > If you wanted to be smart about it, you use some sort of bitsizeof() which > should have been what C provided in the first place. > So to be "smart", we should use features that C does not have, but which you think it should have had? All these people writing correct, working code are "stupid", when in fact we should have been "smart" enough to write code that does not make sense in C and could not compiler? >> Given a pointer to an array of nibbles and a length, how do I iterate >> through the array? > > for(i=0; i Even if it were possible to have the packed nibble array "a", and there were a "bitsizeof" operator, then that still would not be correct. > >> void do_something(nibble* p); >> int sum (nibble* p, size_t n) { >> while (n) >> do_something(p+n); >> } >> >> Pointer arithmetic won't work, because you can't address half a byte. >> What is the address of p[n-1] ? You can't know, without knowing if p >> points to the first or second nibble in a byte. > > --pointers would either have to be forbidden for subbyte objects, or > would have to be implemented in a way involving, e.g., a shift if necessary. > For example, the 7th bit inside a byte -- well 3 extra bits of > address are needed to know which bit it is, so which byte is address>>3, > and which bit is address&7. > > By the way, on some machines I think this already happens, not to > address bits and nybbles, but to address bytes. Did anybody moan that > on such machines, "bytes are unaddressable"? And therefore unusable > in C? Accessing a "byte" is always easy in C, because that's the definition of a "byte" - I assume you mean "octet". Yes, people who use machines with CHAR_BIT == 16 (or anything other than 8) /do/ moan because they can't access octets easily. I know I certainly moaned when programming on such a processor. There is no octet type, or uint8_t, on such systems. You can't make arrays of 8-bit elements, and you can't take their addresses or directly address them. You have to use bitfields, or shifts and masks. This applies to all C compilers on such devices (as far as I know, gcc does not support any CHAR_BIT == 16 systems). > If and when anybody ever moaned that, then people like you told > them they were idiots, and you implemented the right tuff to do it > inside GCC. Undoubtably therefore, the needed code for my suggestion > already is inside GCC, merely with a few numbers changed. They moan about it - but they live with it, because that's the way C works, and that's the processor they are dealing with. And they write access functions or bitfields as needed to get the job done. They don't demand that their compiler supplier does something magical. > >> C does not naturally work with objects smaller than a byte (which >> means the smallest addressable memory location, and is at least 8 bits >> but might be more). They can exist as bit fields inside other objects, >> but not in isolation. > > --other languages like Pascal managed to address these "unaddressable" > objects, > to use the bogus word one of my critics branded them with. No, Pascal cannot address items smaller than a byte. Pascal provides abstractions in its array operators that let you work with packed arrays - that is because Pascal's array operator is a higher level than C's array operator, and has more features. > >> To use such types it's is much cleaner to define an abstraction layer >> that does the packing, masking, extracting etc. for you. Either a set >> of functions that work with a pointer to some buffer, into which 4-bit >> values are store
[gimplefe] "Unknown tree: c_maybe_const_expr" error while parsing conditional expression
Hi, I am trying to replace c_parser_paren_condition (parser) in c_parser_gimple_if_stmt by c_parser_gimple_paren_condition (parser) as described in the patch I am trying test case void __GIMPLE () foo () { int a; bb_2: if (a == 2) goto bb_3; else goto bb_4; bb_3: a_2 = 4; bb_4: return; } but it fails to parse gimple expression and produces error as /home/prasad/test3.c: In function ‘foo’: /home/prasad/test3.c:1:18: error: invalid operands in gimple comparison void __GIMPLE () foo () ^~~ if (<<< Unknown tree: c_maybe_const_expr a >>> == 2) goto bb_3; else goto bb_4; /home/prasad/test3.c:1:18: internal compiler error: verify_gimple failed I failed to debug where it is setting to C_MAYBE_CONST_EXPR Thanks, Prasad diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 70800a2..9e5152c 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -1425,6 +1425,7 @@ static void c_parser_gimple_switch_stmt (c_parser *, gimple_seq *); static void c_parser_gimple_return_stmt (c_parser *, gimple_seq *); static void c_finish_gimple_return (location_t, tree); static c_expr c_parser_parse_ssa_names (c_parser *); +static tree c_parser_gimple_paren_condition (c_parser *); /* Parse a translation unit (C90 6.7, C99 6.9). @@ -19025,6 +19026,25 @@ c_parser_gimple_goto_stmt (location_t loc, tree label, gimple_seq *seq) return; } +/* Parse a parenthesized condition */ + +static tree +c_parser_gimple_paren_condition (c_parser *parser) +{ + c_expr cond; + enum tree_code subcode = NOP_EXPR; + cond.original_code = ERROR_MARK; + cond.original_type = NULL; + location_t loc = c_parser_peek_token (parser)->location; + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) +return error_mark_node; + cond = c_parser_gimple_binary_expression (parser, &subcode); + cond = convert_lvalue_to_rvalue (loc, cond, true, true); + cond.value = c_objc_common_truthvalue_conversion (loc, cond.value); + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + return cond.value; +} + /* Parse gimple if-else statement */ static void @@ -19033,7 +19053,7 @@ c_parser_gimple_if_stmt (c_parser *parser, gimple_seq *seq) tree cond, t_label, f_label, label; location_t loc; c_parser_consume_token (parser); - cond = c_parser_paren_condition (parser); + cond = c_parser_gimple_paren_condition (parser); if (c_parser_next_token_is_keyword (parser, RID_GOTO)) {