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

Reply via email to