This is an archive of the discontinued LLVM Phabricator instance.

[GH54588]Fix ItaniumMangler for NTTP unnamed unions w/ unnamed structs
ClosedPublic

Authored by erichkeane on Mar 31 2022, 7:43 AM.

Details

Summary

As reported in https://github.com/llvm/llvm-project/issues/54588
and discussed in https://github.com/itanium-cxx-abi/cxx-abi/issues/139

We are supposed to do a DFS, pre-order, decl-order search for a name for
the union in this case. Prevoiusly we crashed because the IdentiferInfo
pointer was nullptr, so this makes sure we have a name in the cases
described by the ABI.

I added an llvm-unreachable to cover an unexpected case at the end of
the new function with information/reference to the ABI in case we come
up with some way to get back to here.

Diff Detail

Event Timeline

erichkeane created this revision.Mar 31 2022, 7:43 AM
Herald added a project: Restricted Project. · View Herald TranscriptMar 31 2022, 7:43 AM
erichkeane requested review of this revision.Mar 31 2022, 7:43 AM

Unfortunately, this initialization case does allow a situation where

clang/lib/AST/ItaniumMangle.cpp
5561

Alas, bit-fields are also allowed to be anonymous.

5576

Unfortunately, I think class value mangling has a counter-example to this: you can have an anonymous struct or union which doesn't declare any named members but will of course nonetheless show up in the list of members in the enclosing class. Code can even give it a non-zero initializer using list-initialization; that value can never be read, but it's there, and presumably it's part of uniquely determining a different template argument value and therefore needs to be mangled.

I don't know what we should do about this in the ABI, but we shouldn't crash in the compiler.

erichkeane added inline comments.Mar 31 2022, 12:13 PM
clang/lib/AST/ItaniumMangle.cpp
5561

Ah, good point, i'll update the comment and add a test.

5576

I'm not really understanding what you mean? Can you provide an example? All of the cases I could come up with like this ended up getting caught by the 'zero -init' case.

That said, I considered this 'unreachable' to be a distinct improvement over our current behavior which is to crash at effectively line 5558.

Would you prefer some sort of 'fatal-error' emit here?

Handle the unnamed bitfield case.

I'm still not sure how to reproduce the 'unreachable' example I added that @rjmccall suggested was possible, nor how we can deal with that, so waiting on his feedback for how he thinks we should handle that case.

Presumably I could replace it with a 'don't know how to handle that yet' fatal error like we do in the MS Mangler?

rjmccall added inline comments.Mar 31 2022, 1:43 PM
clang/lib/AST/ItaniumMangle.cpp
5576

I think the test case would be something like:

struct A {
  union { unsigned: 10; };
  int x;
  constexpr A(int x) : x(x) {}
};

template <A a> void foo() {}
template void foo<A(5)>();

But also consider:

struct B {
  struct Nested {
    union { unsigned: 10; };
    int x;
  } nested;
  constexpr B(int x) : nested{5, x} {}
};

template <B b> void bar() {}
template void bar<B(10)>();
erichkeane updated this revision to Diff 419748.Apr 1 2022, 7:14 AM

Update to 'diag' instead of crash, as implied/requested by @rjmccall

clang/lib/AST/ItaniumMangle.cpp
5576

With my current patch, that first example mangles to:
@_Z3fooIXtl1ALNS0_Ut_EELi5EEEEvv (that is, it doesn't touch this crash). Unfortunately, that doesn't 'demangle' with llvm-cxxfilt.

For the 2nd example, i had to modify it to be:

struct B {
  struct Nested {
    union {
      unsigned : 10;
    };
    int x;
  } nested;
  constexpr B(int x) : nested{{}, x} {}
};
  
  
template <B b> void bar() {}
template void bar<B(10)>();

As you wrote it, we get the error:
temp.cpp:20:31: error: initializer for aggregate with no elements requires explicit braces

I tried putting a '5' in those brackets, and get:
temp.cpp:20:32: error: excess elements in union initializer

HOWEVER, I think it makes sense to have a Diag here rather than an llvm-unreachable, so I've done that instead.

rjmccall accepted this revision.Apr 1 2022, 11:27 AM
rjmccall added inline comments.
clang/lib/AST/ItaniumMangle.cpp
5576

Hmm, alright, works for me.

This revision is now accepted and ready to land.Apr 1 2022, 11:27 AM
This revision was landed with ongoing or failed builds.Apr 1 2022, 11:48 AM
This revision was automatically updated to reflect the committed changes.
Herald added a project: Restricted Project. · View Herald TranscriptApr 1 2022, 11:48 AM
thakis added a subscriber: thakis.Apr 1 2022, 4:29 PM

Looks like this breaks tests on macOS: http://45.33.8.238/macm1/31733/step_7.txt

Please take a look, and revert for now if it takes a while to fix.

Looks like this breaks tests on macOS: http://45.33.8.238/macm1/31733/step_7.txt

Please take a look, and revert for now if it takes a while to fix.

That is sad, it seems that llvm-cxxfilt isn't working right on some of the machines :/

thakis added a comment.Apr 4 2022, 6:50 AM

Looks like this breaks tests on macOS: http://45.33.8.238/macm1/31733/step_7.txt

Please take a look, and revert for now if it takes a while to fix.

That is sad, it seems that llvm-cxxfilt isn't working right on some of the machines :/

Oh hm, if it's due to the wrong llvm-cxxfilt being called, maybe we just need to update clang/test/lit.cfg.py to add llvm-cxxfilt to tools to make sure it uses the just-built one instead of the one on PATH (? not sure).

thakis added a comment.Apr 4 2022, 6:54 AM

Oh hm, if it's due to the wrong llvm-cxxfilt being called, maybe we just need to update clang/test/lit.cfg.py to add llvm-cxxfilt to tools to make sure it uses the just-built one instead of the one on PATH (? not sure).

Actually, I consistently saw this failing on all our mac bots, and as far as I can tell they _don't_ have llvm-cxxfilt on PATH. Maybe it's due to macOS prepending a _ by default and llvm-cxxfilt insisting on host underscoriness?

% out/gn/bin/llvm-cxxfilt _Z4funcPci
_Z4funcPci
% out/gn/bin/llvm-cxxfilt __Z4funcPcia
func(char*, int, signed char)

Yes, looks like it. Since you're always passing a linux triple (which doesn't add the extra underscore), I think it'll work if you pass -n to llvm-cxxfilt to force that mode:

% out/gn/bin/llvm-cxxfilt -n _Z4funcPcia
func(char*, int, signed char)

Oh hm, if it's due to the wrong llvm-cxxfilt being called, maybe we just need to update clang/test/lit.cfg.py to add llvm-cxxfilt to tools to make sure it uses the just-built one instead of the one on PATH (? not sure).

Actually, I consistently saw this failing on all our mac bots, and as far as I can tell they _don't_ have llvm-cxxfilt on PATH. Maybe it's due to macOS prepending a _ by default and llvm-cxxfilt insisting on host underscoriness?

% out/gn/bin/llvm-cxxfilt _Z4funcPci
_Z4funcPci
% out/gn/bin/llvm-cxxfilt __Z4funcPcia
func(char*, int, signed char)

Yes, looks like it. Since you're always passing a linux triple (which doesn't add the extra underscore), I think it'll work if you pass -n to llvm-cxxfilt to force that mode:

% out/gn/bin/llvm-cxxfilt -n _Z4funcPcia
func(char*, int, signed char)

Ah, great, thank you for looking into that! I already re-committed with the test line disabled and a FIXME(since we're testing the 'mangled' names already!), but I'll try a commit with this -n to re-enable the line to see if this fixes it (and be quick about reverting it myself if I see the errors come across.

Thank you again for your help!