[clang] [clang] Fix static_cast bypassing access control (PR #132285)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Mar 20 14:02:22 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: None (offsetof)
<details>
<summary>Changes</summary>
Fix access and ambiguity checks not being performed when converting to an rvalue reference to a base class type with `static_cast`.
Fixes #<!-- -->121429
---
Full diff: https://github.com/llvm/llvm-project/pull/132285.diff
3 Files Affected:
- (modified) clang/docs/ReleaseNotes.rst (+1)
- (modified) clang/lib/Sema/SemaCast.cpp (+11-13)
- (modified) clang/test/CXX/expr/expr.post/expr.static.cast/p3-0x.cpp (+64-1)
``````````diff
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>();
``````````
</details>
https://github.com/llvm/llvm-project/pull/132285
More information about the cfe-commits
mailing list