Details
- Reviewers
rsmith
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
Ugh, the hole goes deeper, because the Itanium ABI unambiguously follows the C++11 (instantiation-dependent) behavior.
Definitely need Richard's input here as I'm fairly sure this will break things as-is.
clang/test/CodeGenCXX/mangle-exprs.cpp | ||
---|---|---|
215 ↗ | (On Diff #290653) | Amusingly, both GCC and MSVC reject this valid code. GCC says: "sorry, unimplemented: mangling noexcept_expr" MSVC says: "'void test5::a(bool)': no function template defined that matches forced instantiation" |
clang/test/CodeGenCXX/mangle.cpp | ||
805 | GCC mangles this as _ZN6test341fIiEEvDTstDTplcvT__EcvS1__EEE, so we're breaking compat here :-\ And in fact we're just incorrect. https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling:
Here, instantiation-dependent *is* explicitly defined as "type-dependent or value-dependent or ...". And therefore these cases must not be "encoded directly", including the motivating case (decltype(N) where N is a typed constant whose initializer is value-dependent). We could consider not two but *three* types of decltypetypes:
This only works if it's OK for mangling to depend on non-canonical type details - I don't know whether this is the case. @rsmith - any hints here? | |
clang/test/SemaTemplate/dependent-expr.cpp | ||
132 | Took me a while to understand this, I think this is an improvement as we now diagnose when we see the template rather than when we see the instantiation. |
clang/test/CodeGenCXX/mangle.cpp | ||
---|---|---|
805 | Hmm, my naive reading of the mangle code matches what I described. The big comment in ItaniumMangle talks about related issues: https://github.com/llvm/llvm-project/blob/24238f09edb98b0f460aa41139874ae5d4e5cd8d/clang/lib/AST/ItaniumMangle.cpp#L2541-L2572 I don't really understand what's going on here, sorry. |
clang/test/CodeGenCXX/mangle-exprs.cpp | ||
---|---|---|
218 ↗ | (On Diff #290653) | As with the other case, the expression here is instantiation-dependent so should be mangled. |
clang/test/CodeGenCXX/mangle.cpp | ||
805 | Looks like we need the single-step-desugaring loop below the big comment you quoted to stop when it hits a decltype type. That's presumably where we step from the instantiation-dependent-but-not-type-dependent decltype node to its desugared type. | |
clang/test/SemaTemplate/dependent-expr.cpp | ||
132 | Right. We treat statement-expressions in a template as always being value- and instantiation-dependent, in part to match GCC and in part to avoid needing to define value- and instantiation-dependence for all statements and block-scope declarations, so decltype(statement expression) would have been a dependent type before. |
clang/test/CodeGenCXX/mangle.cpp | ||
---|---|---|
805 | Also... the FIXME from that comment will apply here too. Given: template<typename T> void f(decltype(sizeof(T)), decltype(sizeof(T))) {} template void f<int>(unsigned long, unsigned long); we currently (correctly, as far as I can see) use a substitution for the second parameter type, but with the change here, I don't think we will do so any more. We could fix that by deduplicating DecltypeTypes when they're instantiation dependent but not dependent; that's what we do for ConstantArrayType's size expression, for example. If we do that, we'll need to store the actual expression on the DecltypeTypeLoc, since we can't rely on the DecltypeType having the right expression any more (only an expression that's equivalent to it). |
address comments:
- don't break existing mangling tests
- deduplicate instantiation-dependent-but-not-type-dependent DecltypeType node (for name mangling substitution)
- fix the dependence bit of DecltypeType
clang/lib/AST/Type.cpp | ||
---|---|---|
3404–3408 | I think I must have missed to reset the dependent bit from the result of toTypeDependence. toTypeDependence will set the dependent bit if E is value-dependent, but it is wrong for decltype. | |
clang/test/CodeGenCXX/mangle.cpp | ||
805 | Thanks for the hints and explanations.
thanks for the example, yeah, the behavior was changed with the prior change of this patch.
It took me sometime to understand the whole piece here, but I'm afraid that I still don't fully understand the second part -- any reason why we can't rely on the underlying expression of DecltypeType when doing the deduplication? If we store the actual expression on DecltypeTypeLoc, how do we retrieve it in ASTContext::getDecltypeType(), I didn't find any connection between DecltypeTypeLoc and ASTContext::getDecltypeType. I updated the patch using the DecltypeTypeLoc to do the duplication, it passes the example you gave above, but it might be wrong. |
clang/include/clang/AST/Type.h | ||
---|---|---|
4478 | We shouldn't store the context here. To provide it to the Profile implementation, use a ContextualFoldingSet. | |
4499–4508 | Can we remove this class now? | |
clang/lib/AST/ASTContext.cpp | ||
5342–5347 | Maybe fold these two paragraphs together
| |
clang/test/CodeGenCXX/mangle.cpp | ||
805 | The problem with the patch as it now stands is that for a case such as: int x; template<typename T> void f(decltype(sizeof(T.f(x)))); template<typename T> void g(decltype(sizeof(T.f(x)))); ... there is only one reference to x reachable in the AST, on line #2. The expression containing the DeclRefExpr on line #3 was discarded entirely. So (for example) any tooling that's looking to find references to x will not find the one on line #3. The best way to fix this would be to store the Expr* for the actual expression in the DecltypeTypeLoc information. We'll also need to make sure that TreeTransform uses that Expr* rather than the one from the type when transforming a DecltypeType with source info. |
clang/include/clang/AST/Type.h | ||
---|---|---|
4499–4508 | yeah I think it is possible, but I would rather do it in a follow-up patch -- the current patch seems large enough. Added a FIXME. | |
clang/test/CodeGenCXX/mangle.cpp | ||
805 | Thanks, now I get it. I have updated this patch to implement what you suggested (storing the actual expression in DecltypeTypeLoc), it touches more files. Please take another look. |
Closing it as Richard has landed a better patch in https://github.com/llvm/llvm-project/commit/638867afd4bce4a2c56dea041299428af3727d61.
We shouldn't store the context here. To provide it to the Profile implementation, use a ContextualFoldingSet.