Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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 @@ -895,6 +895,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)
- Declarations using class template argument deduction with redundant
parentheses around the declarator are no longer rejected. (#GH39811)
- Fixed a crash caused by invalid declarations of ``std::initializer_list``. (#GH132256)
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 @@ -263,7 +263,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
Expand Down Expand Up @@ -1425,8 +1425,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 @@ -1602,8 +1602,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 @@ -1616,7 +1616,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 @@ -1640,13 +1639,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
70 changes: 68 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,70 @@ void test(A &a, B &b) {
const A &&ar10 = static_cast<const A&&>(xvalue<A>());
const A &&ar11 = static_cast<const A&&>(xvalue<B>());
}

namespace GH121429 {

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}}

}
Loading