Skip to content

Commit ac82e33

Browse files
committed
[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`.
1 parent 5151e6d commit ac82e33

File tree

3 files changed

+76
-14
lines changed

3 files changed

+76
-14
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,7 @@ Bug Fixes to C++ Support
357357
- Fixed a Clang regression in C++20 mode where unresolved dependent call expressions were created inside non-dependent contexts (#GH122892)
358358
- Clang now emits the ``-Wunused-variable`` warning when some structured bindings are unused
359359
and the ``[[maybe_unused]]`` attribute is not applied. (#GH125810)
360+
- Fixed ``static_cast`` not performing access or ambiguity checks when converting to an rvalue reference to a base class. (#GH121429)
360361

361362
Bug Fixes to AST Handling
362363
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/lib/Sema/SemaCast.cpp

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ static void DiagnoseCastQual(Sema &Self, const ExprResult &SrcExpr,
221221
// %2: Destination Type
222222
static TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr,
223223
QualType DestType, bool CStyle,
224-
CastKind &Kind,
224+
SourceRange OpRange, CastKind &Kind,
225225
CXXCastPath &BasePath,
226226
unsigned &msg);
227227
static TryCastResult TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr,
@@ -1357,8 +1357,8 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
13571357
// C++11 [expr.static.cast]p3:
13581358
// A glvalue of type "cv1 T1" can be cast to type "rvalue reference to cv2
13591359
// T2" if "cv2 T2" is reference-compatible with "cv1 T1".
1360-
tcr = TryLValueToRValueCast(Self, SrcExpr.get(), DestType, CStyle, Kind,
1361-
BasePath, msg);
1360+
tcr = TryLValueToRValueCast(Self, SrcExpr.get(), DestType, CStyle, OpRange,
1361+
Kind, BasePath, msg);
13621362
if (tcr != TC_NotApplicable)
13631363
return tcr;
13641364

@@ -1534,8 +1534,8 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
15341534
/// Tests whether a conversion according to N2844 is valid.
15351535
TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr,
15361536
QualType DestType, bool CStyle,
1537-
CastKind &Kind, CXXCastPath &BasePath,
1538-
unsigned &msg) {
1537+
SourceRange OpRange, CastKind &Kind,
1538+
CXXCastPath &BasePath, unsigned &msg) {
15391539
// C++11 [expr.static.cast]p3:
15401540
// A glvalue of type "cv1 T1" can be cast to type "rvalue reference to
15411541
// cv2 T2" if "cv2 T2" is reference-compatible with "cv1 T1".
@@ -1548,7 +1548,6 @@ TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr,
15481548

15491549
// Because we try the reference downcast before this function, from now on
15501550
// this is the only cast possibility, so we issue an error if we fail now.
1551-
// FIXME: Should allow casting away constness if CStyle.
15521551
QualType FromType = SrcExpr->getType();
15531552
QualType ToType = R->getPointeeType();
15541553
if (CStyle) {
@@ -1572,13 +1571,12 @@ TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr,
15721571

15731572
if (RefConv & Sema::ReferenceConversions::DerivedToBase) {
15741573
Kind = CK_DerivedToBase;
1575-
CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
1576-
/*DetectVirtual=*/true);
1577-
if (!Self.IsDerivedFrom(SrcExpr->getBeginLoc(), SrcExpr->getType(),
1578-
R->getPointeeType(), Paths))
1579-
return TC_NotApplicable;
1580-
1581-
Self.BuildBasePathArray(Paths, BasePath);
1574+
if (Self.CheckDerivedToBaseConversion(FromType, ToType,
1575+
SrcExpr->getBeginLoc(), OpRange,
1576+
&BasePath, CStyle)) {
1577+
msg = 0;
1578+
return TC_Failed;
1579+
}
15821580
} else
15831581
Kind = CK_NoOp;
15841582

clang/test/CXX/expr/expr.post/expr.static.cast/p3-0x.cpp

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
2-
// expected-no-diagnostics
32

43
// A glvalue of type "cv1 T1" can be cast to type "rvalue reference to
54
// cv2 T2" if "cv2 T2" is reference-compatible with "cv1 T1" (8.5.3).
@@ -23,3 +22,67 @@ void test(A &a, B &b) {
2322
const A &&ar10 = static_cast<const A&&>(xvalue<A>());
2423
const A &&ar11 = static_cast<const A&&>(xvalue<B>());
2524
}
25+
26+
struct C : private A { // expected-note 4 {{declared private here}}
27+
C&& that();
28+
29+
void f() {
30+
(void)static_cast<A&&>(*this);
31+
(void)static_cast<const A&&>(*this);
32+
33+
(void)static_cast<A&&>(that());
34+
(void)static_cast<const A&&>(that());
35+
}
36+
};
37+
C c;
38+
const C cc;
39+
40+
void f() {
41+
static_cast<A&&>(c); // expected-error {{cannot cast 'C' to its private base class 'A'}}
42+
static_cast<A&&>(c.that()); // expected-error {{cannot cast 'C' to its private base class 'A'}}
43+
44+
static_cast<const A&&>(c); // expected-error {{cannot cast 'C' to its private base class 'const A'}}
45+
static_cast<const A&&>(c.that()); // expected-error {{cannot cast 'C' to its private base class 'const A'}}
46+
}
47+
48+
constexpr auto v = (
49+
(A&&)c,
50+
(A&&)(C&&)c,
51+
(A&&)cc,
52+
(A&&)(const C&&)c,
53+
(const A&&)c,
54+
(const A&&)(C&&)c,
55+
(const A&&)cc,
56+
(const A&&)(const C&&)c
57+
);
58+
59+
struct D : A, B { // expected-warning {{direct base 'A' is inaccessible due to ambiguity}}
60+
D&& rv();
61+
};
62+
D d;
63+
64+
void g(const D cd) {
65+
static_cast<A&&>(d); // expected-error {{ambiguous conversion from derived class 'D' to base class 'A'}}
66+
static_cast<A&&>(d.rv()); // expected-error {{ambiguous conversion from derived class 'D' to base class 'A'}}
67+
68+
static_cast<const A&&>(d); // expected-error {{ambiguous conversion from derived class 'D' to base class 'const A'}}
69+
static_cast<const A&&>(d.rv()); // expected-error {{ambiguous conversion from derived class 'D' to base class 'const A'}}
70+
71+
(A&&)d; // expected-error {{ambiguous conversion from derived class 'D' to base class 'A'}}
72+
(A&&)(D&&)d; // expected-error {{ambiguous conversion from derived class 'D' to base class 'A'}}
73+
(A&&)cd; // expected-error {{ambiguous conversion from derived class 'D' to base class 'A'}}
74+
(A&&)(const D&&)d; // expected-error {{ambiguous conversion from derived class 'D' to base class 'A'}}
75+
(const A&&)d; // expected-error {{ambiguous conversion from derived class 'D' to base class 'A'}}
76+
(const A&&)(D&&)d; // expected-error {{ambiguous conversion from derived class 'D' to base class 'A'}}
77+
(const A&&)cd; // expected-error {{ambiguous conversion from derived class 'D' to base class 'A'}}
78+
(const A&&)(const D&&)d; // expected-error {{ambiguous conversion from derived class 'D' to base class 'A'}}
79+
}
80+
81+
template<class T, class U>
82+
auto h(U u = {}) -> decltype(static_cast<T&&>(u));
83+
84+
template<class, class>
85+
int h();
86+
87+
int i = h<A, C>();
88+
int j = h<A, D>();

0 commit comments

Comments
 (0)