Bug 65284 - [5 Regression] C++ lambda and auto return value causes ICE or gimple error
Summary: [5 Regression] C++ lambda and auto return value causes ICE or gimple error
Status: RESOLVED DUPLICATE of bug 65339
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 5.0
: P3 normal
Target Milestone: 5.0
Assignee: Aldy Hernandez
URL:
Keywords: ice-on-valid-code, rejects-valid
Depends on:
Blocks:
 
Reported: 2015-03-02 22:05 UTC by Matthias Klose
Modified: 2015-03-09 20:36 UTC (History)
4 users (show)

See Also:
Host:
Target: arm-linux-gnueabihf, x86-64-linux
Build:
Known to work: 4.9.2
Known to fail: 5.0
Last reconfirmed: 2015-03-04 00:00:00


Attachments
reduced testcase (247 bytes, text/plain)
2015-03-04 23:19 UTC, Aldy Hernandez
Details
smaller and simpler testcase (190 bytes, text/plain)
2015-03-06 22:44 UTC, Aldy Hernandez
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Matthias Klose 2015-03-02 22:05:48 UTC
r221115 on arm-linux-gnueabihf

$ g++ -std=c++11 -c -O2 schema-parser.ii 
schema-parser.ii: In member function 'Maybe<ParsedSchema> ParsedSchema::findNested() const':
schema-parser.ii:45:21: internal compiler error: Segmentation fault
 Maybe<ParsedSchema> ParsedSchema::findNested() const {
                     ^
Please submit a full bug report,
with preprocessed source if appropriate.

$ gdb --args /usr/lib/gcc/arm-linux-gnueabihf/5/cc1plus -fpreprocessed schema-parser.ii -quiet -dumpbase schema-parser.ii -march=armv7-a -mfloat-abi=hard -mfpu=vfpv3-d16 -mthumb -mtls-dialect=gnu -auxbase schema-parser -O2 -std=c++11 -version -fstack-protector-strong -Wformat -Wformat-security -o /tmp/ccABpp5w.s

(gdb) bt
#0  0x00346d52 in maybe_canonicalize_mem_ref_addr(tree_node**) ()
#1  0x0034ee4c in fold_stmt_1(gimple_stmt_iterator*, bool, tree_node* (*)(tree_node*)) ()
#2  0x0053bb56 in (anonymous namespace)::pass_forwprop::execute(function*) ()
#3  0x00434e5e in execute_one_pass(opt_pass*) ()
#4  0x00435148 in execute_pass_list_1(opt_pass*) [clone .constprop.59] ()
#5  0x00435152 in execute_pass_list_1(opt_pass*) [clone .constprop.59] ()
#6  0x00435180 in execute_pass_list(function*, opt_pass*) ()
#7  0x00298eb6 in cgraph_node::expand() ()
#8  0x0029a93c in symbol_table::compile() [clone .part.42] ()
#9  0x0029ab78 in symbol_table::finalize_compilation_unit() ()
#10 0x001a34e4 in cp_write_global_declarations() ()
#11 0x004aa082 in compile_file() ()
#12 0x001571a6 in toplev::main(int, char**) ()
#13 0x00157bf4 in main ()

$ cat schema-parser.ii
namespace _ {
template <typename T> class NullableValue {
public:
  T operator*();
  NullableValue(T);
};
}
template <typename T> class Maybe {
public:
  Maybe(T t) : ptr(t) {}
  template <typename Func> auto map(Func f) -> Maybe<decltype(f(T()))> {
    return f(*ptr);
  }
  _::NullableValue<T> ptr;
};
template <typename T> class A {
public:
  T *operator->();
};
typedef int uint64_t;
class B {
public:
  long getId();
};
class C {
  struct D;
  A<D> impl;
  friend class ParsedSchema;
};
class ParsedSchema {
  Maybe<ParsedSchema> findNested() const;
  ParsedSchema(ParsedSchema, C);
  C *parser;
  B getProto() const;
  int raw;
};
class F {
public:
  Maybe<uint64_t> lookup(uint64_t, int);
  ParsedSchema get(uint64_t);
};
struct C::D {
  F compiler;
};
Maybe<ParsedSchema> ParsedSchema::findNested() const {
  int name;
  parser->impl->compiler.lookup(getProto().getId(), name)
      .map([this](uint64_t childId) {
        return ParsedSchema(parser->impl->compiler.get(childId), *parser);
      });
}
Comment 1 Richard Biener 2015-03-03 10:01:53 UTC
I get (on x86_64-linux):

./cc1plus  -quiet t.ii -std=c++11
t.ii: In lambda function:
t.ii:50:7: error: using result of function returning 'void'
       });
       ^

so assuming the testcase is valid this is a C++ rejects-valid bug now
(4.9 accepts it)?

and with a cross to arm:

> ./cc1plus  -quiet -std=c++11 ../../trunk-g/gcc/t.ii -I include
../../trunk-g/gcc/t.ii: In lambda function:
../../trunk-g/gcc/t.ii:48:30: error: non-trivial conversion at assignment
  .map([this](uint64_t childId) {
                              ^
struct ParsedSchema
struct ParsedSchema *
<retval> = D.4929;
../../trunk-g/gcc/t.ii:48:30: internal compiler error: verify_gimple failed
0xf83713 verify_gimple_in_seq(gimple_statement_base*)
        /space/rguenther/src/svn/trunk2/gcc/tree-cfg.c:4736
0xcb9d25 gimplify_body(tree_node*, bool)

do you have checking disabled?
Comment 2 Matthias Klose 2015-03-03 19:06:31 UTC
> do you have checking disabled?

configured with --enable-checking=release
Comment 3 Aldy Hernandez 2015-03-04 16:33:57 UTC
Confirmed with --enable-checking=release and a cross build:

$ ./cc1plus a.ii -quiet -std=c++11 -I./ -O2
a.ii: In member function ‘Maybe<ParsedSchema> ParsedSchema::findNested() const’:
a.ii:45:21: internal compiler error: Segmentation fault
 Maybe<ParsedSchema> ParsedSchema::findNested() const {


I'll take a look.
Comment 4 Aldy Hernandez 2015-03-04 19:54:24 UTC
This was caused by r210292:

commit f1ec53b67367cb5d4aba65b5648e5faa5f29bdf0
Author: jason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Date:   Fri May 9 20:07:45 2014 +0000

        PR c++/60463
        PR c++/60755
        * lambda.c (lambda_expr_this_capture): Add new parameter
        add_capture_p controlling whether the functions will try to
        capture 'this' via the default capture.
        (maybe_resolve_dummy): Likewise.
        * cp-tree.h: Adjust prototypes.
        * call.c, semantics.c: Change callers of these functions.
        * call.c (build_new_method_call_1): Use the actual 'this' that
        would be potentially captured for the overload resolution, instead
        of the dummy object.
    
    git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@210292 138bc75d-0d04-0410-961f-82ee72b054a4

Jason, just so I know what I'm looking at here, is the testcase even valid?  Because mainline on x86-64 has a totally different symptom than ppc with --enable-checking and a totally different symptom than ppc with --enable-checking=release.

On mainline on x86-64 (with either default checking or --enable-checking=release), we get:

reynosa:/build/t/gcc$ ./cc1plus ~/a.ii -quiet -std=c++11 -O2 -I./
/home/aldyh/a.ii: In lambda function:
/home/aldyh/a.ii:50:7: error: using result of function returning ‘void’
       });

On a cross PPC with default checking we get:

reynosa:/build/arm-linux-gnueabihf-checking/gcc$ ./cc1plus ~/a.ii -quiet -std=c++11 -O2 -I./ 
/home/aldyh/a.ii: In lambda function:
/home/aldyh/a.ii:48:35: error: non-trivial conversion at assignment
       .map([this](uint64_t childId) {
                                   ^
struct ParsedSchema
struct ParsedSchema *
<retval> = D.4925;
/home/aldyh/a.ii:48:35: internal compiler error: verify_gimple failed
0xf4da3b verify_gimple_in_seq(gimple_statement_base*)
	/source/gcc/gcc/tree-cfg.c:4736
0xc7fe6d gimplify_body(tree_node*, bool)
	/source/gcc/gcc/gimplify.c:9117
0xc802a7 gimplify_function_tree(tree_node*)
	/source/gcc/gcc/gimplify.c:9202
0xa2f3e0 cgraph_node::analyze()
	/source/gcc/gcc/cgraphunit.c:633
0xa306ba analyze_functions
	/source/gcc/gcc/cgraphunit.c:1023
0xa34a5f symbol_table::finalize_compilation_unit()
	/source/gcc/gcc/cgraphunit.c:2435
0x799173 cp_write_global_declarations()
	/source/gcc/gcc/cp/decl2.c:4754
Please submit a full bug report,

Finally, on a cross PPC with --enable-checking=release we get:

reynosa:/build/arm-linux-gnueabihf/gcc$ ./cc1plus ~/a.ii -quiet -std=c++11 -O2 -I./ 
/home/aldyh/a.ii: In member function ‘Maybe<ParsedSchema> ParsedSchema::findNested() const’:
/home/aldyh/a.ii:45:21: internal compiler error: Segmentation fault
 Maybe<ParsedSchema> ParsedSchema::findNested() const {
                     ^
0xd1b9a4 crash_signal
	/source/gcc/gcc/toplev.c:383
0xa40122 maybe_canonicalize_mem_ref_addr
	/source/gcc/gcc/gimple-fold.c:3504
0xa402c3 fold_stmt_1
	/source/gcc/gcc/gimple-fold.c:3556
0xa40e07 fold_stmt(gimple_stmt_iterator*, tree_node* (*)(tree_node*))
	/source/gcc/gcc/gimple-fold.c:3810
0xe438c7 execute
	/source/gcc/gcc/tree-ssa-forwprop.c:2347
Please submit a full bug report,

Odd indeed.  A little guidance would be appreciated, as I don't even know which one of the three is the correct path.
Comment 5 Aldy Hernandez 2015-03-04 23:19:27 UTC
Created attachment 34959 [details]
reduced testcase
Comment 6 Aldy Hernandez 2015-03-05 02:46:03 UTC
For the construction of the lambda in the simplified testcase I have just uploaded:

  MaybeInt().xmap([abc](int childId)
		  {
		    return ParsedSchema(bark, childId + 666);
		  });

We initially generate the following tree:

ParsedSchema::findNested()::<lambda(int)> (const struct __lambda0 * const __closure, int childId)
{
  const int abc [value-expr: __closure->__abc];

  <<cleanup_point return D.2331 = <<< Unknown tree: aggr_init_expr
  6
  __comp_ctor 
  *NON_LVALUE_EXPR <this>
  NON_LVALUE_EXPR <this>
  *NON_LVALUE_EXPR <this> = bark;, <<< Unknown tree: empty_class_expr >>>;
  childId + 666 >>>>>;
}

Whose AGGR_INIT_EXPR will be gimplified into:

ParsedSchema::findNested()::<lambda(int)> (const struct __lambda0 * const __closure, int childId)
{
  const int abc [value-expr: __closure->__abc];

  <<cleanup_point return D.2331 = ParsedSchema::ParsedSchema (&*NON_LVALUE_EXPR <this>, *NON_LVALUE_EXPR <this> = bark;, <<< Unknown tree: empty_class_expr >>>;, childId + 666)>>;
}

Notice the non-existent return value from ParsedSchema::ParsedSchema is being read from, and constructors do not return anything.  I suppose D.2331 should be set from NON_LVALUE_EXPR<this>, although even the assignment into *NON_LVALUE_EXPR looks odd.  Isn't a NON_LVALUE_EXPR by definition not assignable?

Before the patch that broke this, we had:

  <<cleanup_point return <retval> = TARGET_EXPR <D.2133, <<< Unknown tree: aggr_init_expr
  6
  __comp_ctor 
  D.2133
  (struct ParsedSchema *) 0
  TARGET_EXPR <D.2123, bark>;, <<< Unknown tree: empty_class_expr >>>;
  childId + 666 >>>>;, D.2133>>;

Notice the TARGET_EXPR, which then does the right thing when gimplified.
Comment 7 Aldy Hernandez 2015-03-06 22:44:31 UTC
Created attachment 34977 [details]
smaller and simpler testcase

In cp_simplify_init_expr(), we are lowering part of the return
statement for the lambda function from this:

*NON_LVALUE_EXPR <this> = TARGET_EXPR <D.2173, <<< Unknown tree: aggr_init_expr
  4
  __comp_ctor 
  D.2173
  NON_LVALUE_EXPR <this> >>>>;

into:

<<< Unknown tree: aggr_init_expr
  4
  __comp_ctor 
  *NON_LVALUE_EXPR <this>		<-- notice we've dropped D.2173
  NON_LVALUE_EXPR <this> >>>;

This last blob cannot be stored into retval because the value of the aggr_init_expr is a read from the constructor which has a void return type.
Comment 8 Aldy Hernandez 2015-03-09 20:36:25 UTC
Fixed on mainline by Jason's fix to PR c++/65339.  Thanks.

*** This bug has been marked as a duplicate of bug 65339 ***