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
Details
Diff Detail
Event Timeline
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. |
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? |
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? |
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. |
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.
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:
So:
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:
... 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. |
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. | |
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. |
lib/AST/ItaniumMangle.cpp | ||
---|---|---|
3250–3251 |
I think the final form would also be preferable. I'll go ahead and implement it. | |
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. |
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.
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.