https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87494
Bug ID: 87494 Summary: hidden visibility constexpr variables left unevaluated Product: gcc Version: unknown Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: froydnj at gcc dot gnu.org Target Milestone: --- The following testcase, reduced from Firefox: #pragma GCC visibility push(hidden) typedef int size_t; class A; class B { A *m_fn1() const; bool mBaseVal; }; class A {}; class nsStaticAtom : public A {}; namespace mozilla { namespace detail { struct GkAtoms { enum { F, T, AtomsCount }; nsStaticAtom mAtoms[AtomsCount]; } extern gGkAtoms; } } class nsGkAtoms { public: static constexpr nsStaticAtom *_false = &mozilla::detail::gGkAtoms.mAtoms[size_t(mozilla::detail::GkAtoms::F)]; static constexpr nsStaticAtom *_true = &mozilla::detail::gGkAtoms.mAtoms[size_t(mozilla::detail::GkAtoms::T)]; }; A *B::m_fn1() const { return mBaseVal ? nsGkAtoms::_true : nsGkAtoms::_false; } when compiled with x86-64 GCC version 8.2, gives: cmpb $0, (%rdi) movq _ZN9nsGkAtoms6_falseE(%rip), %rax je .L1 movq _ZN9nsGkAtoms5_trueE(%rip), %rax .L1: ret which leads to link failures, because neither symbol is defined. Removing the #pragma gives correct output: cmpb $0, (%rdi) movq _ZN7mozilla6detail8gGkAtomsE@GOTPCREL(%rip), %rax jne .L3 ret .L3: addq $1, %rax ret Very curiously, so does changing B::m_fn1() to: A *B::m_fn1() const { return mBaseVal ? (nsStaticAtom*)nsGkAtoms::_true : nsGkAtoms::_false; } which gives slightly different, but still correct, assembly: leaq 1+_ZN7mozilla6detail8gGkAtomsE(%rip), %rax cmpb $0, (%rdi) leaq -1(%rax), %rdx cmove %rdx, %rax ret