From 0627f978bc7792adb1152dce6df75386bb9e5ecc Mon Sep 17 00:00:00 2001 From: Rose Hudson Date: Thu, 13 Nov 2025 10:51:30 +0000 Subject: [PATCH] [Clang][Sema] properly remove qualifiers in __is_pointer_interconvertible_base_of getCanonicalTypeUnqualified() doesn't actually remove cv qualifiers if the type is a SubstTemplateTypeParmType. Use getUnqualifiedType() instead, which does. Fixes: #135273 --- clang/lib/Sema/SemaChecking.cpp | 4 ++-- ...ointer-interconvertible-template-param.cpp | 22 +++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 clang/test/Sema/pointer-interconvertible-template-param.cpp diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index a8e3fe6c07b12..73473f1878ed1 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -15607,8 +15607,8 @@ bool Sema::IsLayoutCompatible(QualType T1, QualType T2) const { bool Sema::IsPointerInterconvertibleBaseOf(const TypeSourceInfo *Base, const TypeSourceInfo *Derived) { - QualType BaseT = Base->getType()->getCanonicalTypeUnqualified(); - QualType DerivedT = Derived->getType()->getCanonicalTypeUnqualified(); + QualType BaseT = Base->getType().getUnqualifiedType(); + QualType DerivedT = Derived->getType().getUnqualifiedType(); if (BaseT->isStructureOrClassType() && DerivedT->isStructureOrClassType() && getASTContext().hasSameType(BaseT, DerivedT)) diff --git a/clang/test/Sema/pointer-interconvertible-template-param.cpp b/clang/test/Sema/pointer-interconvertible-template-param.cpp new file mode 100644 index 0000000000000..174ac9a44a639 --- /dev/null +++ b/clang/test/Sema/pointer-interconvertible-template-param.cpp @@ -0,0 +1,22 @@ +// RUN: %clangxx %s -o %t +// RUN: %t | FileCheck %s + +#include + +class A {}; +class B : public A {}; + +template +inline constexpr bool is_pointer_interconvertible_base_of_v = __is_pointer_interconvertible_base_of(_Base, _Derived); + +int main() { + // CHECK: 1 + std::cout << __is_pointer_interconvertible_base_of(const A, A) << std::endl; + // CHECK-NEXT: 1 + std::cout << is_pointer_interconvertible_base_of_v << std::endl; + + // CHECK-NEXT: 1 + std::cout << __is_pointer_interconvertible_base_of(const A, B) << std::endl; + // CHECK-NEXT: 1 + std::cout << is_pointer_interconvertible_base_of_v << std::endl; +}