summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/clang/Basic/DiagnosticASTKinds.td8
-rw-r--r--include/clang/Basic/DiagnosticIDs.h2
-rw-r--r--lib/AST/VTableBuilder.cpp52
3 files changed, 51 insertions, 11 deletions
diff --git a/include/clang/Basic/DiagnosticASTKinds.td b/include/clang/Basic/DiagnosticASTKinds.td
index d353b451aa..0b37030d7e 100644
--- a/include/clang/Basic/DiagnosticASTKinds.td
+++ b/include/clang/Basic/DiagnosticASTKinds.td
@@ -168,6 +168,14 @@ let CategoryName = "Inline Assembly Issue" in {
"invalid operand number in inline asm string">;
}
+// vtable related.
+let CategoryName = "VTable ABI Issue" in {
+ def err_vftable_ambiguous_component : Error<
+ "ambiguous vftable component for %0 introduced via covariant thunks; "
+ "this is an inherent limitation of the ABI">;
+ def note_covariant_thunk : Note<
+ "covariant thunk required by %0">;
+}
// Importing ASTs
def err_odr_variable_type_inconsistent : Error<
diff --git a/include/clang/Basic/DiagnosticIDs.h b/include/clang/Basic/DiagnosticIDs.h
index 99b469d70e..a675dfabe4 100644
--- a/include/clang/Basic/DiagnosticIDs.h
+++ b/include/clang/Basic/DiagnosticIDs.h
@@ -34,7 +34,7 @@ namespace clang {
DIAG_START_LEX = DIAG_START_SERIALIZATION + 120,
DIAG_START_PARSE = DIAG_START_LEX + 300,
DIAG_START_AST = DIAG_START_PARSE + 500,
- DIAG_START_COMMENT = DIAG_START_AST + 100,
+ DIAG_START_COMMENT = DIAG_START_AST + 110,
DIAG_START_SEMA = DIAG_START_COMMENT + 100,
DIAG_START_ANALYSIS = DIAG_START_SEMA + 3000,
DIAG_UPPER_LIMIT = DIAG_START_ANALYSIS + 100
diff --git a/lib/AST/VTableBuilder.cpp b/lib/AST/VTableBuilder.cpp
index de0c11a249..5c7b9d2a68 100644
--- a/lib/AST/VTableBuilder.cpp
+++ b/lib/AST/VTableBuilder.cpp
@@ -13,6 +13,7 @@
#include "clang/AST/VTableBuilder.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/RecordLayout.h"
#include "clang/Basic/TargetInfo.h"
@@ -3482,9 +3483,24 @@ static bool findPathForVPtr(ASTContext &Context,
CXXBasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/false,
/*DetectVirtual=*/true);
+#if 0
+ std::vector<const CXXRecordDecl *> BaseLists;
+ for (const auto &B : RD->bases()) {
+ const CXXRecordDecl *Base = B.getType()->getAsCXXRecordDecl();
+ Paths.clear();
+ if (!Base->isDerivedFrom(Info->BaseWithVPtr, Paths))
+ continue;
+ for (const auto &Chain : BaseLists) {
+ const CXXRecordDecl *MostDerived = Chain.front();
+ }
+ }
+#endif
// All virtual bases which are on the path to the BaseWithVPtr are not equal.
// Specifically, virtual paths which introduce additional covariant thunks
// must be preferred over paths which do not introduce such thunks.
+ const CXXRecordDecl *Base = nullptr;
+ CharUnits NewOffset;
+ const CXXMethodDecl *CovariantMD = nullptr;
for (const auto *MD : Info->BaseWithVPtr->methods()) {
if (!MD->isVirtual())
continue;
@@ -3501,10 +3517,10 @@ static bool findPathForVPtr(ASTContext &Context,
// Ok, let's iterate through our virtual bases looking for a base which
// provides a return adjusting overrider for this method.
- const CXXRecordDecl *Base = nullptr;
- CharUnits NewOffset;
for (const auto &B : RD->bases()) {
const CXXRecordDecl *VBase = B.getType()->getAsCXXRecordDecl();
+ if (Base == VBase)
+ continue;
// There might be a vbase which derives from a vbase which provides a
// covariant override for the method *and* provides its own covariant
// override.
@@ -3512,7 +3528,7 @@ static bool findPathForVPtr(ASTContext &Context,
// looking for the most derived virtual base which provides a covariant
// override for the method.
Paths.clear();
- if (!VBase->isDerivedFrom(Base ? Base : Info->BaseWithVPtr, Paths) ||
+ if (!VBase->isDerivedFrom(Info->BaseWithVPtr, Paths) ||
!Paths.getDetectedVirtual())
continue;
const CXXMethodDecl *VBaseMD = MD->getCorrespondingMethodInClass(VBase);
@@ -3525,17 +3541,33 @@ static bool findPathForVPtr(ASTContext &Context,
// Skip any overriders which are not return adjusting.
if (BO.isEmpty() || !BO.VirtualBase)
continue;
- Base = VBase;
- NewOffset = VBaseNewOffset;
+ Paths.clear();
+ if (!Base || VBase->isDerivedFrom(Base, Paths)) {
+ assert(!Base || Paths.getDetectedVirtual());
+ Base = VBase;
+ NewOffset = VBaseNewOffset;
+ CovariantMD = VBaseMD;
+ } else {
+ Paths.clear();
+ if (!Base->isDerivedFrom(VBase, Paths)) {
+ DiagnosticsEngine &Diags = Context.getDiagnostics();
+ Diags.Report(RD->getLocation(), diag::err_vftable_ambiguous_component)
+ << RD;
+ Diags.Report(CovariantMD->getLocation(), diag::note_covariant_thunk)
+ << CovariantMD;
+ Diags.Report(VBaseMD->getLocation(), diag::note_covariant_thunk)
+ << VBaseMD;
+ }
+ }
}
-
- if (Base && Recurse(Base, NewOffset))
- return true;
}
+ if (Base && Recurse(Base, NewOffset))
+ return true;
+
for (const auto &B : RD->bases()) {
- const CXXRecordDecl *Base = B.getType()->getAsCXXRecordDecl();
- CharUnits NewOffset = GetBaseOffset(B);
+ Base = B.getType()->getAsCXXRecordDecl();
+ NewOffset = GetBaseOffset(B);
if (Recurse(Base, NewOffset))
return true;
}