This is an archive of the discontinued LLVM Phabricator instance.

[AST] Refactor UnaryTransformType into TransformTraitType supporting non-unary transforms
Needs ReviewPublic

Authored by EricWF on Mar 31 2018, 6:05 PM.

Details

Summary

This patch refactors UnaryTransformType into TransformTraitType which accepts an arbitrary number of input arguments, which is needed to support upcoming traits such as __raw_invocation_type

Diff Detail

Event Timeline

EricWF created this revision.Mar 31 2018, 6:05 PM
rsmith added inline comments.Apr 4 2018, 7:23 PM
include/clang/AST/Type.h
3990

You can't store types with non-trivial destructors on AST nodes; the Type destructor will never run, so you'll leak. Instead, consider tail-allocating this list of QualTypes, or performing a separate allocation using the ASTContext slab allocator to hold the list if tail-allocation isn't feasible for some reason.

include/clang/Basic/DiagnosticCommonKinds.td
111–114

Hmm, do you need to touch this diagnostic in this change?

(If so, can you fix the second select to use %plural?)

include/clang/Basic/Specifiers.h
80 ↗(On Diff #140558)

Not sure what happened here, these whitespace changes look unrelated to your patch.

include/clang/Serialization/ASTBitCodes.h
1088

Please commit the whitespace changes in this file separately.

lib/AST/ASTDumper.cpp
1373

I prefer this as it was before ('s wrapping the thing they're quoting)...

lib/AST/ASTImporter.cpp
812

2 seems unnecessarily low here.

lib/AST/ASTStructuralEquivalence.cpp
512

This should presumably also check the kind...

lib/AST/ItaniumMangle.cpp
3250–3251

We need manglings to be self-delimiting, and we can't tell where the end of the argument list is with this mangling approach. :(

(Eg, f(__raw_invocation_type(T1, T2, T3)) and f(__raw_invocation_type(T1, T2), T3) would mangle the same with this mangling.)

Maybe drop an E on the end? (Or maybe do that only for traits that don't require exactly one argument, but that would create pain for demanglers....)

lib/AST/TypePrinter.cpp
954

This doesn't look right...

lib/Parse/ParseDeclCXX.cpp
1077–1087

This only works if none of the arguments are pack expansions.

lib/Sema/SemaTemplateDeduction.cpp
5367–5368

Marking the transformed type doesn't seem necessary. It can't possibly name template parameters (except via the inputs to the trait).

lib/Sema/SemaType.cpp
1508–1509

Try to avoid default: cases like this, as they suppress the warning notifying the user to update this switch when new traits are added.

8004–8013

Looks like you were half-way through factoring out the commonality between this and the parser's version?

8037–8038

You'll need to deal with the case that the arguments contain unexpanded packs here before assuming that ArgTypes.size() is meaningful.

lib/Sema/TreeTransform.h
625–627

I would drop the "Source" from this. We generally don't shorten "TypeSourceInfo" to "TypeSource", and it's clear enough to just say "Type" here I think. I'd also drop the "AndExpandPacks" because that's just a part of what it means to transform a list.

EricWF marked 10 inline comments as done.Apr 4 2018, 9:11 PM
EricWF added inline comments.
include/clang/AST/Type.h
3990

Ack. Tail-allocation seems tricky due to DependentTransformTraitType. I'll go ahead with using ASTContext::Allocate.

include/clang/Basic/DiagnosticCommonKinds.td
111–114

The changes aren't currently needed. I'll remove them for now.

include/clang/Serialization/ASTBitCodes.h
1088

Darn git clang-format being too aggressive.

lib/AST/ItaniumMangle.cpp
3250–3251

Makes sense. Thanks for the explanation. I'll go ahead and drop and E on the end.

However, will this cause ABI issues? Either with existing code or with GCC? If so, perhaps we should maintain the current mangling for __underlying_type.

lib/AST/TypePrinter.cpp
954

Woops, a funky merge + clang-format strike again!

lib/Sema/SemaType.cpp
1508–1509

Understood, but surely this is a case where default: is warranted. We're switching over a range of values much larger than TransformTraitType::TTKind in order to transform it into the TTKind

Do you have suggestions for improving it?

8004–8013

That was my goal, but I wasn't sure where it was appropriate to put this so it could be shared across components.

Any suggestions?

EricWF marked 4 inline comments as done.Apr 4 2018, 9:30 PM
EricWF added inline comments.
lib/Parse/ParseDeclCXX.cpp
1077–1087

Hmm. Interesting. The TypeTraitExpr parsing does the same thing.

Is the appropriate fix to delay the diagnostic until pack expansions have been expanded much later?

EricWF added inline comments.Apr 5 2018, 3:15 PM
lib/AST/ItaniumMangle.cpp
3250–3251

To answer my own question, GCC doesn't mangle __underlying_type yet. And I doubt that people are currently depending on the dependent mangling of __underlying_type. Perhaps I'm wrong about that last assumption though.

EricWF updated this revision to Diff 141293.Apr 6 2018, 1:29 AM
EricWF marked 2 inline comments as done.

Address all inline comments.

  • Dynamically allocate TransformTraitTypes list of argument types; making the node trivially destructible.
  • Detect and handle parameter packs when building TransformTraitType.
  • Factor out trait arity diagnostics between the parser and sema.
  • Rename TransformTypeSourceListAndExpandPacks as suggested.
  • Add a terminator character to the mangling to prevent ambiguity.
EricWF marked 12 inline comments as done.May 3 2018, 2:10 PM

Ping.

rsmith added inline comments.May 3 2018, 3:43 PM
include/clang/AST/TypeLoc.h
1992–1993

This assert doesn't make sense: the extra TypeSourceInfo*s are not stored after a TransformTraitTypeLoc. Rather, *TypeLoc is a non-owning veneer around separately-allocated data. ConcreteTypeLoc takes care of adding any necessary padding to get to the right alignment for you.

include/clang/ASTMatchers/ASTMatchers.h
5262–5266

Generally I think we want the primitive AST matchers to pretty directly correspond to the Clang AST. I think it would make sense to replace this matcher with a generalized transformTrait matcher -- but in a separate commit from this one. This is OK for now.

lib/AST/ASTContext.cpp
4630

You can just drop the function name (and hyphen) here; that's an obsolescent style.

lib/AST/ItaniumMangle.cpp
3250–3251

The existing U3eut mangling (with no terminating E) was approximately OK, following http://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangle.qualified-type. It would be better to use U17__underlying_type, though. This is not exactly right, since it treats __underlying_type as a type qualifier rather than a type function, but that's not too far off.

The new mangling doesn't match the Itanium ABI rule for vendor extensions. We basically have a choice between u <source-name> (which doesn't give us a good way to encode the arguments) or U <source-name> <template-args> <type> (which could work, but we'd need to make a somewhat-arbitrary choice of which type we consider to be the "main" type to which the qualifier applies).

We could arbitrarily say:

  • the first type in the trait is the "main" type
  • the rest of the trait is mangled as a qualifier
  • the qualifier is given template-args if and only if there is more than one argument

So:

  • __underlying_type(T) would mangle as U17__underlying_type1T (or approximately T __underlying_type)
  • __raw_invocation_type(F, A1, A2) would mangle as U21__raw_invocation_typeI2A12A2E1F (or approximately F __raw_invocation_type<A1, A2>)
  • __raw_invocation_type(F) would mangle as U21__raw_invocation_type1F (or approximately F __raw_invocation_type)

Or we could track here whether the trait can accept >1 argument, and always use the template-args formulation if so. I have no strong opinions either way.

Or we could suggest an Itanium ABI extension to permit <template-args> for the u... vendor extension type form, for vendor type traits. That'd lead to:

  • __underlying_type(T) would mangle as u17__underlying_typeI1TE (or approximately __underlying_type<T>)
  • __raw_invocation_type(F, A1, A2) would mangle as u21__raw_invocation_typeI1F2A12A2E (or approximately __raw_invocation_type<F, A1, A2>)
  • __raw_invocation_type(F) would mangle as u21__raw_invocation_typeI1FE (or approximately __raw_invocation_type<F>)

... and we could encourage demanglers to use parens instead of angles for those arguments.

The final of the above options seems best to me. What do you think?

lib/AST/Type.cpp
3081–3082

This should come from the transformed type, not the base type. (A transform trait could turn a dependent type into a non-depnedent type.)

3085–3086

Likewise, there's no reason to think that variably-modifiedness of the arguments has anything to do with variably-modifiedness of the transformed type. (Eg, __raw_invocation_type(Fn, VLAType) is not going to be a VLA type.)

3089

(And just for clarity: instantiation-dependence and contains-unexpanded-parameter-pack are concerned with the syntactic form of the type, not the semantics, so those two *should* be based on the corresponding properties of the arguments.)

lib/Lex/PPMacroExpansion.cpp
1245 ↗(On Diff #141293)

Remove this fixme too, please. (But let's hold off on this change until you land the __raw_invocation_type patch to keep this patch more focused.)

lib/Parse/ParseDeclCXX.cpp
1058

Call DS.SetTypeSpecError() here and at other points where you bail out of this function.

1073–1074

Instead of performing an ad-hoc arity check here, perform the check in the code that converts a kind + list of arguments into a TransformTraitType. That way there's no way to forget these checks and no side channel state to track about whether you've already done them.

lib/Sema/DeclSpec.cpp
373–380

This is going to be problematic down the line -- I expect there are going to be type transform traits that can produce function types. I think this strongly argues that we need to have already converted the trait into a QualType by the time we get here, rather than representing it as a trait kind and a list of types in the DeclSpec and deferring the conversion to later.

lib/Sema/SemaType.cpp
1508–1509

I think you should convert the trait to a QualType when you parse it, rather than waiting until now, which would make this moot.

8014–8022

Do you really need a PartialDiagnostic here? (Could you directly emit the diagnostic instead?)

8027–8029

I think this would be clearer if split into a function that computes and returns the result type of the trait and code to build the trait from that type, rather than this factored-out lambda approach -- this use of a lambda hides the fundamental behavior of this function, which is "first figure out the type and then build a trait producing that type".

8036

This doesn't seem right; you should delay if any of the arguments is dependent, but instantiation-dependent / containing a pack don't seem like they should matter here.

EricWF planned changes to this revision.May 3 2018, 10:14 PM
EricWF marked 7 inline comments as done.
EricWF added inline comments.
include/clang/ASTMatchers/ASTMatchers.h
5262–5266

I added a generalized transformTrait matcher, but forgot to declare it.

The reason for keeping the unaryTransformType was simply to avoid breaking existing code which already depends on it.
My plan was to possibly remove this wrapper later, after cleaning up usages in the LLVM code base.

lib/AST/Type.cpp
3089

Thanks for the clarification. I was about to ask.

lib/Sema/SemaType.cpp
1508–1509

Hmm. I'm not quite sure how/where to do that in the parser.

Are you suggesting calling BuildTransformTrait from inside ParseTransformTraitTypeSpecifier, and instead of building the DeclSpec containing the result of BuildTransformTrait instead of the list of argument type?

8014–8022

As it stands now, I believe I do, since the diagnostic needs to be emitted in both the parser and sema. If I'm not mistaken it would be incorrect to use Sema's diagnostic engine inside the parser and vice-versa.

However, if I delay the arity check until we're in SemaType as you suggested elsewhere, then the partial diagnostic is unneeded.

8036

We can't check the arity here as long as any of the arguments contain unexpanded parameter packs, so at least in that case we need to delay.

However, I'll change the isInstantationDependent check to isDependent.

EricWF marked 13 inline comments as done.Jul 3 2018, 3:14 PM
EricWF added inline comments.
lib/AST/ItaniumMangle.cpp
3250–3251

Or we could suggest an Itanium ABI extension to permit <template-args> for the u... vendor extension type form,
[...]
The final of the above options seems best to me. What do you think?

I think the final form would also be preferable. I'll go ahead and implement it.
What would it involve to suggest the Itanium ABI extension?

lib/Sema/DeclSpec.cpp
373–380

Ack. Done.

lib/Sema/SemaType.cpp
1508–1509

OK, I've got it all figured out. The requested change has been made.

EricWF updated this revision to Diff 154005.Jul 3 2018, 3:38 PM
EricWF marked 2 inline comments as done.

Address main review comments.

The TransformTraitType is now built early, and the DeclSpec refers to it and not the list of argument types.

Additionally, the mangling formulation u <source-name> [<template-args>] has been implemented as suggested, despite being non-standard. How do we suggest this extension to Itanium?

I believe this patch should be good to go.