[Clang] Fix missing vtable for dynamic_cast<FinalClass &>(*this) in a function template#207349
Conversation
… a function template This is a follow-up to llvm#202594, which fixed a pointer cast, but not a reference cast. Surprisingly, `CXXDynamicCastExpr::getType()` for a reference cast is a `RecordType` and not a `ReferenceType`. How this happens: In `Sema::BuildCXXNamedCast`, a `CastOperation Op` variable is constructed. The `CastOperation` constructor initializes `ResultType(destType.getNonLValueExprType(S.Context))` where `QualType::getNonLValueExprType` turns a `ReferenceType` into a `RecordType`. `Sema::BuildCXXNamedCast` then passes `Op.ResultType` to `CXXDynamicCastExpr::Create`.
This function isn't used for the fix now.
|
@llvm/pr-subscribers-clang Author: Piotr Fusik (pfusik) ChangesThis is a follow-up to #202594, which fixed a pointer cast, but not How this happens: Full diff: https://github.com/llvm/llvm-project/pull/207349.diff 4 Files Affected:
diff --git a/clang/include/clang/AST/TypeBase.h b/clang/include/clang/AST/TypeBase.h
index 3a801e2857b13..c9658775f0470 100644
--- a/clang/include/clang/AST/TypeBase.h
+++ b/clang/include/clang/AST/TypeBase.h
@@ -2950,7 +2950,7 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
///
/// If this is not a pointer or reference, or the type being pointed to does
/// not refer to a CXXRecordDecl, returns NULL.
- CXXRecordDecl *getPointeeCXXRecordDecl() const;
+ const CXXRecordDecl *getPointeeCXXRecordDecl() const;
/// Get the DeducedType whose type will be deduced for a variable with
/// an initializer of this type. This looks through declarators like pointer
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 19b85d0e0af69..42d148715bc40 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -1955,7 +1955,7 @@ const ObjCObjectPointerType *Type::getAsObjCInterfacePointerType() const {
return nullptr;
}
-CXXRecordDecl *Type::getPointeeCXXRecordDecl() const {
+const CXXRecordDecl *Type::getPointeeCXXRecordDecl() const {
QualType PointeeType;
if (const auto *PT = getAsCanonical<PointerType>())
PointeeType = PT->getPointeeType();
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index a77ea5fd3dfff..4ba9414cfcdad 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1891,7 +1891,10 @@ namespace {
ExprResult Ret = inherited::TransformCXXDynamicCastExpr(E);
if (Ret.isInvalid())
return Ret;
- auto *DestDecl = Ret.get()->getType()->getPointeeCXXRecordDecl();
+ QualType T = Ret.get()->getType();
+ if (const auto *PT = T->getAsCanonical<PointerType>())
+ T = PT->getPointeeType();
+ auto *DestDecl = T->getAsCXXRecordDecl();
if (DestDecl && DestDecl->isEffectivelyFinal())
getSema().MarkVTableUsed(Ret.get()->getExprLoc(), DestDecl);
return Ret;
diff --git a/clang/test/CodeGenCXX/dynamic-cast-exact.cpp b/clang/test/CodeGenCXX/dynamic-cast-exact.cpp
index 86a97f764e729..7bf701206f5a4 100644
--- a/clang/test/CodeGenCXX/dynamic-cast-exact.cpp
+++ b/clang/test/CodeGenCXX/dynamic-cast-exact.cpp
@@ -139,3 +139,17 @@ namespace GH198511 {
template<class T> B *A::cast() { return dynamic_cast<B*>(this); }
template B *A::cast<int>();
}
+
+namespace GH198511Ref {
+ // Ensure we mark the B vtable as used here, because we're going to emit a
+ // reference to it.
+ // CHECK: define {{.*}} @_ZN11GH198511Ref1BD0
+ struct B;
+ struct A {
+ virtual ~A() = default;
+ template<class T> B &cast();
+ };
+ struct B final : A { };
+ template<class T> B &A::cast() { return dynamic_cast<B&>(*this); }
+ template B &A::cast<int>();
+}
|
🐧 Linux x64 Test Results
✅ The build succeeded and all tests passed. |
🐧 Linux x64 Test Results
All executed tests passed, but another part of the build failed. Click on a failure below to see the details. compiler-rt/lib/tsan/dd/CMakeFiles/clang_rt.dd-x86_64.dir/dd_interceptors.cpp.oIf these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the |
… a function template (#207349) This is a follow-up to #202594, which fixed a pointer cast, but not a reference cast. Surprisingly, `CXXDynamicCastExpr::getType()` for a reference cast is a `RecordType` and not a `ReferenceType`. How this happens: In `Sema::BuildCXXNamedCast`, a `CastOperation Op` variable is constructed. The `CastOperation` constructor initializes `ResultType(destType.getNonLValueExprType(S.Context))` where `QualType::getNonLValueExprType` turns a `ReferenceType` into a `RecordType`. `Sema::BuildCXXNamedCast` then passes `Op.ResultType` to `CXXDynamicCastExpr::Create`.
This is a follow-up to #202594, which fixed a pointer cast, but not
a reference cast. Surprisingly,
CXXDynamicCastExpr::getType()for a reference cast is a
RecordTypeand not aReferenceType.How this happens:
In
Sema::BuildCXXNamedCast, aCastOperation Opvariable is constructed.The
CastOperationconstructor initializesResultType(destType.getNonLValueExprType(S.Context))where
QualType::getNonLValueExprTypeturns aReferenceTypeintoa
RecordType.Sema::BuildCXXNamedCastthen passesOp.ResultTypeto
CXXDynamicCastExpr::Create.