https://github.com/offsetof updated https://github.com/llvm/llvm-project/pull/132285
>From ac82e33db6879a8657706129fb28f3565e1899ba Mon Sep 17 00:00:00 2001 From: offsetof <offse...@mailo.com> Date: Thu, 20 Mar 2025 20:54:58 +0000 Subject: [PATCH 1/2] [clang] Fix static_cast bypassing access control Fix access and ambiguity checks not being performed when converting to an rvalue reference to a base class type with `static_cast`. --- clang/docs/ReleaseNotes.rst | 1 + clang/lib/Sema/SemaCast.cpp | 24 ++++--- .../expr/expr.post/expr.static.cast/p3-0x.cpp | 65 ++++++++++++++++++- 3 files changed, 76 insertions(+), 14 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 159991e8db981..18dcedad810ae 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -357,6 +357,7 @@ Bug Fixes to C++ Support - Fixed a Clang regression in C++20 mode where unresolved dependent call expressions were created inside non-dependent contexts (#GH122892) - Clang now emits the ``-Wunused-variable`` warning when some structured bindings are unused and the ``[[maybe_unused]]`` attribute is not applied. (#GH125810) +- Fixed ``static_cast`` not performing access or ambiguity checks when converting to an rvalue reference to a base class. (#GH121429) Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp index 718f6bec34910..7d64b4e954e4a 100644 --- a/clang/lib/Sema/SemaCast.cpp +++ b/clang/lib/Sema/SemaCast.cpp @@ -221,7 +221,7 @@ static void DiagnoseCastQual(Sema &Self, const ExprResult &SrcExpr, // %2: Destination Type static TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType, bool CStyle, - CastKind &Kind, + SourceRange OpRange, CastKind &Kind, CXXCastPath &BasePath, unsigned &msg); static TryCastResult TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr, @@ -1357,8 +1357,8 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr, // C++11 [expr.static.cast]p3: // A glvalue of type "cv1 T1" can be cast to type "rvalue reference to cv2 // T2" if "cv2 T2" is reference-compatible with "cv1 T1". - tcr = TryLValueToRValueCast(Self, SrcExpr.get(), DestType, CStyle, Kind, - BasePath, msg); + tcr = TryLValueToRValueCast(Self, SrcExpr.get(), DestType, CStyle, OpRange, + Kind, BasePath, msg); if (tcr != TC_NotApplicable) return tcr; @@ -1534,8 +1534,8 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr, /// Tests whether a conversion according to N2844 is valid. TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType, bool CStyle, - CastKind &Kind, CXXCastPath &BasePath, - unsigned &msg) { + SourceRange OpRange, CastKind &Kind, + CXXCastPath &BasePath, unsigned &msg) { // C++11 [expr.static.cast]p3: // A glvalue of type "cv1 T1" can be cast to type "rvalue reference to // cv2 T2" if "cv2 T2" is reference-compatible with "cv1 T1". @@ -1548,7 +1548,6 @@ TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, // Because we try the reference downcast before this function, from now on // this is the only cast possibility, so we issue an error if we fail now. - // FIXME: Should allow casting away constness if CStyle. QualType FromType = SrcExpr->getType(); QualType ToType = R->getPointeeType(); if (CStyle) { @@ -1572,13 +1571,12 @@ TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, if (RefConv & Sema::ReferenceConversions::DerivedToBase) { Kind = CK_DerivedToBase; - CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, - /*DetectVirtual=*/true); - if (!Self.IsDerivedFrom(SrcExpr->getBeginLoc(), SrcExpr->getType(), - R->getPointeeType(), Paths)) - return TC_NotApplicable; - - Self.BuildBasePathArray(Paths, BasePath); + if (Self.CheckDerivedToBaseConversion(FromType, ToType, + SrcExpr->getBeginLoc(), OpRange, + &BasePath, CStyle)) { + msg = 0; + return TC_Failed; + } } else Kind = CK_NoOp; diff --git a/clang/test/CXX/expr/expr.post/expr.static.cast/p3-0x.cpp b/clang/test/CXX/expr/expr.post/expr.static.cast/p3-0x.cpp index 830ccda245baa..0f6968f00f8c1 100644 --- a/clang/test/CXX/expr/expr.post/expr.static.cast/p3-0x.cpp +++ b/clang/test/CXX/expr/expr.post/expr.static.cast/p3-0x.cpp @@ -1,5 +1,4 @@ // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s -// expected-no-diagnostics // A glvalue of type "cv1 T1" can be cast to type "rvalue reference to // cv2 T2" if "cv2 T2" is reference-compatible with "cv1 T1" (8.5.3). @@ -23,3 +22,67 @@ void test(A &a, B &b) { const A &&ar10 = static_cast<const A&&>(xvalue<A>()); const A &&ar11 = static_cast<const A&&>(xvalue<B>()); } + +struct C : private A { // expected-note 4 {{declared private here}} + C&& that(); + + void f() { + (void)static_cast<A&&>(*this); + (void)static_cast<const A&&>(*this); + + (void)static_cast<A&&>(that()); + (void)static_cast<const A&&>(that()); + } +}; +C c; +const C cc; + +void f() { + static_cast<A&&>(c); // expected-error {{cannot cast 'C' to its private base class 'A'}} + static_cast<A&&>(c.that()); // expected-error {{cannot cast 'C' to its private base class 'A'}} + + static_cast<const A&&>(c); // expected-error {{cannot cast 'C' to its private base class 'const A'}} + static_cast<const A&&>(c.that()); // expected-error {{cannot cast 'C' to its private base class 'const A'}} +} + +constexpr auto v = ( + (A&&)c, + (A&&)(C&&)c, + (A&&)cc, + (A&&)(const C&&)c, + (const A&&)c, + (const A&&)(C&&)c, + (const A&&)cc, + (const A&&)(const C&&)c +); + +struct D : A, B { // expected-warning {{direct base 'A' is inaccessible due to ambiguity}} + D&& rv(); +}; +D d; + +void g(const D cd) { + static_cast<A&&>(d); // expected-error {{ambiguous conversion from derived class 'D' to base class 'A'}} + static_cast<A&&>(d.rv()); // expected-error {{ambiguous conversion from derived class 'D' to base class 'A'}} + + static_cast<const A&&>(d); // expected-error {{ambiguous conversion from derived class 'D' to base class 'const A'}} + static_cast<const A&&>(d.rv()); // expected-error {{ambiguous conversion from derived class 'D' to base class 'const A'}} + + (A&&)d; // expected-error {{ambiguous conversion from derived class 'D' to base class 'A'}} + (A&&)(D&&)d; // expected-error {{ambiguous conversion from derived class 'D' to base class 'A'}} + (A&&)cd; // expected-error {{ambiguous conversion from derived class 'D' to base class 'A'}} + (A&&)(const D&&)d; // expected-error {{ambiguous conversion from derived class 'D' to base class 'A'}} + (const A&&)d; // expected-error {{ambiguous conversion from derived class 'D' to base class 'A'}} + (const A&&)(D&&)d; // expected-error {{ambiguous conversion from derived class 'D' to base class 'A'}} + (const A&&)cd; // expected-error {{ambiguous conversion from derived class 'D' to base class 'A'}} + (const A&&)(const D&&)d; // expected-error {{ambiguous conversion from derived class 'D' to base class 'A'}} +} + +template<class T, class U> +auto h(U u = {}) -> decltype(static_cast<T&&>(u)); + +template<class, class> +int h(); + +int i = h<A, C>(); +int j = h<A, D>(); >From 7b015dece6cab815c3245a0395879b35cebc43c4 Mon Sep 17 00:00:00 2001 From: offsetof <offse...@mailo.com> Date: Mon, 24 Mar 2025 16:12:40 +0000 Subject: [PATCH 2/2] fixup! [clang] Fix static_cast bypassing access control Update test --- .../expr/expr.post/expr.static.cast/p3-0x.cpp | 43 +++++++++---------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/clang/test/CXX/expr/expr.post/expr.static.cast/p3-0x.cpp b/clang/test/CXX/expr/expr.post/expr.static.cast/p3-0x.cpp index 0f6968f00f8c1..750741bd4dd97 100644 --- a/clang/test/CXX/expr/expr.post/expr.static.cast/p3-0x.cpp +++ b/clang/test/CXX/expr/expr.post/expr.static.cast/p3-0x.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++14 -Wno-unused-value -verify %s // A glvalue of type "cv1 T1" can be cast to type "rvalue reference to // cv2 T2" if "cv2 T2" is reference-compatible with "cv1 T1" (8.5.3). @@ -27,11 +27,11 @@ struct C : private A { // expected-note 4 {{declared private here}} C&& that(); void f() { - (void)static_cast<A&&>(*this); - (void)static_cast<const A&&>(*this); + static_cast<A&&>(*this); + static_cast<const A&&>(*this); - (void)static_cast<A&&>(that()); - (void)static_cast<const A&&>(that()); + static_cast<A&&>(that()); + static_cast<const A&&>(that()); } }; C c; @@ -45,23 +45,25 @@ void f() { static_cast<const A&&>(c.that()); // expected-error {{cannot cast 'C' to its private base class 'const A'}} } -constexpr auto v = ( - (A&&)c, - (A&&)(C&&)c, - (A&&)cc, - (A&&)(const C&&)c, - (const A&&)c, - (const A&&)(C&&)c, - (const A&&)cc, - (const A&&)(const C&&)c -); +constexpr bool g() { + (A&&)c; + (A&&)(C&&)c; + (A&&)cc; + (A&&)(const C&&)c; + (const A&&)c; + (const A&&)(C&&)c; + (const A&&)cc; + (const A&&)(const C&&)c; + return true; +} +static_assert(g(), ""); struct D : A, B { // expected-warning {{direct base 'A' is inaccessible due to ambiguity}} D&& rv(); }; D d; -void g(const D cd) { +void h(const D cd) { static_cast<A&&>(d); // expected-error {{ambiguous conversion from derived class 'D' to base class 'A'}} static_cast<A&&>(d.rv()); // expected-error {{ambiguous conversion from derived class 'D' to base class 'A'}} @@ -79,10 +81,7 @@ void g(const D cd) { } template<class T, class U> -auto h(U u = {}) -> decltype(static_cast<T&&>(u)); - -template<class, class> -int h(); +auto s(U u = {}) -> decltype(static_cast<T&&>(u)); // expected-note 2 {{substitution failure}} -int i = h<A, C>(); -int j = h<A, D>(); +int i = s<A, C>(); // expected-error {{no matching function}} +int j = s<A, D>(); // expected-error {{no matching function}} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits