This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
[Bug c++/78609] invalid member's visibility detection in constexpr
- From: "matthijs at stdin dot nl" <gcc-bugzilla at gcc dot gnu dot org>
- To: gcc-bugs at gcc dot gnu dot org
- Date: Thu, 11 Jan 2018 13:29:41 +0000
- Subject: [Bug c++/78609] invalid member's visibility detection in constexpr
- Auto-submitted: auto-generated
- References: <bug-78609-4@http.gcc.gnu.org/bugzilla/>
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78609
Matthijs Kooijman <matthijs at stdin dot nl> changed:
What |Removed |Added
----------------------------------------------------------------------------
CC| |matthijs at stdin dot nl
--- Comment #2 from Matthijs Kooijman <matthijs at stdin dot nl> ---
I also ran into this problem. It seems that gcc somehow inlines c_str() (or
rather, evaluates the constexpr variable it is assigned to) before visibility
checks (possibly because the constexpr is evaluated before template
initialization?).
Below is a smaller example, which is confirmed broken up to gcc 8. I could not
reduce this example any further, so it seems the essential pattern that
triggers this is:
- There is a class instance in a constexpr variable with static storage
duration
- A pointer to a private member of this object is accessed through a method
- This pointer is assigned to a constexpr variable
- This pointer is assigned in a template instantiation
Here's the code:
class foo {
char c;
public:
//constexpr foo(): c(1) { }
//constexpr foo(char c): c(c) { }
constexpr const char* c_str() const { return &c; }
};
constexpr foo basename = foo(); // Fails
// These also fail, if you add the appropriate constructor above
//static constexpr foo basename = foo(1); // Fails
//static constexpr foo basename(1); // Fails
//static constexpr foo basename{1}; // Fails
//static constexpr foo basename{}; // Fails
// Surprisingly this works (but needs a constructor above):
//static constexpr foo basename; // Works
template <class T>
void call() {
// This is where it breaks
constexpr const char *unused = basename.c_str();
}
int main() {
// Instantiate the call function
call<int>();
}
// Removing the template argument on T makes it work
// Letting T be deduced by adding an argument to call() also fails
// Making the "unused" variable non-constexpr makes it work
// Making get() return c instead of &c makes it work
// Making "basename" a static variable inside call() also fails
//
// Tested on avr-gcc avr-gcc 4.9.2, gcc Debian 6.3.0-18, gcc Debian
// 7.2.0-19, gcc Debian 8-20180110-1
$ avr-gcc ATest.cpp -std=c++11
ATest.cpp: In instantiation of ‘void call() [with T = int]’:
ATest.cpp:26:13: required from here
ATest.cpp:2:10: error: ‘char foo::c’ is private
char c;
^
ATest.cpp:21:49: error: within this context
constexpr const char *unused = basename.c_str();
^