diff options
author | Reid Kleckner <rnk@google.com> | 2017-10-27 22:48:41 +0000 |
---|---|---|
committer | Reid Kleckner <rnk@google.com> | 2017-10-27 22:48:41 +0000 |
commit | c124c77b3b52e2d04aed181a426f1971cb1614e4 (patch) | |
tree | 6b10da22ed9fb1c352abf68507b2354c64568dcb /lib/Sema | |
parent | 0d8450b358fac348761b11924a92e8d269389cb1 (diff) | |
download | clang-c124c77b3b52e2d04aed181a426f1971cb1614e4.tar.gz |
[MS] Allow access to ambiguous, inaccessible direct bases
Summary:
Clang typically warns that in the following class hierarchy, 'A' is
inaccessible because there is no series of casts that the user can
write to access it unambiguously:
struct A { };
struct B : A { };
struct C : A, B { };
MSVC allows the user to convert from C* to A*, though, and we've
encountered this issue in the latest Windows SDK headers.
This patch allows this conversion when -fms-compatibility is set and
adds a warning for it under -Wmicrosoft-inaccessible-base.
Reviewers: rsmith
Subscribers: cfe-commits
Differential Revision: https://reviews.llvm.org/D39389
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316807 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 55 |
1 files changed, 38 insertions, 17 deletions
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 750e0623c5..fa9e9f3218 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -2503,13 +2503,8 @@ bool Sema::IsDerivedFrom(SourceLocation Loc, QualType Derived, QualType Base, return DerivedRD->isDerivedFrom(BaseRD, Paths); } -void Sema::BuildBasePathArray(const CXXBasePaths &Paths, - CXXCastPath &BasePathArray) { - assert(BasePathArray.empty() && "Base path array must be empty!"); - assert(Paths.isRecordingPaths() && "Must record paths!"); - - const CXXBasePath &Path = Paths.front(); - +static void BuildBasePathArray(const CXXBasePath &Path, + CXXCastPath &BasePathArray) { // We first go backward and check if we have a virtual base. // FIXME: It would be better if CXXBasePath had the base specifier for // the nearest virtual base. @@ -2526,6 +2521,13 @@ void Sema::BuildBasePathArray(const CXXBasePaths &Paths, BasePathArray.push_back(const_cast<CXXBaseSpecifier*>(Path[I].Base)); } + +void Sema::BuildBasePathArray(const CXXBasePaths &Paths, + CXXCastPath &BasePathArray) { + assert(BasePathArray.empty() && "Base path array must be empty!"); + assert(Paths.isRecordingPaths() && "Must record paths!"); + return ::BuildBasePathArray(Paths.front(), BasePathArray); +} /// CheckDerivedToBaseConversion - Check whether the Derived-to-Base /// conversion (where Derived and Base are class types) is /// well-formed, meaning that the conversion is unambiguous (and @@ -2557,23 +2559,42 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, "Can only be used with a derived-to-base conversion"); (void)DerivationOkay; - if (!Paths.isAmbiguous(Context.getCanonicalType(Base).getUnqualifiedType())) { + const CXXBasePath *Path = nullptr; + if (!Paths.isAmbiguous(Context.getCanonicalType(Base).getUnqualifiedType())) + Path = &Paths.front(); + + // For MSVC compatibility, check if Derived directly inherits from Base. Clang + // warns about this hierarchy under -Winaccessible-base, but MSVC allows the + // user to access such bases. + if (!Path && getLangOpts().MSVCCompat) { + for (const CXXBasePath &PossiblePath : Paths) { + if (PossiblePath.size() == 1) { + Path = &PossiblePath; + if (AmbigiousBaseConvID) + Diag(Loc, diag::ext_ms_ambiguous_direct_base) + << Base << Derived << Range; + break; + } + } + } + + if (Path) { if (!IgnoreAccess) { // Check that the base class can be accessed. - switch (CheckBaseClassAccess(Loc, Base, Derived, Paths.front(), - InaccessibleBaseID)) { - case AR_inaccessible: - return true; - case AR_accessible: - case AR_dependent: - case AR_delayed: - break; + switch ( + CheckBaseClassAccess(Loc, Base, Derived, *Path, InaccessibleBaseID)) { + case AR_inaccessible: + return true; + case AR_accessible: + case AR_dependent: + case AR_delayed: + break; } } // Build a base path if necessary. if (BasePath) - BuildBasePathArray(Paths, *BasePath); + ::BuildBasePathArray(*Path, *BasePath); return false; } |