[Bug rtl-optimization/14319] incorrect optimization of union of structs with common initial sequences
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=14319 Tim Rentsch changed: What|Removed |Added CC||txr at alumni dot caltech.edu --- Comment #13 from Tim Rentsch --- Right you are. I don't know how I could have missed that.
[Bug rtl-optimization/14319] incorrect optimization of union of structs with common initial sequences
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=14319 --- Comment #14 from Tim Rentsch --- (In reply to James Kuyper from comment #11) That last message was in reply to James Kuyper in #11. I was expecting a reference would be added automatically.
[Bug c/83584] "ISO C forbids conversion of object pointer to function pointer type" -- no, not really
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83584 Tim Rentsch changed: What|Removed |Added CC||txr at alumni dot caltech.edu --- Comment #13 from Tim Rentsch --- (In reply to Andrew Pinski from comment #11) > So again this is not a bug. I mostly agree, but I think some clarification is needed. For reference here is the diagnostic gcc gives (under -pedantic-errors) error: ISO C forbids conversion of object pointer to function pointer This text is wrong because it is factually incorrect. There is nothing in the ISO C standard that forbids or prohibits converting an object pointer type to a function pointer type, or vice versa. The catch is that these conversions aren't required to be supported either. Section 6.3 discusses conversions, with section 6.3.2.3 specifically concerned with pointer types. Each case involving converting a type to or from a pointer type is listed with a specific permission, eg, "Any pointer type may be converted to an integer type." There is no such statement that says object pointer types may be converted to function pointer types, or vice versa. We may reasonably infer from these statements that the "may be converted" cases must be accepted by all conforming compilers, but not the others. To say this the other way, any case not explicitly covered (involving a pointer type) /may/ be accepted but is not required to be. Of course if such a conversion is evaluated its behavior is undefined, but I mean something else, namely, whether a program is accepted if it contains any such conversion, whether it is evaluated or not. To me it seems clear that the ISO C standard means that such a program doesn't have to be accepted: it /can/ be accepted, but it doesn't /have/ to be. Note section 4 paragraph 5: "A /strictly conforming program/ shall use only those features of the language and library specified in this International Standard." Converting between object pointer types and function pointer types is not covered in the Standard. I don't mean the behavior isn't defined; I mean the case is not addressed, ie, it is not a feature of the language. Hence any program containing such a conversion is not a strictly conforming program, and as such it can be rejected. So I believe gcc is within its rights to make this an error. It would be nice if the diagnostic text were better, and consistent with what the Standard says, but as far as being an error goes I think gcc is in the clear here.
[Bug c/83584] "ISO C forbids conversion of object pointer to function pointer type" -- no, not really
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83584 --- Comment #16 from Tim Rentsch --- (In reply to Andrew Pinski from comment #14) > -pedantic is not designed to reject all programs that are not strictly > conforming, but to enable emitting all _required_ diagnostics. I > don't think a conversion between function and object pointer type > requires a diagnostic. A conversion between function and object pointer type does not require a diagnostic. The point of my comment is that rejecting a program on that basis is consistent with the Standard. Moreover, it is reasonable for gcc to reject such a program on that basis, as explained below. The -pedantic option is not designed to reject all programs that are not strictly conforming. Indeed it could not do so because detecting exactly those cases is not computable. I agree that the -pedantic option is meant to enable emitting all required diagnostics. But it is not meant to emit _only_ those diagnostics that the Standard requires. For example, there is this case: static int foo[]; /* given a size later in the source */ Compiling with -pedantic (note: not -pedantic-errors!) and no other options gives error: array size missing in 'foo' This construct is syntactically valid and has no constraint violations, yet it is rejected under -pedantic. (Rejecting the program is okay because the construct itself has undefined behavior, under 6.9.2 p3.) I believe -pedantic is meant to accept(*) only those programs that are accepted by other compilers that strictly follow what ISO C requires (assuming the same type sizes, etc). That is, -pedantic is meant to be conservative, allowing only those programs that any other conforming implementation would not reject. Hence it is reasonable for -pedantic to reject the construct shown above, because some implementations might not be able to handle it. For the same reasons it is reasonable for -pedantic to reject programs with a conversion between an object pointer type and a function pointer type. More strongly, it would be _un_reasonable for such a program to be allowed under -pedantic-errors, because they very likely would be rejected by other conforming implementations; allowing such programs pretty much defeats the purpose of -pedantic. (*) Here "accept" is meant in the sense of not issuing any diagnostics for, regardless of whether the diagnostics are warnings or errors.
[Bug rtl-optimization/14319] incorrect optimization of union of structs with common initial sequences
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=14319 --- Comment #10 from Tim Rentsch --- I would like to add a few comments to the discussion. One: C and C++ are different in how they treat unions. My comments here are about C. I believe they apply to C++ as well, but I am not as familiar with the C++ standard as the C standard, so please take that into consideration. Two: The issue here is about how accesses involving struct and union members interact with aliasing questions. Clearly possible aliasing is allowed IF one considers just the effective type rules (6.5 p6&7), because the access types involved are both just 'int'. What makes a difference here is accesses being performed by way of the '->' operator, and possible union membership for the objects in question. Three: The ISO C standard doesn't articulate clearly (at least, not as clearly as I would like) what the aliasing implications are for accesses involving struct and union members. Obviously it would help if the Standard were improved in this area. Four: Despite the last observation, the "one special guarantee" clause (and hence also DR 257) is clearly not germane to this problem. The reason for this is that the "one special guarantee" clause is concerned with read access ("inspect" is the word used in the Standard), but the example code has no read accesses, only write accesses. That paragraph of the Standard is not relevant here. Five: For basically the same reason, this bug should not be considered a duplicate of Bug 65892. The example code in Bug 65892 _does_ involve a read access, and the "one special guarantee" clause _is_ relevant to that discussion. Because of that, these two bugs should be separated again, as their resolutions may be (and I believe probably will be) different in the two cases. I am expecting to post a separate comment for Bug 65892 shortly.
[Bug c/65892] gcc fails to implement N685 aliasing of union members
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65892 Tim Rentsch changed: What|Removed |Added CC||txr at alumni dot caltech.edu --- Comment #18 from Tim Rentsch --- I would like to add a few comments to the discussion. One: C and C++ are different in how they treat unions. My comments here are about C. I believe they apply to C++ as well, but I am not as familiar with the C++ standard as the C standard, so please take that into consideration. Two: I have recently posted a comment for Bug 14319. That comment explains my reasoning why these two bugs should be separated and not be considered duplicates. Three: I note the comments made by joseph with regard to the .s1/.s2 matter. There may be a larger open question there, but to avoid muddying the waters please assume that his change to use .s2 in the initializer has been made. Four: I understand that there are also larger issues related to how union membership may have a bearing on alias analysis. My comments here are confined to the particular case at hand, namely, given a definition for union U followed by a definition for function f(), could f() be optimized so the p1->m value is cached in a register (or something similar) before the body of the if() is executed, and the cached value used as the return value. Five: The answer to the question is clearly No. The example code is very much on point to the "one special guarantee" clause, and so the read access p1->m is permitted. As the access is permitted, and as there are no other conditions present that cause undefined or unspecified behavior, the behavior is well-defined, which means any optimization that changes the unoptimized behavior is wrong. Six: To see the example code is covered under the "one special guarantee" clause, note the second part of EXAMPLE 3 in 6.5.2.3. In particular, the commentary in parentheses, "(because the union type is not visible within function f)", shows that whether the union type is defined before or after f() is the determining factor here. Whether a . or -> union membership operation is present or not present has no bearing on the definedness of the struct member access p1->m. Seven: I understand the objections about impacting alias analysis and so forth. I agree that it makes the analysis more difficult (although not as sweeping in its implications as some comments imply). Despite the problems, the examples in the Standard, and also the response to DR 257, both show that the committee members fully intend that this case be covered under the "one special guarantee" clause. Eight: In the meantime, I strongly recommend gcc be patched to support the expected decision (which is the more conservative choice) rather than suspending activity until some indefinite time in the future.
[Bug c/65892] gcc fails to implement N685 aliasing of union members
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65892 --- Comment #21 from Tim Rentsch --- [responding to comments from jos...@codesourcery.com in Comment 19] >> Five: The answer to the question is clearly No. The example code >> is very much on point to the "one special guarantee" clause, and >> so the read access p1->m is permitted. As the access is permitted, > > I maintain that, as I said in comment#9, the textual history > indicates that the original intent of saying things are permitted > here is *only* an exception to the general implementation-defined > nature of type punning, not to any other reason why things might > be undefined (such as aliasing rules, data races, etc.). I went back and read through your earlier comments more carefully. After that I also reviewed C90, N869, C99, N1124, N1256, DR 236, DR 257, DR 283, and C11 (in the guise of the just-pre-C11 draft N1570). Let me say first that I agree with you that the Semantics section of the member access operators (. and ->) needs at least some revision and clarification. Having said that, let me offer several more detailed responses and/or comments. One: IME later versions of the C standard generally do a better job of expressing what is intended than earlier versions do. Two: The "visible union" condition in C99 was viewed not as a change to C90 but as correcting an oversight; it was expected all along that the union type would be in scope, even if the expectation was not a conscious one originally. I am sorry I don't have a reference handy for this, but one can be found digging around in the historical documents on the open-std.org website. Three: The "one special guarantee" rule is independent of the rules for effective types. This observation is obviously right because effective type rules matter only for access to objects. The only objects being accessed under the "one special guarantee" rule are guaranteed to have compatible types, which is always allowed by effective type rules. Four: The "one special guarantee" rule is related to the area of "type punning" through unions, but seen by WG14 as a separate issue relative to the general topic. This is evident from the committee response in DR 257. Five: The footnote added in C99 TC3 about type punning is seen by WG14 not as a change but just as a clarifying comment noting what behavior was intended all along. This is evident from the text and response in DR 283. Note that Clark Nelson, the author of this DR, is a long-standing member of WG14, and the suggested revision given in the text was adopted verbatim for the TC. Six: A key question here is What is the point or purpose of the "one special guarantee" rule in the first place? the Standard doesn't say, but let me propose two likely motivations. 1. Normally objects may be assumed not to overlap unless they are accessed through an explicit union membership expression (or through a character type, etc). The "one special guarantee" rule identifies a case where an explicit union membership expression is not needed. 2. The C standard distinctly allows any amount of padding between consecutive members of a struct. Without the "one special guarantee" rule, there would be no way to be sure that the offsets of the respective members would match in all cases. The "one special guarantee" rule has the effect of forcing offsets of struct members in a common initial sequence to be the same. That is important for code portability. Seven: Given that the question is now under serious debate, IMO someone involved with gcc development should take the initiative and responsibility to submit a defect report in order to clarify the issue. Apparently other compilers don't have this problem - only gcc does. Eight: In the meantime, the most prudent course of action is to fix gcc so that it does not reorder code in cases like the above. Whenever there is any doubt, the only sensible choice is to err on the side of caution, and not perform any code transformations that might not be allowed in a conforming implementation. (Of course it would be okay to perform such transformations under some non-default compiler option, as long as it is not in force unless explicitly requested, and clearly flagged as possibly non-conforming.) Nine: Doing a final review, I realized I have not yet responded directly to your last comment. I agree with your general sentiment that the "one special guarantee" rule is not meant as a "super rule" that trumps all other possible reasons for undefined behavior. However, I do not agree with your primary point that it is meant to be limited to the "type punning" area. The example I previously mentioned in the C standard, and the committee discussion in DR 257, both show that there are other factors involved here beyond just those related to type punning. I hope the above has helped clarify the matter. I look forward to reading your responding comment
[Bug c/65892] gcc fails to implement N685 aliasing of union members
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65892 --- Comment #22 from Tim Rentsch --- [responding to comments from rguent...@suse.de in Comment 20] > GCC already implements this if you specify -fno-strict-aliasing. The main point of my comments is that the ISO C standard requires the behavior in this case (and similar cases) be defined and not subject to any reordering. In other words the result must be the same as an unoptimized version. If a -fstrict-aliasing gcc /does/ transform the code so that the behavior is not the same as an unoptimized version, then gcc is not a conforming implementation. Or is it your position that gcc is conforming only when operated in the -fno-strict-aliasing mode? That position seems contrary to the documented description of the -fstrict-aliasing option.