Author: rnk Date: Fri Oct 27 15:48:41 2017 New Revision: 316807 URL: http://llvm.org/viewvc/llvm-project?rev=316807&view=rev Log: [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 Added: cfe/trunk/test/CodeGenCXX/microsoft-inaccessible-base.cpp Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/lib/Sema/SemaDeclCXX.cpp cfe/trunk/test/SemaCXX/accessible-base.cpp Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=316807&r1=316806&r2=316807&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticGroups.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td Fri Oct 27 15:48:41 2017 @@ -890,6 +890,7 @@ def MicrosoftVoidPseudoDtor : DiagGroup< def MicrosoftAnonTag : DiagGroup<"microsoft-anon-tag">; def MicrosoftCommentPaste : DiagGroup<"microsoft-comment-paste">; def MicrosoftEndOfFile : DiagGroup<"microsoft-end-of-file">; +def MicrosoftInaccessibleBase : DiagGroup<"microsoft-inaccessible-base">; // Aliases. def : DiagGroup<"msvc-include", [MicrosoftInclude]>; // -Wmsvc-include = -Wmicrosoft-include Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=316807&r1=316806&r2=316807&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Oct 27 15:48:41 2017 @@ -7565,6 +7565,9 @@ def err_ambiguous_derived_to_base_conv : def err_ambiguous_memptr_conv : Error< "ambiguous conversion from pointer to member of %select{base|derived}0 " "class %1 to pointer to member of %select{derived|base}0 class %2:%3">; +def ext_ms_ambiguous_direct_base : ExtWarn< + "accessing inaccessible direct base %0 of %1 is a Microsoft extension">, + InGroup<MicrosoftInaccessibleBase>; def err_memptr_conv_via_virtual : Error< "conversion from pointer to member of class %0 to pointer to member " Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=316807&r1=316806&r2=316807&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Fri Oct 27 15:48:41 2017 @@ -2503,13 +2503,8 @@ bool Sema::IsDerivedFrom(SourceLocation 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 CXXB 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(QualT "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; } Added: cfe/trunk/test/CodeGenCXX/microsoft-inaccessible-base.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-inaccessible-base.cpp?rev=316807&view=auto ============================================================================== --- cfe/trunk/test/CodeGenCXX/microsoft-inaccessible-base.cpp (added) +++ cfe/trunk/test/CodeGenCXX/microsoft-inaccessible-base.cpp Fri Oct 27 15:48:41 2017 @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -fms-compatibility -triple x86_64-windows-msvc %s -emit-llvm -o - | FileCheck %s + +// Make sure we choose the *direct* base path when doing these conversions. + +// CHECK: %struct.C = type { %struct.A, %struct.B } +// CHECK: %struct.D = type { %struct.B, %struct.A } + +struct A { int a; }; +struct B : A { int b; }; + +struct C : A, B { }; +extern "C" A *a_from_c(C *p) { return p; } +// CHECK-LABEL: define %struct.A* @a_from_c(%struct.C* %{{.*}}) +// CHECK: bitcast %struct.C* %{{.*}} to %struct.A* + +struct D : B, A { }; +extern "C" A *a_from_d(D *p) { return p; } +// CHECK-LABEL: define %struct.A* @a_from_d(%struct.D* %{{.*}}) +// CHECK: %[[p_i8:[^ ]*]] = bitcast %struct.D* %{{.*}} to i8* +// CHECK: getelementptr inbounds i8, i8* %[[p_i8]], i64 8 Modified: cfe/trunk/test/SemaCXX/accessible-base.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/accessible-base.cpp?rev=316807&r1=316806&r2=316807&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/accessible-base.cpp (original) +++ cfe/trunk/test/SemaCXX/accessible-base.cpp Fri Oct 27 15:48:41 2017 @@ -1,10 +1,11 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -DMS -fms-compatibility -Wmicrosoft-inaccessible-base -fsyntax-only -verify %s struct A { int a; }; -struct X1 : virtual A +struct X1 : virtual A {}; struct Y1 : X1, virtual A @@ -13,7 +14,7 @@ struct Y1 : X1, virtual A struct Y2 : X1, A // expected-warning{{direct base 'A' is inaccessible due to ambiguity:\n struct Y2 -> struct X1 -> struct A\n struct Y2 -> struct A}} {}; -struct X2 : A +struct X2 : A {}; struct Z1 : X2, virtual A // expected-warning{{direct base 'A' is inaccessible due to ambiguity:\n struct Z1 -> struct X2 -> struct A\n struct Z1 -> struct A}} @@ -21,3 +22,30 @@ struct Z1 : X2, virtual A // expected-wa struct Z2 : X2, A // expected-warning{{direct base 'A' is inaccessible due to ambiguity:\n struct Z2 -> struct X2 -> struct A\n struct Z2 -> struct A}} {}; + +A *y2_to_a(Y2 *p) { +#ifdef MS + // expected-warning@+4 {{accessing inaccessible direct base 'A' of 'Y2' is a Microsoft extension}} +#else + // expected-error@+2 {{ambiguous conversion}} +#endif + return p; +} + +A *z1_to_a(Z1 *p) { +#ifdef MS + // expected-warning@+4 {{accessing inaccessible direct base 'A' of 'Z1' is a Microsoft extension}} +#else + // expected-error@+2 {{ambiguous conversion}} +#endif + return p; +} + +A *z1_to_a(Z2 *p) { +#ifdef MS + // expected-warning@+4 {{accessing inaccessible direct base 'A' of 'Z2' is a Microsoft extension}} +#else + // expected-error@+2 {{ambiguous conversion}} +#endif + return p; +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits