20

I have the following code:

#include <iostream>

class BaseClass {
 protected:
 static int x;
};

int BaseClass::x;

class DerivedA: public BaseClass {
 public:
     DerivedA() {
        x = 3;
     }
};    

class DerivedB: public BaseClass {
 public:
     DerivedB() {
        std::cout << DerivedA::x;
     }
};

int main(int argc, char* argv[]) {
        DerivedB b;
}

Compiling with g++ (g++ classtest.cpp) I receive the following error:

classtest.cpp: In constructor ‘DerivedB::DerivedB()’:
classtest.cpp:9:5: error: ‘int BaseClass::x’ is protected
int BaseClass::x;
^ classtest.cpp:25:32: error: within this context
std::cout << DerivedA::x;

When I'm compiling with clang++ (clang++ classtest.cpp) there's no error.

Why is g++ returning the compilation error?

I use g++ version 5.1.0 and clang++ version 3.6.1

Stephan Weinhold
  • 1,623
  • 1
  • 28
  • 37
Timo
  • 1,724
  • 14
  • 36
  • 4
    It also compiles in MVS2015 – Zereges Jul 13 '15 at 17:16
  • 1
    I'm more surprised that clang is **not** throwing an error... But I can confirm, it's not. – Drew Dormann Jul 13 '15 at 17:18
  • 2
    @DrewDormann Why? I'm surprised by the error: despite the `DerivedA::`, it's actually accessing a protected member of `BaseClass`, from a class that is derived from `BaseClass`. –  Jul 13 '15 at 17:21
  • I'm not positive, but doesn't it make sense that you should be declaring x inside one of the extended classes? I mean otherwise it's just a global and the protected class doesn't know that it has permissions. – TheHuman Wall Jul 13 '15 at 17:21
  • 1
    @TheHumanWall: `x` is declared as a static member of `BaseClass`. It is, and must be, defined separately. – Fred Larson Jul 13 '15 at 17:23
  • DerivedA is optimized out in the emitted IR. – Abhishek Vasisht Jul 13 '15 at 17:24
  • 3
    FWIW, this did work in GCC 4.3, but GCC 4.4 started giving error messages for it. –  Jul 13 '15 at 18:09

1 Answers1

17

GCC bug. [class.access.base]/p5:

A member m is accessible at the point R when named in class N if

  • m as a member of N is public, or
  • m as a member of N is private, and R occurs in a member or friend of class N, or
  • m as a member of N is protected, and R occurs in a member or friend of class N, or in a member of a class P derived from N, where m as a member of P is public, private, or protected, or
  • there exists a base class B of N that is accessible at R, and m is accessible at R when named in class B.

N is DerivedA, m is x, R is the constructor of DerivedB. There exists a base class BaseClass of DerivedA that is accessible at R, and x named in class BaseClass (i.e., BaseClass::x) is plainly accessible at R, so by the fourth bullet point, DerivedA::x is accessible at R.

T.C.
  • 133,968
  • 17
  • 288
  • 421
  • 1
    Thats one helluva bug. Even though the bullet in question is not the most common, its is not obscure by any means. – Captain Giraffe Jul 13 '15 at 17:39
  • 6
    Can't find this on gcc's bugzilla - want to submit? – Barry Jul 13 '15 at 17:47
  • 3
    Thanks for the clear explanation. Too bad we can't offer bounties for tasks, such as opening a bugreport :) – Timo Jul 13 '15 at 19:50
  • good **grief**. hopefully this explains the pile of incomprehensible errors i'm currently getting with 5.2 trying to implement some semi-trivial crtp. currently downloading 223 mb of debian testing updates, which `aptitude versions` implies now includes 5.3. fingers crossed this horror is resolved! – underscore_d Dec 19 '15 at 20:13
  • *exciting update**: yup, debian testing now has 5.3, which immediately solves this problem. (well, it at least lets my code compile; whether or not the binary does anything useful remains to be seen!) – underscore_d Dec 19 '15 at 20:32