Potential bug about the order of destructors of static objects and atexit() callbacks in C++?

2016-08-01 Thread lh mouse
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++?

2016-08-01 Thread Markus Trippelsdorf
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)

2016-08-01 Thread David Brown
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

2016-08-01 Thread Prasad Ghangal
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))
 {