Skip to content

Commit 6003c30

Browse files
authored
[clang] NFC: Unify implementations of CheckMemberPointerConversion (#131966)
This deduplicates the implementation of CheckMemberPointerConversion accross SemaCast and SemaOverload.
1 parent ead2724 commit 6003c30

File tree

5 files changed

+115
-133
lines changed

5 files changed

+115
-133
lines changed

clang/include/clang/Sema/Sema.h

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10057,15 +10057,24 @@ class Sema final : public SemaBase {
1005710057
bool InOverloadResolution,
1005810058
QualType &ConvertedType);
1005910059

10060+
enum class MemberPointerConversionResult {
10061+
Success,
10062+
DifferentPointee,
10063+
NotDerived,
10064+
Ambiguous,
10065+
Virtual,
10066+
Inaccessible
10067+
};
10068+
enum class MemberPointerConversionDirection : bool { Downcast, Upcast };
1006010069
/// CheckMemberPointerConversion - Check the member pointer conversion from
1006110070
/// the expression From to the type ToType. This routine checks for ambiguous
1006210071
/// or virtual or inaccessible base-to-derived member pointer conversions for
10063-
/// which IsMemberPointerConversion has already returned true. It returns true
10064-
/// and produces a diagnostic if there was an error, or returns false
10065-
/// otherwise.
10066-
bool CheckMemberPointerConversion(Expr *From, QualType ToType, CastKind &Kind,
10067-
CXXCastPath &BasePath,
10068-
bool IgnoreBaseAccess);
10072+
/// which IsMemberPointerConversion has already returned true. It produces a
10073+
// diagnostic if there was an error.
10074+
MemberPointerConversionResult CheckMemberPointerConversion(
10075+
QualType FromType, const MemberPointerType *ToPtrType, CastKind &Kind,
10076+
CXXCastPath &BasePath, SourceLocation CheckLoc, SourceRange OpRange,
10077+
bool IgnoreBaseAccess, MemberPointerConversionDirection Direction);
1006910078

1007010079
/// IsQualificationConversion - Determines whether the conversion from
1007110080
/// an rvalue of type FromType to ToType is a qualification conversion

clang/lib/Sema/SemaAccess.cpp

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1874,33 +1874,30 @@ Sema::AccessResult Sema::CheckAddressOfMemberAccess(Expr *OvlExpr,
18741874
}
18751875

18761876
Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc,
1877-
QualType Base,
1878-
QualType Derived,
1877+
QualType Base, QualType Derived,
18791878
const CXXBasePath &Path,
1880-
unsigned DiagID,
1881-
bool ForceCheck,
1879+
unsigned DiagID, bool ForceCheck,
18821880
bool ForceUnprivileged) {
18831881
if (!ForceCheck && !getLangOpts().AccessControl)
18841882
return AR_accessible;
18851883

18861884
if (Path.Access == AS_public)
18871885
return AR_accessible;
18881886

1889-
CXXRecordDecl *BaseD, *DerivedD;
1890-
BaseD = cast<CXXRecordDecl>(Base->castAs<RecordType>()->getDecl());
1891-
DerivedD = cast<CXXRecordDecl>(Derived->castAs<RecordType>()->getDecl());
1892-
1893-
AccessTarget Entity(Context, AccessTarget::Base, BaseD, DerivedD,
1894-
Path.Access);
1887+
AccessTarget Entity(Context, AccessTarget::Base, Base->getAsCXXRecordDecl(),
1888+
Derived->getAsCXXRecordDecl(), Path.Access);
18951889
if (DiagID)
18961890
Entity.setDiag(DiagID) << Derived << Base;
18971891

18981892
if (ForceUnprivileged) {
1899-
switch (CheckEffectiveAccess(*this, EffectiveContext(),
1900-
AccessLoc, Entity)) {
1901-
case ::AR_accessible: return Sema::AR_accessible;
1902-
case ::AR_inaccessible: return Sema::AR_inaccessible;
1903-
case ::AR_dependent: return Sema::AR_dependent;
1893+
switch (
1894+
CheckEffectiveAccess(*this, EffectiveContext(), AccessLoc, Entity)) {
1895+
case ::AR_accessible:
1896+
return Sema::AR_accessible;
1897+
case ::AR_inaccessible:
1898+
return Sema::AR_inaccessible;
1899+
case ::AR_dependent:
1900+
return Sema::AR_dependent;
19041901
}
19051902
llvm_unreachable("unexpected result from CheckEffectiveAccess");
19061903
}

clang/lib/Sema/SemaCast.cpp

Lines changed: 14 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1794,72 +1794,25 @@ TryStaticMemberPointerUpcast(Sema &Self, ExprResult &SrcExpr, QualType SrcType,
17941794
}
17951795
}
17961796

1797-
const MemberPointerType *SrcMemPtr = SrcType->getAs<MemberPointerType>();
1798-
if (!SrcMemPtr) {
1799-
msg = diag::err_bad_static_cast_member_pointer_nonmp;
1800-
return TC_NotApplicable;
1801-
}
1802-
1803-
// Lock down the inheritance model right now in MS ABI, whether or not the
1804-
// pointee types are the same.
1805-
if (Self.Context.getTargetInfo().getCXXABI().isMicrosoft()) {
1806-
(void)Self.isCompleteType(OpRange.getBegin(), SrcType);
1807-
(void)Self.isCompleteType(OpRange.getBegin(), DestType);
1808-
}
1809-
1810-
// T == T, modulo cv
1811-
if (!Self.Context.hasSameUnqualifiedType(SrcMemPtr->getPointeeType(),
1812-
DestMemPtr->getPointeeType()))
1813-
return TC_NotApplicable;
1814-
1815-
// B base of D
1816-
QualType SrcClass(SrcMemPtr->getClass(), 0);
1817-
QualType DestClass(DestMemPtr->getClass(), 0);
1818-
CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
1819-
/*DetectVirtual=*/true);
1820-
if (!Self.IsDerivedFrom(OpRange.getBegin(), SrcClass, DestClass, Paths))
1797+
switch (Self.CheckMemberPointerConversion(
1798+
SrcType, DestMemPtr, Kind, BasePath, OpRange.getBegin(), OpRange, CStyle,
1799+
Sema::MemberPointerConversionDirection::Upcast)) {
1800+
case Sema::MemberPointerConversionResult::Success:
1801+
if (Kind == CK_NullToMemberPointer) {
1802+
msg = diag::err_bad_static_cast_member_pointer_nonmp;
1803+
return TC_NotApplicable;
1804+
}
1805+
break;
1806+
case Sema::MemberPointerConversionResult::DifferentPointee:
1807+
case Sema::MemberPointerConversionResult::NotDerived:
18211808
return TC_NotApplicable;
1822-
1823-
// B is a base of D. But is it an allowed base? If not, it's a hard error.
1824-
if (Paths.isAmbiguous(Self.Context.getCanonicalType(DestClass))) {
1825-
Paths.clear();
1826-
Paths.setRecordingPaths(true);
1827-
bool StillOkay =
1828-
Self.IsDerivedFrom(OpRange.getBegin(), SrcClass, DestClass, Paths);
1829-
assert(StillOkay);
1830-
(void)StillOkay;
1831-
std::string PathDisplayStr = Self.getAmbiguousPathsDisplayString(Paths);
1832-
Self.Diag(OpRange.getBegin(), diag::err_ambiguous_memptr_conv)
1833-
<< 1 << SrcClass << DestClass << PathDisplayStr << OpRange;
1834-
msg = 0;
1835-
return TC_Failed;
1836-
}
1837-
1838-
if (const RecordType *VBase = Paths.getDetectedVirtual()) {
1839-
Self.Diag(OpRange.getBegin(), diag::err_memptr_conv_via_virtual)
1840-
<< SrcClass << DestClass << QualType(VBase, 0) << OpRange;
1809+
case Sema::MemberPointerConversionResult::Ambiguous:
1810+
case Sema::MemberPointerConversionResult::Virtual:
1811+
case Sema::MemberPointerConversionResult::Inaccessible:
18411812
msg = 0;
18421813
return TC_Failed;
18431814
}
18441815

1845-
if (!CStyle) {
1846-
switch (Self.CheckBaseClassAccess(OpRange.getBegin(),
1847-
DestClass, SrcClass,
1848-
Paths.front(),
1849-
diag::err_upcast_to_inaccessible_base)) {
1850-
case Sema::AR_accessible:
1851-
case Sema::AR_delayed:
1852-
case Sema::AR_dependent:
1853-
// Optimistically assume that the delayed and dependent cases
1854-
// will work out.
1855-
break;
1856-
1857-
case Sema::AR_inaccessible:
1858-
msg = 0;
1859-
return TC_Failed;
1860-
}
1861-
}
1862-
18631816
if (WasOverloadedFunction) {
18641817
// Resolve the address of the overloaded function again, this time
18651818
// allowing complaints if something goes wrong.
@@ -1878,9 +1831,6 @@ TryStaticMemberPointerUpcast(Sema &Self, ExprResult &SrcExpr, QualType SrcType,
18781831
return TC_Failed;
18791832
}
18801833
}
1881-
1882-
Self.BuildBasePathArray(Paths, BasePath);
1883-
Kind = CK_DerivedToBaseMemberPointer;
18841834
return TC_Success;
18851835
}
18861836

clang/lib/Sema/SemaExprCXX.cpp

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4666,18 +4666,29 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
46664666
case ICK_Pointer_Member: {
46674667
CastKind Kind;
46684668
CXXCastPath BasePath;
4669-
if (CheckMemberPointerConversion(From, ToType, Kind, BasePath, CStyle))
4669+
switch (CheckMemberPointerConversion(
4670+
From->getType(), ToType->castAs<MemberPointerType>(), Kind, BasePath,
4671+
From->getExprLoc(), From->getSourceRange(), CStyle,
4672+
MemberPointerConversionDirection::Downcast)) {
4673+
case MemberPointerConversionResult::Success:
4674+
assert(Kind != CK_NullToMemberPointer ||
4675+
From->isNullPointerConstant(Context,
4676+
Expr::NPC_ValueDependentIsNull) &&
4677+
"Expr must be null pointer constant!");
4678+
break;
4679+
case MemberPointerConversionResult::Inaccessible:
4680+
break;
4681+
case MemberPointerConversionResult::DifferentPointee:
4682+
llvm_unreachable("unexpected result");
4683+
case MemberPointerConversionResult::NotDerived:
4684+
llvm_unreachable("Should not have been called if derivation isn't OK.");
4685+
case MemberPointerConversionResult::Ambiguous:
4686+
case MemberPointerConversionResult::Virtual:
46704687
return ExprError();
4688+
}
46714689
if (CheckExceptionSpecCompatibility(From, ToType))
46724690
return ExprError();
46734691

4674-
// We may not have been able to figure out what this member pointer resolved
4675-
// to up until this exact point. Attempt to lock-in it's inheritance model.
4676-
if (Context.getTargetInfo().getCXXABI().isMicrosoft()) {
4677-
(void)isCompleteType(From->getExprLoc(), From->getType());
4678-
(void)isCompleteType(From->getExprLoc(), ToType);
4679-
}
4680-
46814692
From =
46824693
ImpCastExprToType(From, ToType, Kind, VK_PRValue, &BasePath, CCK).get();
46834694
break;

clang/lib/Sema/SemaOverload.cpp

Lines changed: 55 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -3548,64 +3548,79 @@ bool Sema::IsMemberPointerConversion(Expr *From, QualType FromType,
35483548
return false;
35493549
}
35503550

3551-
bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType,
3552-
CastKind &Kind,
3553-
CXXCastPath &BasePath,
3554-
bool IgnoreBaseAccess) {
3555-
QualType FromType = From->getType();
3551+
Sema::MemberPointerConversionResult Sema::CheckMemberPointerConversion(
3552+
QualType FromType, const MemberPointerType *ToPtrType, CastKind &Kind,
3553+
CXXCastPath &BasePath, SourceLocation CheckLoc, SourceRange OpRange,
3554+
bool IgnoreBaseAccess, MemberPointerConversionDirection Direction) {
35563555
const MemberPointerType *FromPtrType = FromType->getAs<MemberPointerType>();
35573556
if (!FromPtrType) {
35583557
// This must be a null pointer to member pointer conversion
3559-
assert(From->isNullPointerConstant(Context,
3560-
Expr::NPC_ValueDependentIsNull) &&
3561-
"Expr must be null pointer constant!");
35623558
Kind = CK_NullToMemberPointer;
3563-
return false;
3559+
return MemberPointerConversionResult::Success;
3560+
}
3561+
3562+
// Lock down the inheritance model right now in MS ABI, whether or not the
3563+
// pointee types are the same.
3564+
if (Context.getTargetInfo().getCXXABI().isMicrosoft()) {
3565+
(void)isCompleteType(CheckLoc, FromType);
3566+
(void)isCompleteType(CheckLoc, QualType(ToPtrType, 0));
35643567
}
35653568

3566-
const MemberPointerType *ToPtrType = ToType->getAs<MemberPointerType>();
3567-
assert(ToPtrType && "No member pointer cast has a target type "
3568-
"that is not a member pointer.");
3569+
// T == T, modulo cv
3570+
if (Direction == MemberPointerConversionDirection::Upcast &&
3571+
!Context.hasSameUnqualifiedType(FromPtrType->getPointeeType(),
3572+
ToPtrType->getPointeeType()))
3573+
return MemberPointerConversionResult::DifferentPointee;
35693574

3570-
QualType FromClass = QualType(FromPtrType->getClass(), 0);
3571-
QualType ToClass = QualType(ToPtrType->getClass(), 0);
3575+
QualType FromClass = QualType(FromPtrType->getClass(), 0),
3576+
ToClass = QualType(ToPtrType->getClass(), 0);
35723577

3573-
// FIXME: What about dependent types?
3574-
assert(FromClass->isRecordType() && "Pointer into non-class.");
3575-
assert(ToClass->isRecordType() && "Pointer into non-class.");
3578+
QualType Base = FromClass, Derived = ToClass;
3579+
if (Direction == MemberPointerConversionDirection::Upcast)
3580+
std::swap(Base, Derived);
35763581

35773582
CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
35783583
/*DetectVirtual=*/true);
3579-
bool DerivationOkay =
3580-
IsDerivedFrom(From->getBeginLoc(), ToClass, FromClass, Paths);
3581-
assert(DerivationOkay &&
3582-
"Should not have been called if derivation isn't OK.");
3583-
(void)DerivationOkay;
3584-
3585-
if (Paths.isAmbiguous(Context.getCanonicalType(FromClass).
3586-
getUnqualifiedType())) {
3587-
std::string PathDisplayStr = getAmbiguousPathsDisplayString(Paths);
3588-
Diag(From->getExprLoc(), diag::err_ambiguous_memptr_conv)
3589-
<< 0 << FromClass << ToClass << PathDisplayStr << From->getSourceRange();
3590-
return true;
3584+
if (!IsDerivedFrom(OpRange.getBegin(), Derived, Base, Paths))
3585+
return MemberPointerConversionResult::NotDerived;
3586+
3587+
if (Paths.isAmbiguous(Base->getCanonicalTypeUnqualified())) {
3588+
Diag(CheckLoc, diag::err_ambiguous_memptr_conv)
3589+
<< int(Direction) << FromClass << ToClass
3590+
<< getAmbiguousPathsDisplayString(Paths) << OpRange;
3591+
return MemberPointerConversionResult::Ambiguous;
35913592
}
35923593

35933594
if (const RecordType *VBase = Paths.getDetectedVirtual()) {
3594-
Diag(From->getExprLoc(), diag::err_memptr_conv_via_virtual)
3595-
<< FromClass << ToClass << QualType(VBase, 0)
3596-
<< From->getSourceRange();
3597-
return true;
3595+
Diag(CheckLoc, diag::err_memptr_conv_via_virtual)
3596+
<< FromClass << ToClass << QualType(VBase, 0) << OpRange;
3597+
return MemberPointerConversionResult::Virtual;
35983598
}
35993599

3600-
if (!IgnoreBaseAccess)
3601-
CheckBaseClassAccess(From->getExprLoc(), FromClass, ToClass,
3602-
Paths.front(),
3603-
diag::err_downcast_from_inaccessible_base);
3604-
36053600
// Must be a base to derived member conversion.
36063601
BuildBasePathArray(Paths, BasePath);
3607-
Kind = CK_BaseToDerivedMemberPointer;
3608-
return false;
3602+
Kind = Direction == MemberPointerConversionDirection::Upcast
3603+
? CK_DerivedToBaseMemberPointer
3604+
: CK_BaseToDerivedMemberPointer;
3605+
3606+
if (!IgnoreBaseAccess)
3607+
switch (CheckBaseClassAccess(
3608+
CheckLoc, Base, Derived, Paths.front(),
3609+
Direction == MemberPointerConversionDirection::Upcast
3610+
? diag::err_upcast_to_inaccessible_base
3611+
: diag::err_downcast_from_inaccessible_base)) {
3612+
case Sema::AR_accessible:
3613+
case Sema::AR_delayed:
3614+
case Sema::AR_dependent:
3615+
// Optimistically assume that the delayed and dependent cases
3616+
// will work out.
3617+
break;
3618+
3619+
case Sema::AR_inaccessible:
3620+
return MemberPointerConversionResult::Inaccessible;
3621+
}
3622+
3623+
return MemberPointerConversionResult::Success;
36093624
}
36103625

36113626
/// Determine whether the lifetime conversion between the two given

0 commit comments

Comments
 (0)