Ping.

On Wed, Mar 09, 2016 at 04:55:23PM +0100, Marek Polacek wrote:
> On Wed, Mar 09, 2016 at 04:31:37PM +0100, Jakub Jelinek wrote:
> > No, I meant:
> >   switch (n)
> >     {
> >       struct S x;
> >     case 1:
> >       fn ();
> >       break;
> >     case 2:
> >       fn2 ();
> >       break;
> >     case 3:
> >       x = fn ();
> >       if (x.a[0] != 42)
> >     __builtin_abort ();
> >       break;
> >     case 4:
> >       if (fn ().a[0] != 42)
> >     __builtin_abort ();
> >       break;
> > ...
> > 
> > The reason is that anything after a noreturn call can be optimized away
> > shortly afterwards.  Perhaps you want __attribute__((noinline, noclone)) on
> > the function too just in case (I know you haven't included -O*).
>  
> Aha.  I couldn't do exactly this because of 
> error: switch jumps into scope of identifier with variably modified type
> so I moved the decl out of the switch.
> 
> > Otherwise LGTM.
> 
> Thanks.
> 
> Bootstrapped/regtested on x86_64-linux.
> 
> 2016-03-09  Marek Polacek  <pola...@redhat.com>
> 
>       PR c/70093
>       * c-typeck.c (build_function_call_vec): Create a TARGET_EXPR for
>       nested functions returning VM types.
> 
>       * cgraphunit.c (cgraph_node::expand_thunk): Also build call to the
>       function being thunked if the result type doesn't have fixed size.
>       * gimplify.c (gimplify_modify_expr): Also set LHS if the result type
>       doesn't have fixed size.
> 
>       * gcc.dg/nested-func-10.c: New test.
>       * gcc.dg/nested-func-9.c: New test.
> 
> diff --git gcc/c/c-typeck.c gcc/c/c-typeck.c
> index 6aa0f03..de9d465 100644
> --- gcc/c/c-typeck.c
> +++ gcc/c/c-typeck.c
> @@ -3068,6 +3068,16 @@ build_function_call_vec (location_t loc, 
> vec<location_t> arg_loc,
>      result = build_call_array_loc (loc, TREE_TYPE (fntype),
>                                  function, nargs, argarray);
>  
> +  /* In this improbable scenario, a nested function returns a VM type.
> +     Create a TARGET_EXPR so that the call always has a LHS, much as
> +     what the C++ FE does for functions returning non-PODs.  */
> +  if (variably_modified_type_p (TREE_TYPE (fntype), NULL_TREE))
> +    {
> +      tree tmp = create_tmp_var_raw (TREE_TYPE (fntype));
> +      result = build4 (TARGET_EXPR, TREE_TYPE (fntype), tmp, result,
> +                    NULL_TREE, NULL_TREE);
> +    }
> +
>    if (VOID_TYPE_P (TREE_TYPE (result)))
>      {
>        if (TYPE_QUALS (TREE_TYPE (result)) != TYPE_UNQUALIFIED)
> diff --git gcc/cgraphunit.c gcc/cgraphunit.c
> index 8b3fddc..4351ae4 100644
> --- gcc/cgraphunit.c
> +++ gcc/cgraphunit.c
> @@ -1708,7 +1708,9 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool 
> force_gimple_thunk)
>  
>        /* Build call to the function being thunked.  */
>        if (!VOID_TYPE_P (restype)
> -       && (!alias_is_noreturn || TREE_ADDRESSABLE (restype)))
> +       && (!alias_is_noreturn
> +           || TREE_ADDRESSABLE (restype)
> +           || TREE_CODE (TYPE_SIZE_UNIT (restype)) != INTEGER_CST))
>       {
>         if (DECL_BY_REFERENCE (resdecl))
>           {
> diff --git gcc/gimplify.c gcc/gimplify.c
> index b331e41..692d168 100644
> --- gcc/gimplify.c
> +++ gcc/gimplify.c
> @@ -4838,7 +4838,8 @@ gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, 
> gimple_seq *post_p,
>       }
>        notice_special_calls (call_stmt);
>        if (!gimple_call_noreturn_p (call_stmt)
> -       || TREE_ADDRESSABLE (TREE_TYPE (*to_p)))
> +       || TREE_ADDRESSABLE (TREE_TYPE (*to_p))
> +       || TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (*to_p))) != INTEGER_CST)
>       gimple_call_set_lhs (call_stmt, *to_p);
>        assign = call_stmt;
>      }
> diff --git gcc/testsuite/gcc.dg/nested-func-10.c 
> gcc/testsuite/gcc.dg/nested-func-10.c
> index e69de29..ac6f76f 100644
> --- gcc/testsuite/gcc.dg/nested-func-10.c
> +++ gcc/testsuite/gcc.dg/nested-func-10.c
> @@ -0,0 +1,56 @@
> +/* PR c/70093 */
> +/* { dg-do compile } */
> +/* { dg-options "" } */
> +
> +void __attribute__((noinline, noclone))
> +foo (int n)
> +{
> +  struct S { int a[n]; };
> +
> +  struct S __attribute__((noreturn))
> +  fn (void)
> +  {
> +    __builtin_abort ();
> +  }
> +
> +  auto struct S __attribute__((noreturn))
> +  fn2 (void)
> +  {
> +    __builtin_abort ();
> +  }
> +
> +  struct S x;
> +  __typeof__ (fn ()) *p = &x;
> +  switch (n)
> +    {
> +    case 1:
> +      fn ();
> +      break;
> +    case 2:
> +      fn2 ();
> +      break;
> +    case 3:
> +      x = fn ();
> +      if (x.a[0] != 42)
> +     __builtin_abort ();
> +      break;
> +    case 4:
> +      if (fn ().a[0] != 42)
> +     __builtin_abort ();
> +      break;
> +    case 5:
> +      if (p->a[0] != 42)
> +     __builtin_abort ();
> +      break;
> +    case 6:
> +      if (fn2 ().a[0] != 42)
> +     __builtin_abort ();
> +      break;
> +    }
> +}
> +
> +int
> +main (void)
> +{
> +  foo (1);
> +}
> diff --git gcc/testsuite/gcc.dg/nested-func-9.c 
> gcc/testsuite/gcc.dg/nested-func-9.c
> index e69de29..902c258 100644
> --- gcc/testsuite/gcc.dg/nested-func-9.c
> +++ gcc/testsuite/gcc.dg/nested-func-9.c
> @@ -0,0 +1,47 @@
> +/* PR c/70093 */
> +/* { dg-do run } */
> +/* { dg-options "" } */
> +
> +void
> +foo (int n)
> +{
> +  struct S { int a[n]; };
> +
> +  struct S
> +  fn (void)
> +  {
> +    struct S s;
> +    s.a[0] = 42;
> +    return s;
> +  }
> +
> +  auto struct S
> +  fn2 (void)
> +  {
> +    return fn ();
> +  }
> +
> +  struct S x;
> +  fn ();
> +  fn2 ();
> +  x = fn ();
> +
> +  if (x.a[0] != 42)
> +    __builtin_abort ();
> +
> +  if (fn ().a[0] != 42)
> +    __builtin_abort ();
> +
> +  __typeof__ (fn ()) *p = &x;
> +  if (p->a[0] != 42)
> +    __builtin_abort ();
> +
> +  if (fn2 ().a[0] != 42)
> +    __builtin_abort ();
> +}
> +
> +int
> +main (void)
> +{
> +  foo (1);
> +}
> 
>       Marek

        Marek

Reply via email to