Bug 40490 - failure to emit resolved inline virtual function definition or IMPORT on HP-UX with -O
Summary: failure to emit resolved inline virtual function definition or IMPORT on HP-U...
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: middle-end (show other bugs)
Version: 4.4.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2009-06-19 00:20 UTC by Scott McPeak
Modified: 2010-03-16 14:30 UTC (History)
4 users (show)

See Also:
Host: hppa2.0w-hp-hpux11.11
Target: hppa2.0w-hp-hpux11.11
Build: hppa2.0w-hp-hpux11.11
Known to work:
Known to fail:
Last reconfirmed: 2009-06-21 18:32:03


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Scott McPeak 2009-06-19 00:20:31 UTC
The following input:

  class A {
  public:
    A();
    virtual void find() {}
  };

  static void foo(A &a)
  {
    a.find();
  }

  void bar()
  {
    A a;
    foo(a);
  }

when compiled with gcc-4.0.3, 4.0.4, 4.3.3 and 4.4.0 on HP-UX with -O
will produce assembly code that contains a call to find() but no
definition and no IMPORT:

  $ gcc-4.4.0/bin/g++ -S -O repro.cc
  $ grep 4find repro.s
          bl _ZN1A4findEv,%r2

Contrast with A::A(), which has both a call and an IMPORT:

  $ grep AC1 repro.s
          bl _ZN1AC1Ev,%r2
          .IMPORT _ZN1AC1Ev,CODE

The above input is approximately minimal; removing or changing any of
the features will make the problem disappear, typically by causing
find() to be completely inlined into the call site.

Interestingly, gcc-4.1.2 does not show a problem on this particular
input, although my recollection is it was showing the problem on a
larger variant.  I do not know where along the minimization process
gcc-4.1.2 stopped reproducing.

The lack of an IMPORT despite no definition is particularly nasty,
because 'nm' simply reports it as an undefined symbol, but the HP-UX
linker refuses to link the result into an executable when presented
with another object file that contains the definition:

  $ g++ -c -O repro.cc
  $ g++ -c -O rest.cc      # defines A::A() and main()
  $ g++ repro.o rest.o
  /usr/ccs/bin/ld: Unsatisfied symbols:
     A::find()    (first referenced in repro.o) (data)
  collect2: ld returned 1 exit status
  $ nm repro.o | grep 4find
           U _ZN1A4findEv
  $ nm rest.o | grep 4find
  00000000 W _ZN1A4findEv

The above is with GNU 'as' 2.15 and 2.17 (same result).  When using
the HP-UX assembler version "HP92453-03 UX.11.01.17 PA-RISC 2.0
Assembler" (which only accepts gcc-4.0.x output), it more helpfully
notices the missing IMPORT:

  as: error 7403: undefined label - _ZN1A4findEv (7403)

Of course, I didn't discover the IMPORT issue until after some hours
of searching for an explanation to the mysterious linker complaint.
It would be nice if GNU 'as' would realize that it is creating a .o
file that cannot be linked.

For completeness, the HP-UX linker version is "92453-07 linker linker
ld B.11.63 071126".

The IMPORT anomaly is specific to HP-UX, but the failure to emit a
definition of an inline is not.  On linux/x86_64 with gcc-4.0.3, for
example, repro.o again has a call but no definition, but is able to
link by using the definition from rest.o because there is no IMPORT
concept.  I find it suspicious that the compiler would ever choose to
emit a direct call to a defined inline function without also including
that function's definition; but the C++ ODR guarantees the compiler it
will see the class definition again, including the method body, in the
translation unit containing the definition of A::A(), so the omission
is not by itself necessarily indicative of a bug.

It's worth noting that the presence of a direct call to find() means
the compiler figured out it is A::find() being called, despite that
method being virtual.  I suspect the mechanism that does that may be
partly to blame.  That's the reason for including "resolved" in this
bug's title.
Comment 1 John David Anglin 2009-06-21 18:32:03 UTC
Changing to middle-end as it is responsible for determining which
calls are added to the list of pending assemble externals.
Comment 2 John David Anglin 2009-07-04 22:05:49 UTC
Breakpoint 6, assemble_external (decl=0x7ae86f80)
    at ../../gcc/gcc/varasm.c:2304
2304	  gcc_assert (asm_out_file);
(gdb) p debug_tree (decl)
 <function_decl 7ae86f80 find
    type <method_type 7ae85f08
        type <void_type 7adf74e0 void VOID
            align 8 symtab 0 alias set -1 canonical type 7adf74e0
            pointer_to_this <pointer_type 7adf7548>>
        SI
        size <integer_cst 7ade07a0 constant 32>
        unit size <integer_cst 7ade0540 constant 4>
        align 32 symtab 0 alias set -1 canonical type 7ae85f08 method basetype <record_type 7ae85d00 A>
        arg-types <tree_list 7ae8c7e0 value <pointer_type 7ae85f70>
            chain <tree_list 7adfa1a0 value <void_type 7adf74e0 void>>>
        pointer_to_this <pointer_type 7ae8e3a8>>
    addressable used nothrow public static weak autoinline no-static-chain virtual decl_5 SI defer-output file pr40490.cc line 4 col 16 align 32 context <record_type 7ae85d00 A> initial <error_mark 7ade0500>
    arguments <parm_decl 7adf65a0 this
        type <pointer_type 7ae8e000 type <record_type 7ae85d00 A>
            readonly unsigned SI size <integer_cst 7ade07a0 32> unit size <integer_cst 7ade0540 4>
            align 32 symtab 0 alias set -1 canonical type 7ae8e000>
        readonly unsigned SI file pr40490.cc line 4 col 21 size <integer_cst 7ade07a0 32> unit size <integer_cst 7ade0540 4>
        align 32 context <function_decl 7ae86f80 find> arg-type <pointer_type 7ae8e000>>
    result <result_decl 7adf66e0 D.1717 type <void_type 7adf74e0 void>
        ignored VOID file pr40490.cc line 4 col 23
        align 8 context <function_decl 7ae86f80 find>>
    pending-inline-info 7ae8bd90
    (mem:SI (symbol_ref/v/i:SI ("@_ZN1A4findEv") [flags 0x1] <function_decl 7ae86f80 find>) [0 S4 A32])>
$10 = void

DECL_EXTERNAL (decl) is 0, so the symbol is not imported.  Probably, the
component should be changed to c++.
Comment 3 Michael Haubenwallner 2010-03-16 14:30:43 UTC
While the input from comment#0 indeed seems to work with gcc-4.2.4 too, this one has the same problem with 4.2.4, 4.3.1 and 4.4.3 (each hp-gcc):

  class A
  {
  public:
    virtual ~A();
    virtual void find() {}
  };

  void foo()
  {
    A a;
    A* pa = &a;
    pa->find();
  }