$ uname -srm Linux 2.6.11.4 i686 $ g++ -v Reading specs from /opt/compilers/gcc-3.4.3/lib/gcc/i686-pc-linux-gnu/3.4.3/specs Configured with: ../gcc-3.4.3/configure --prefix=/opt/compilers/gcc-3.4.3 --enable-shared --enable-threads --enable-languages=c,c++ Thread model: posix gcc version 3.4.3 Copy and paste at prompt: $ cat > t.cpp << EOF struct A { protected: int foo_; }; template <class T> struct B : public A { }; template <class T> struct C : protected B<T> { int foo () { return A::foo_; } }; EOF Compilation of the above with: $ g++ -c t.cpp results in: t.cpp: In member function `int C<T>::foo()': t.cpp:4: error: object missing in reference to `A::foo_' t.cpp:17: error: from this location Thanks, Liviu
Ok, I don't know if this is valid code (I think it is invalid as foo_ is qualified and not dependent, even though ICC and Comeau does not reject this): struct A { int foo_; }; template <class T> struct B : public A {}; template<> struct B<int> {}; template <class T> struct C : B<T> { int foo () { return A::foo_; } }; Take the above code and add: C<int> a; void f(void) {a.foo();} ICC only rejects the code at instantiation time which seems wrong. Someone else will have to comment to make sure that I got my analysis right. The way to "fix" the if the code is invalid is to do B<T>::A::_foo or this->_foo.
A::foo_ is not template-dependent, so it is looked up and bound at the time of template definition, not at instantiation time. Because template-dependent base classes are not visible at the time, the access is assumed to be from the outside, not within the class hierarchy through this->, and the error, though surprising, is correct. W.
I discussed this with Mike Miller of EDG. His response to my query on the issue (copied with his permission) is below. Mike Miller wrote: ... > There were a couple of different examples in that thread, > so just to avoid confusion, here's the one I'll refer to: > > struct A { > int foo_; > }; > template <typename T> struct B: public A { }; > template <typename T> struct C: B<T> { > int foo() { > return A::foo_; // #1 > } > }; > > The question is how the reference on line #1 is treated. Wolfgang's > analysis isn't quite right. While it's true that "A" is non-dependent > and thus is bound to ::A at template definition time, that is > irrelevant. When C<int>::foo() (for instance) is instantiated, it turns > out that the reference to ::A::foo_ is, in fact, a non-static member of > a base class (9.3.1p3), so the reference is transformed into > (*this).::A::foo_ and there is no error. This is not a violation of > 14.6.2p3 -- there's no lookup in a dependent base class involved, as > Wolfgang's comments assume, and the description "the access is assumed > to be from the outside, not within the class hierarchy through this->" > doesn't accurately describe how 9.3.1p3 works. > > In fact, though, this just sort of happens to work because A is both > visible in the definition context and a base class of the instantiated > template. If you add an explicit specialization > > template<> struct B<int> { }; > > as suggested in Andrew's comment, so A is not a base class, or if you > change the program so that A is not visible in the definition context > (by making it a member of a namespace, for instance), we do report an > error in the instantiated C<int>::foo(). (There's no requirement to > report errors in uninstantiated templates, of course, contrary to > Andrew's observation.) > > This is sort of contrary to the "spirit" of two-stage lookup, though -- > Wolfgang's expectation is not unreasonable, I think, even though the > details of his reasoning are incorrect. I'm probably going to open a > core issue on this, especially in light of the differences between > implementations.
Here's a followup email from Mike with some calarifying comments: Mike Miller wrote: > Martin Sebor wrote: > >> Thanks a lot for the detailed analysis! I wonder if your reasoning >> would be the same given a slightly different test case (one that's >> closer to the original in comment #1): >> >>> >>> struct A { >> >> >> protected: // <<< ADDED <<< >> >>> int foo_; >>> }; >>> template <typename T> struct B: public A { }; >>> template <typename T> struct C: B<T> { >>> int foo() { >>> return A::foo_; // #1 >>> } >>> }; > > > No, I don't think that changes things. Again, the situation is the > same: whether A is the global class or the injected-class-name doesn't > affect whether C<int> (or whatever) has access to A::foo_. (There are > cases where it does matter, but this isn't one of them. Those typically > involve private or protected inheritance, where the access from > "outside" is greater than the inherited access.) > > The general principle is that non-dependent names are looked up and > bound in the definition context (14.6.3), but that's really the only > semantic effect. In cases like this one, it's as if "A" were replaced > by "::A". If the result of using "::A" is well-formed, then the version > with just "A" is, too. > >> But if an implementation is permitted to diagnose access violations >> at definition time wouldn't the gcc compilation error be justified? > > > I think the general rule is that you should only issue a diagnostic if > you can tell that no well-formed instantiation is possible (14.6p7). In > these cases, at least some specializations will have well-formed > instantiations, so no diagnostic is permitted.
Martin & Mike, I'm happy to reopen this PR. I understand your analysis, and in fact thought about it when I wrote my comment. Independently of whether it may be strictly mandated by the standard, I do have to admit that I find it confusing to see the semantics of something change at the time of instantiation, even though it was already bound at template definition time. I do think that this is a further complication of the already not quite so intuitive two-stage name lookup rules. But I guess that's immaterial. We're not into intuitive things, but into the letter of the law. Some people in this country already claim that lawyers stray too far from the letter of the law anyway, so we won't give them more reason to complain. Incidentally, two question: a) your reference to 9.3.1p3 must have been to something else. In TC1, 9.3.1 is on const and volatile member functions. b) how does your interpretation affect the validity of the following program: ------------------ struct A { int foo_; }; typedef int A::* pAi; template <typename T> struct B: public A { }; template <typename T> struct C: B<T> { pAi foo() { return &A::foo_; } }; ----------------- If A::foo_ refers to the member variable *of the present object*, then taking its address returns an int*, not an "int A::*" object, right? However, I can't seem to find a compiler that would reject the code. Thanks Wolfgang
Responses to Wolfgang's two questions: a) You're right; I was looking at the current WP rather than the 2003 Standard. Sorry. It's 9.3.1p2 in the 2003 Standard (the change from troff to LaTeX resulted in some paragraphs being numbered differently, and I didn't notice that this was one of those cases). b) No, unary & applied to a qualified-id that names a non-static member is always a pointer to member (5.3.1p2-3), regardless of whether the qualifier is an injected-class-name or an ordinary class-name.
Postponed until 4.0.2.
Confirmed, and .....
And removing target milestone and suspending since the DR report is still active: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#515
Will not be fixed in 4.1.1; adjust target milestone to 4.1.2.
This was voted in WP in 2005: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#515
Closing 4.1 branch.
Closing 4.2 branch.
GCC 4.3.4 is being released, adjusting target milestone.
Subject: Bug 21008 Author: jason Date: Fri Nov 13 14:40:22 2009 New Revision: 154150 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=154150 Log: PR c++/21008, DR 515 * semantics.c (finish_non_static_data_member): Don't check derivation in a template. Added: trunk/gcc/testsuite/g++.dg/template/inherit4.C Modified: trunk/gcc/cp/ChangeLog trunk/gcc/cp/semantics.c trunk/gcc/testsuite/ChangeLog trunk/gcc/testsuite/g++.dg/lookup/scoped8.C
Subject: Bug 21008 Author: jason Date: Fri Nov 13 15:37:29 2009 New Revision: 154153 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=154153 Log: PR c++/21008, DR 515 * semantics.c (finish_non_static_data_member): Don't check derivation in a template. Added: branches/gcc-4_3-branch/gcc/testsuite/g++.dg/template/inherit4.C Modified: branches/gcc-4_3-branch/gcc/cp/ChangeLog branches/gcc-4_3-branch/gcc/cp/semantics.c branches/gcc-4_3-branch/gcc/testsuite/ChangeLog branches/gcc-4_3-branch/gcc/testsuite/g++.dg/lookup/scoped8.C
Subject: Bug 21008 Author: jason Date: Fri Nov 13 18:03:31 2009 New Revision: 154158 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=154158 Log: PR c++/21008, DR 515 * semantics.c (finish_non_static_data_member): Don't check derivation in a template. Added: branches/gcc-4_4-branch/gcc/testsuite/g++.dg/template/inherit4.C Modified: branches/gcc-4_4-branch/gcc/cp/ChangeLog branches/gcc-4_4-branch/gcc/cp/semantics.c branches/gcc-4_4-branch/gcc/testsuite/ChangeLog branches/gcc-4_4-branch/gcc/testsuite/g++.dg/lookup/scoped8.C
Fixed.
ake: Entering directory '/home/Christian/binutils-gdb/cygwin-obj/gdb' CXXLD gdb.exe http://www.compilatori.com/computers/smartphones/ cp-support.o: in function `gdb_demangle(char const*, int)': http://www.acpirateradio.co.uk/services/ios15/ /home/Christian/binutils-gdb/cygwin-obj/gdb/../../gdb/cp-support.c:1619:(.text+0x5502): http://www.logoarts.co.uk/property/lidar-sensor/ relocation truncated to fit: R_X86_64_PC32 against undefined symbol http://www.slipstone.co.uk/property/hp-of-cars/ `TLS init function for thread_local_segv_handler' http://www.mconstantine.co.uk/category/technology/ /home/Christian/binutils-gdb/cygwin-obj/gdb/../../gdb/cp-support.c:1619:(.text+0x551b): http://embermanchester.uk/property/chat-themes/ relocation truncated to fit: R_X86_64_PC32 against undefined symbol `TLS init function for thread_local_segv_handler' collect2: error: ld returned 1 exit status http://connstr.net/property/mars-researches/ make: *** [Makefile:1881: gdb.exe] Error 1 make: Leaving directory '/home/Christian/binutils-gdb/cygwin-obj/gdb' http://joerg.li/services/kia-rio-price/ $ g++ -v Using built-in specs. http://www.jopspeech.com/technology/thunderbolt-4/ COLLECT_GCC=g++ COLLECT_LTO_ http://www.go-mk-websites.co.uk/category/technology/ WRAPPER=/usr/lib/gcc/x86_64-pc-cygwin/10/lto-wrapper.exe Target: x86_64-pc-cygwin http://www.wearelondonmade.com/tech/driving-assistant/ Configured with: /mnt/share/cygpkgs/gcc/gcc.x86_64/src/gcc-10.2.0/configure -- http://fishingnewsletters.co.uk/category/technology/ srcdir=/mnt/share/cygpkgs/gcc/gcc.x86_64/src/gcc-10.2.0 --prefix=/usr --exec-prefix=/usr http://the-hunters.org/category/travel/ --localstatedir=/var --sysconfdir=/etc --docdir=/usr/share/doc/gcc -- https://waytowhatsnext.com/computers/discord-and-steam/ htmldir=/usr/share/doc/gcc/html -C --build=x86_64-pc-cygwin --host=x86_64-pc-cygwin --target=x86_64-pc-cygwin --without-libiconv-prefix --without-libintl-prefix -- http://www.iu-bloomington.com/property/properties-in-turkey/ libexecdir=/usr/lib --with-gcc-major-version-only --enable-shared --enable-shared-libgcc --enable-static --enable-version-specific-runtime-libs --enable-bootstrap --enable-__cxa_atexit --with-dwarf2 https://komiya-dental.com/sports/telegram/ --with-tune=generic --enable-languages=c,c++,fortran,lto,objc,obj-c++ --enable-graphite --enable-threads=posix --enable-libatomic --enable-libgomp --enable-libquadmath http://www-look-4.com/health/winter-sickness/ --enable-libquadmath-support --disable-libssp --enable-libada --disable-symvers --with-gnu-ld --with-gnu-as --with-cloog-include=/usr/include/cloog-isl --without-libiconv-prefix --without-libintl-prefix --with-system-zlib https://www.webb-dev.co.uk/sports/gym-during-covid/ --enable-linker-build-id --with-default-libstdcxx-abi=gcc4-compatible --enable-libstdcxx-filesystem-ts Thread model: posix Supported LTO compression algorithms: zlib zstd gcc version 10.2.0 (GCC)