This patch fixes an ICE I reported earlier today as PR go/89019, which
occurs when compiling sufficiently complicated Go code with link-time
optimization (i.e., -flto) enabled.

Both of these simple test programs are sufficient to trigger the ICE:

    $ cat crash1.go
    package main

    type fcanary func()

    $ cat crash2.go
    package main

    func f() {
        var canary func()
        func() {
            canary()
        }()
    }

The cause appears to be that the propagation of structural equality
requirements is mishandled during the handoff from the Go frontend to
the middle-end. Pointers to types that required structural equality
were not always marked as requiring structural equality themselves.
Remarkably, the only code that notices the mistake is the free_lang_data
IPA pass, which is only active when LTO is enabled.

The enclosed patch fixes the issue and provides test coverage by adding
a subtest to the Go torture test suite that compiles with -flto.
Bootstrapped and ran Go test suite on x86_64-pc-linux-gnu.

2018-01-23  Nikhil Benesch  <nikhil.bene...@gmail.com>

        PR go/89019
        * go-gcc.cc (Gcc_backend::placeholder_struct_type): Mark
        placeholder structs as requiring structural equality.
        (Gcc_backend::set_placeholder_pointer_type): Propagate
        the canonical type from the referenced type to the pointer type.
        * lib/go-torture.exp: Test compiling with -flto.

diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc
index 7fbdd074119..4e9e0e3026a 100644
--- a/gcc/go/go-gcc.cc
+++ b/gcc/go/go-gcc.cc
@@ -1049,6 +1049,7 @@ Gcc_backend::set_placeholder_pointer_type(Btype* 
placeholder,
     }
   gcc_assert(TREE_CODE(tt) == POINTER_TYPE);
   TREE_TYPE(pt) = TREE_TYPE(tt);
+  TYPE_CANONICAL(pt) = TYPE_CANONICAL(tt);
   if (TYPE_NAME(pt) != NULL_TREE)
     {
       // Build the data structure gcc wants to see for a typedef.
@@ -1080,6 +1081,12 @@ Gcc_backend::placeholder_struct_type(const std::string& 
name,
                             get_identifier_from_string(name),
                             ret);
       TYPE_NAME(ret) = decl;
+
+      // The struct type that eventually replaces this placeholder will require
+      // structural equality. The placeholder must too, so that the requirement
+      // for structural equality propagates to references that are constructed
+      // before the replacement occurs.
+      SET_TYPE_STRUCTURAL_EQUALITY(ret);
     }
   return this->make_type(ret);
 }
diff --git a/gcc/testsuite/lib/go-torture.exp b/gcc/testsuite/lib/go-torture.exp
index 213711e41df..a7eca184416 100644
--- a/gcc/testsuite/lib/go-torture.exp
+++ b/gcc/testsuite/lib/go-torture.exp
@@ -34,7 +34,8 @@ if ![info exists TORTURE_OPTIONS] {
        { -O2 -fomit-frame-pointer -finline-functions -funroll-loops } \
        { -O2 -fbounds-check } \
        { -O3 -g } \
-       { -Os }]
+       { -Os } \
+       { -flto }]
 }
 
 

Reply via email to