Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
24 changes: 11 additions & 13 deletions clang/lib/Sema/SemaCast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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".
Expand All @@ -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) {
Expand All @@ -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;

Expand Down
66 changes: 64 additions & 2 deletions clang/test/CXX/expr/expr.post/expr.static.cast/p3-0x.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
// expected-no-diagnostics
// 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).
Expand All @@ -23,3 +22,66 @@ 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() {
static_cast<A&&>(*this);
static_cast<const A&&>(*this);

static_cast<A&&>(that());
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 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 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'}}

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 s(U u = {}) -> decltype(static_cast<T&&>(u)); // expected-note 2 {{substitution failure}}

int i = s<A, C>(); // expected-error {{no matching function}}
int j = s<A, D>(); // expected-error {{no matching function}}