Index: include/clang/Basic/DiagnosticGroups.td =================================================================== --- include/clang/Basic/DiagnosticGroups.td +++ include/clang/Basic/DiagnosticGroups.td @@ -324,6 +324,7 @@ def Varargs : DiagGroup<"varargs">; def Unsequenced : DiagGroup<"unsequenced">; +def UnspecifiedInheritanceModel : DiagGroup<"ms-unspecified-inheritance-model">; // GCC name for -Wunsequenced def : DiagGroup<"sequence-point", [Unsequenced]>; Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -2510,6 +2510,12 @@ InGroup; def note_previous_ms_inheritance : Note< "previous inheritance model specified here">; +def warn_unspecified_ms_inheritance : Warning< + "incomplete classes use the 'full_generality' pointer-to-member " + "representation; a different translation unit may have chosen a different " + "representation">, + InGroup; +def note_ms_inheritance_selected : Note<"inheritance model selected here">; def err_machine_mode : Error<"%select{unknown|unsupported}0 machine mode %1">; def err_mode_not_primitive : Error< "mode attribute only supported for integer and floating-point types">; Index: lib/Sema/SemaType.cpp =================================================================== --- lib/Sema/SemaType.cpp +++ lib/Sema/SemaType.cpp @@ -5146,7 +5146,8 @@ } /// Locks in the inheritance model for the given class and all of its bases. -static void assignInheritanceModel(Sema &S, CXXRecordDecl *RD) { +static void assignInheritanceModel(Sema &S, CXXRecordDecl *RD, + SourceLocation Loc) { RD = RD->getMostRecentDecl(); if (!RD->hasAttr()) { MSInheritanceAttr::Spelling IM; @@ -5166,6 +5167,18 @@ break; } + // The user probably did not want the unspecified inheritance model in the + // best case. Diagnose this case so that the code could be reworked by + // providing a definition prior to the use of a pointer-to-member or via the + // use of inheritance keywords. + if (S.MSPointerToMemberRepresentationMethod == + LangOptions::PPTMK_BestCase && + IM == MSInheritanceAttr::Keyword_unspecified_inheritance) { + S.Diag(RD->getSourceRange().getBegin(), + diag::warn_unspecified_ms_inheritance); + S.Diag(Loc, diag::note_ms_inheritance_selected); + } + RD->addAttr(MSInheritanceAttr::CreateImplicit( S.getASTContext(), IM, /*BestCase=*/S.MSPointerToMemberRepresentationMethod == @@ -5180,7 +5193,7 @@ // form pointers to members of base classes without calling // RequireCompleteType on the pointer to member of the base class type. for (const CXXBaseSpecifier &BS : RD->bases()) - assignInheritanceModel(S, BS.getType()->getAsCXXRecordDecl()); + assignInheritanceModel(S, BS.getType()->getAsCXXRecordDecl(), Loc); } } @@ -5222,7 +5235,8 @@ if (const MemberPointerType *MPTy = T->getAs()) { if (!MPTy->getClass()->isDependentType()) { RequireCompleteType(Loc, QualType(MPTy->getClass(), 0), 0); - assignInheritanceModel(*this, MPTy->getMostRecentCXXRecordDecl()); + assignInheritanceModel(*this, MPTy->getMostRecentCXXRecordDecl(), + Loc); } } } Index: test/SemaCXX/member-pointer-ms.cpp =================================================================== --- test/SemaCXX/member-pointer-ms.cpp +++ test/SemaCXX/member-pointer-ms.cpp @@ -103,7 +103,13 @@ // An incomplete type with an unspecified inheritance model seems to take one // more slot than virtual. It's not clear what it's used for yet. class IncUnspecified; +#ifdef VMB +// expected-warning@-2 {{incomplete classes use the 'full_generality' pointer-to-member representation}} +#endif static_assert(sizeof(int IncUnspecified::*) == kUnspecifiedDataSize, ""); +#ifdef VMB +// expected-note@-2 {{inheritance model selected here}} +#endif static_assert(sizeof(void (IncUnspecified::*)()) == kUnspecifiedFunctionSize, ""); // complete types @@ -122,6 +128,9 @@ // Test both declared and defined templates. template class X; #ifdef VMB +// expected-warning@-2 {{incomplete classes use the 'full_generality' pointer-to-member representation}} +#endif +#ifdef VMB template <> class __single_inheritance X; template <> class __multiple_inheritance X; template <> class __virtual_inheritance X; @@ -135,6 +144,9 @@ static_assert(sizeof(int X::*) == kMultipleDataSize, ""); static_assert(sizeof(int X::*) == kVirtualDataSize, ""); static_assert(sizeof(int X::*) == kUnspecifiedDataSize, ""); +#ifdef VMB +// expected-note@-2 {{inheritance model selected here}} +#endif static_assert(sizeof(void (X::*)()) == kSingleFunctionSize, ""); static_assert(sizeof(void (X::*)()) == kMultipleFunctionSize, ""); static_assert(sizeof(void (X::*)()) == kVirtualFunctionSize, ""); @@ -167,11 +179,17 @@ // Re-declare to force us to iterate decls when adding attributes. struct ForwardDecl1; +#ifdef VMB +// expected-warning@-2 {{incomplete classes use the 'full_generality' pointer-to-member representation}} +#endif struct ForwardDecl2; typedef int ForwardDecl1::*MemPtr1; typedef int ForwardDecl2::*MemPtr2; MemPtr1 variable_forces_sizing; +#ifdef VMB +// expected-note@-2 {{inheritance model selected here}} +#endif struct ForwardDecl1 : B { virtual void foo(); @@ -208,12 +226,21 @@ template struct UnspecTemplate { static_assert(sizeof(int T::*) == kUnspecifiedDataSize, ""); +#ifdef VMB +// expected-note@-2 {{inheritance model selected here}} +#endif static_assert(sizeof(void (T::*)()) == kUnspecifiedFunctionSize, ""); }; struct NewUnspecified; +#ifdef VMB +// expected-warning@-2 {{incomplete classes use the 'full_generality' pointer-to-member representation}} +#endif SingleTemplate tmpl_single; UnspecTemplate tmpl_unspec; +#ifdef VMB +// expected-note@-2 {{in instantiation of template class}} +#endif struct NewUnspecified { };