I would think that when we see a duplicated base we should just drop
the duplicates and continue.

If the type of b1 is error_mark_node, why isn't the type of b2 also
error_mark_node?

Jason


On Thu, Jun 9, 2016 at 1:01 PM, Paolo Carlini <paolo.carl...@oracle.com> wrote:
> Hi again,
>
> thus today I had to revert my first try at resolving this error recovery
> issue because it caused c++/71465. In retrospect it was a bit heavy handed
> anyway, the zeroing of the type served us well for many years...
>
> Today I tried to investigate the issue a bit more. I remind you that we are
> crashing on the gcc_unreachable () at the end of build_simple_base_path
> while, during error recovery, we are processing the initialization of the
> final 'a' in:
>
> class A
> {
>   virtual void foo () { }
> };
> class B : public A, A { };  // { dg-error "duplicate base type" }
>
> B b1, &b2 = b1;
> A a = b2;
>
> Now the first comment I have about this, about which I'd like to have some
> feedback, is that the gcc_unreachable () at the end of
> build_simple_base_path without a return seems a bit weird to me, because the
> function is *supposed to return a tree*, not void. I guess some front-ends
> would even warn on this?!? Anyway, if we change:
>
>
>     /* */
>
>     gcc_unreachable ();
> }
>
> to:
>
>     /* */
>
>     gcc_assert (seen_error ());
>     return error_mark_node;
> }
>
> we get something which, by and large is equally safe in terms of
> miscompilations and helps a lot error recovery, ie, we would not have
> c++/70202. It's also true however that we would not make much progress in
> trying to understand if we could solve the specific problem at issue in a
> more insightful way.
>
> Then my next observation is the following: if we change the testcase to:
>
> class A
> {
>   virtual void foo () { }
> };
> class B : public A, A { };  // { dg-error "duplicate base type" }
>
> B b1, &b2 = b1;
> A a = b1;
>
> thus everything is the same but at the end we have 'b1', not 'b2', we also
> don't crash. We are saved not by something particularly smart ;) but by this
> check at the beginning of ocp_convert:
>
>   if (error_operand_p (e) || type == error_mark_node)
>      return error_mark_node;
>
> that is, the TREE_TYPE of 'e', the VAR_DECL for 'b1', is error_mark_node and
> we return early the error_mark_node, we don't reach the problematic
> build_base_path. With 'b2' we have a more complicated REFERENCE_REF which we
> don't catch, but otherwise everything is the same, we reach build_base_path
> and we crash on the gcc_unreachable. In practice, if I add at the beginning
> of ocp_convert:
>
> +  if (REFERENCE_REF_P (expr)
> +      && VAR_P (TREE_OPERAND (expr, 0))
> +      && DECL_INITIAL (TREE_OPERAND (expr, 0)) == error_mark_node)
> +    return error_mark_node;
>
> it also passes testing. Then the final observation is that we also don't
> crash if the type of 'A' is simpler, thus we don't have the declaration of
>
>     virtual void foo () { }
>
> Then I gather that when the type is "complex" enough we are not cleaning
> things up completely enough when we encounter it as a duplicated base. Maybe
> as optimal error recovery when we see a duplicated base we should clean up
> everything having to do with bases end up with something equivalent to an
> incomplete class B; or something like that?!? I don't know what we want to
> try short / medium /long term...
>
> Thanks!
> Paolo.
>
>

Reply via email to