-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On Wed, May 11, 2005 at 11:42:05AM -0700, Mark Mitchell wrote: > no obvious answer.
May I bash my head against the wall? :) > In short, the issue is, when given the following code: > > struct A {...}; > struct B { ...; struct A a; ...; }; Telling the compiler that a relationship between the address of b and b.a exists, and that this relationship is to be created according to the relevant ABI. > void f() { C c; /*********** For later reference. ************/ > B b; > g(&b.a); > } > > does the compiler have to assume that "g" may access the parts of "b" > outside of "a". > The interesting case, therefore, is when the body of "g" is not > available, or is insufficient to make a conclusive determination. The struct declaration places an obligation on the compiler to provide an *externally* visible relationship between &b and &b.a; thereby letting &b escape out of the compiler's omniscience. If b.a is fair game for g to modify, then so is b itself - otherwise, why bother having an ABI? If you allow the compiler to assume that *only* b.a gets modified (along with any other global variables), then what will that compiler do with: void g(char const *); void f(char *s) { char const *fred = "fred walks"; *s = 'f'; g(s); } Will you allow that compiler to "optimize" that to: void f(char *s) { g("fred walks"); } since by now the compiler knows that s[0] == 'f'? If you take away the "..." preceding your "struct A a;", then immediately all of glib, GTK+, etc. break. I would find it very surprising indeed if passing an address to a function did *not* mean, "Compiler, this object and all of its containers may have been modified by the time the function returns." It would be very unfortunate to break this very useful pattern for implementing polymorphism in C, even if the letter of the law allows this "optimization". Of course, the compiler would be free to assume c unmodified, as there is no ABI-mandated relationship between &b and &c; &c doesn't escape from the compilers consciousness, so it is free to assume c is unchanged (IMO even if 'volatile', though I forget the arguments about that). > As Joseph said, this is an object of legitimate debate in the ISO C > committee. Nick's paper gives the various arguments repeated here by > ourselves and others; it is clear that there is legitimate debate, and > It's unclear what resolution will eventually be reached. Whether the letter of the law allows it or not, I expect a lot of code to break! Duff's device didn't actually *break* any programs that were expected unambiguously to work one way. That decision only specifically *allowed* certain programs to work. > 1. To avoid breaking code that may in fact already be conformant, or > will be made explicitly conformant in some future revision of the standard. Code such as memset? void g(struct A *a) { memset(a, 0, sizeof (struct B)); } > Our proposed approach is to -- by default -- assume that "g" may access > all of "b". Yes, that would satisfy the principle of least surprise. > However, in the event that the corresponding parameter to "g" has an > attribute (name TBD, possibly the same as the one that appears in > Danny's recent patch), then we may assume that "g" (and its callees) > do not use the pointer to obtain access to any fields of "b". Without threatening to overload its meaning like what happened to "static", would "restrict" suffice? ISTM that "restrict" tells the compiler the same kind of things about g()'s access of b as it tells a compiler about memcpy()'s arguments. > For example: > > void g(A *p __attribute__((X))); void *pseudo_memcpy(char *dest __attribute__((X)), char const *src __attribute__((X)), size_t n); void f(char *s, size_t n) { s[1] = 'Z'; /* Anything *but* 'r'. */ pseudo_memcpy(s, "fred foobar", n); if (s[1] == 'Z') { exit(1); } } Would the compiler be allowed to "optimize" this to: void f(char *s, size_t n) { s[1] = 'Z'; /* Anything *but* 'r'. */ pseudo_memcpy(s, "fred foobar", n); exit(1); } since it "knows" that s[1] - being outside *dest, although still inside a larger containing object - is unmodified? [Maybe this is a straw man, the struct-ness of the containing object being salient.] If I had wanted that effect, I would have liked a type modifier better: void *pseudo_memcpy(char restrict *dest, char const restrict *src, size_t n); instead of allowing access to the containing array: void *pseudo_memcpy(char * restrict dest, char const * restrict src, size_t n); > If, in future, the commitee reaches the conclusion that all functions > should be treated as if they had the attribute, Then at that point I will concede defeat in the Holy War defending C against some colleagues and start using Java! :) > i.e., that you cannot perform the kinds of operations shown above in > the example for "g", then we will modify the compiler so that, by > default, the compiler treats all parameters as if they had this > atrribute. We would then also add a switch to disable the > optimization for people who have legacy code, just as we have > -fno-strict-aliasing. Would the only way to "fix" GTK+ et al then be to pass pointers to GObject-derived widgets as "void *"??? I sincerely hope you're doing "good cop (1) / bad cop (2)" here! -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.0.4 (GNU/Linux) Comment: For info see http://www.gnupg.org iD8DBQFCgn1F/FmLrNfLpjMRAoMEAJ4iEL+CO/txAXPpRjikijQRTGSE8gCfVgF2 ZqjmPdYF2c8J5FVvSyXtXKo= =ZGJ7 -----END PGP SIGNATURE-----