Hi rnk, rsmith,
A polymorphic class with a single base class uses a multiple inheritance
model, not a single inheritance model. However, a pointer-to-member
field may appear before we know that there are any virtual methods.
We will, wrongly, assign the class a single-inheritance
pointer-to-member representation. Later on, we will check to see what
representation it actually got and issue a diagnostic.
Downgrade this diagnostic to a warning *if* the selection of inheritance
model is implicit.
This fixes PR20464.
tl;dr
A derived class, a base class, a virtual method and a pointer-to-member
walk into a bar. The pointer-to-member ruins the experience for
everyone.
http://reviews.llvm.org/D4687
Files:
include/clang/Basic/DiagnosticGroups.td
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/Sema.h
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclAttr.cpp
test/SemaCXX/member-pointer-ms.cpp
Index: include/clang/Basic/DiagnosticGroups.td
===================================================================
--- include/clang/Basic/DiagnosticGroups.td
+++ include/clang/Basic/DiagnosticGroups.td
@@ -192,6 +192,7 @@
def IgnoredQualifiers : DiagGroup<"ignored-qualifiers">;
def : DiagGroup<"import">;
def IncompatibleMSStruct : DiagGroup<"incompatible-ms-struct">;
+def MSInheritanceModel : DiagGroup<"ms-inheritance-model">;
def IncompatiblePointerTypesDiscardsQualifiers
: DiagGroup<"incompatible-pointer-types-discards-qualifiers">;
def IncompatiblePointerTypes
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -2504,7 +2504,9 @@
def note_previous_attribute : Note<"previous attribute is here">;
def note_attribute : Note<"attribute is here">;
def err_mismatched_ms_inheritance : Error<
- "inheritance model does not match %select{definition|previous declaration}0">;
+ "inheritance model does not match %select{definition|previous declaration}0 (%select{single|multiple|virtual|most general}1 vs %select{single|multiple|virtual|most general}2)">;
+def warn_mismatched_ms_inheritance : Warning<
+ "calculated inheritance model does not match definition (%select{single|multiple|virtual|most general}0 vs %select{single|multiple|virtual|most general}1)">;
def warn_ignored_ms_inheritance : Warning<
"inheritance model ignored on %select{primary template|partial specialization}0">,
InGroup<IgnoredAttributes>;
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -2703,7 +2703,7 @@
SourceLocation *ArgLocation = nullptr);
bool checkMSInheritanceAttrOnDefinition(
CXXRecordDecl *RD, SourceRange Range, bool BestCase,
- MSInheritanceAttr::Spelling SemanticSpelling);
+ MSInheritanceAttr::Spelling SemanticSpelling, bool IsImplicit);
void CheckAlignasUnderalignment(Decl *D);
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -12579,9 +12579,9 @@
CheckAlignasUnderalignment(Record);
if (const MSInheritanceAttr *IA = Record->getAttr<MSInheritanceAttr>())
- checkMSInheritanceAttrOnDefinition(cast<CXXRecordDecl>(Record),
- IA->getRange(), IA->getBestCase(),
- IA->getSemanticSpelling());
+ checkMSInheritanceAttrOnDefinition(
+ cast<CXXRecordDecl>(Record), IA->getRange(), IA->getBestCase(),
+ IA->getSemanticSpelling(), IA->isImplicit());
}
// Check if the structure/union declaration is a type that can have zero
Index: lib/Sema/SemaDeclAttr.cpp
===================================================================
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -2845,7 +2845,7 @@
bool Sema::checkMSInheritanceAttrOnDefinition(
CXXRecordDecl *RD, SourceRange Range, bool BestCase,
- MSInheritanceAttr::Spelling SemanticSpelling) {
+ MSInheritanceAttr::Spelling SemanticSpelling, bool IsImplicit) {
assert(RD->hasDefinition() && "RD has no definition!");
// We may not have seen base specifiers or any virtual methods yet. We will
@@ -2857,19 +2857,27 @@
if (SemanticSpelling == MSInheritanceAttr::Keyword_unspecified_inheritance)
return false;
+ MSInheritanceAttr::Spelling CalculatedInheritanceModel =
+ RD->calculateInheritanceModel();
if (BestCase) {
- if (RD->calculateInheritanceModel() == SemanticSpelling)
+ if (CalculatedInheritanceModel == SemanticSpelling)
return false;
} else {
- if (RD->calculateInheritanceModel() <= SemanticSpelling)
+ if (CalculatedInheritanceModel <= SemanticSpelling)
return false;
}
- Diag(Range.getBegin(), diag::err_mismatched_ms_inheritance)
- << 0 /*definition*/;
+ bool MismatchIsErroneous = !BestCase || !IsImplicit;
+ if (MismatchIsErroneous)
+ Diag(Range.getBegin(), diag::err_mismatched_ms_inheritance)
+ << 0 /*definition*/ << SemanticSpelling << CalculatedInheritanceModel;
+ else
+ Diag(Range.getBegin(), diag::warn_mismatched_ms_inheritance)
+ << SemanticSpelling << CalculatedInheritanceModel;
+
Diag(RD->getDefinition()->getLocation(), diag::note_defined_here)
<< RD->getNameAsString();
- return true;
+ return MismatchIsErroneous;
}
/// handleModeAttr - This attribute modifies the width of a decl with primitive
@@ -3894,15 +3902,16 @@
if (IA->getSemanticSpelling() == SemanticSpelling)
return nullptr;
Diag(IA->getLocation(), diag::err_mismatched_ms_inheritance)
- << 1 /*previous declaration*/;
+ << 1 /*previous declaration*/ << SemanticSpelling
+ << IA->getSemanticSpelling();
Diag(Range.getBegin(), diag::note_previous_ms_inheritance);
D->dropAttr<MSInheritanceAttr>();
}
CXXRecordDecl *RD = cast<CXXRecordDecl>(D);
if (RD->hasDefinition()) {
- if (checkMSInheritanceAttrOnDefinition(RD, Range, BestCase,
- SemanticSpelling)) {
+ if (checkMSInheritanceAttrOnDefinition(
+ RD, Range, BestCase, SemanticSpelling, /*IsImplicit=*/false)) {
return nullptr;
}
} else {
Index: test/SemaCXX/member-pointer-ms.cpp
===================================================================
--- test/SemaCXX/member-pointer-ms.cpp
+++ test/SemaCXX/member-pointer-ms.cpp
@@ -248,6 +248,18 @@
struct __virtual_inheritance D;
struct D : virtual B {};
}
+
+#ifdef VMB
+namespace WarnTest {
+struct A {};
+struct B : A { // expected-warning {{inheritance model does not match definition}}
+ // expected-note@-1 {{B defined here}}
+ int B::*x;
+ virtual void f();
+};
+}
+#endif
+
#ifdef VMB
#pragma pointers_to_members(full_generality, multiple_inheritance)
struct TrulySingleInheritance;
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits