summaryrefslogtreecommitdiff
path: root/lib/Sema
diff options
context:
space:
mode:
authorReid Kleckner <rnk@google.com>2017-10-27 22:48:41 +0000
committerReid Kleckner <rnk@google.com>2017-10-27 22:48:41 +0000
commitc124c77b3b52e2d04aed181a426f1971cb1614e4 (patch)
tree6b10da22ed9fb1c352abf68507b2354c64568dcb /lib/Sema
parent0d8450b358fac348761b11924a92e8d269389cb1 (diff)
downloadclang-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.cpp55
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;
}