Teach __builtin_offsetof to compute the offsets of members of base
classes, since we only warn (not error) on offsetof() for non-POD
types. We store the base path within the OffsetOfExpr itself, then
evaluate the offsets within the constant evaluator.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@102571 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 7233518..1c2b76e 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -1414,17 +1414,41 @@
if (*Field == MemberDecl)
break;
}
- if (i < RL.getFieldCount())
- Result += CharUnits::fromQuantity(
- RL.getFieldOffset(i) / Info.Ctx.getCharWidth());
- else
- return false;
+ assert(i < RL.getFieldCount() && "offsetof field in wrong type");
+ Result += CharUnits::fromQuantity(
+ RL.getFieldOffset(i) / Info.Ctx.getCharWidth());
CurrentType = MemberDecl->getType().getNonReferenceType();
break;
}
case OffsetOfExpr::OffsetOfNode::Identifier:
llvm_unreachable("dependent __builtin_offsetof");
+ return false;
+
+ case OffsetOfExpr::OffsetOfNode::Base: {
+ CXXBaseSpecifier *BaseSpec = ON.getBase();
+ if (BaseSpec->isVirtual())
+ return false;
+
+ // Find the layout of the class whose base we are looking into.
+ const RecordType *RT = CurrentType->getAs<RecordType>();
+ if (!RT)
+ return false;
+ RecordDecl *RD = RT->getDecl();
+ const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD);
+
+ // Find the base class itself.
+ CurrentType = BaseSpec->getType();
+ const RecordType *BaseRT = CurrentType->getAs<RecordType>();
+ if (!BaseRT)
+ return false;
+
+ // Add the offset to the base.
+ Result += CharUnits::fromQuantity(
+ RL.getBaseClassOffset(cast<CXXRecordDecl>(BaseRT->getDecl()))
+ / Info.Ctx.getCharWidth());
+ break;
+ }
}
}
return Success(Result.getQuantity(), E);
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index b50bb0c..52f627d 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -718,7 +718,11 @@
PrintedSomething = true;
continue;
}
-
+
+ // Skip implicit base indirections.
+ if (ON.getKind() == OffsetOfExpr::OffsetOfNode::Base)
+ continue;
+
// Field or identifier node.
IdentifierInfo *Id = ON.getFieldName();
if (!Id)
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index 3d528f3..d45bb2f 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -279,6 +279,10 @@
case OffsetOfExpr::OffsetOfNode::Identifier:
ID.AddPointer(ON.getFieldName());
break;
+
+ case OffsetOfExpr::OffsetOfNode::Base:
+ // These nodes are implicit, and therefore don't need profiling.
+ break;
}
}
diff --git a/lib/Frontend/PCHReaderStmt.cpp b/lib/Frontend/PCHReaderStmt.cpp
index 8588c8a..ef6b770 100644
--- a/lib/Frontend/PCHReaderStmt.cpp
+++ b/lib/Frontend/PCHReaderStmt.cpp
@@ -462,6 +462,11 @@
case Node::Identifier:
E->setComponent(I, Node(Start, Reader.GetIdentifier(Record[Idx++]), End));
break;
+
+ case Node::Base:
+ // FIXME: Implement this!
+ llvm_unreachable("PCH for offsetof(base-specifier) not implemented");
+ break;
}
}
diff --git a/lib/Frontend/PCHWriterStmt.cpp b/lib/Frontend/PCHWriterStmt.cpp
index 3d158a4..a1993d3 100644
--- a/lib/Frontend/PCHWriterStmt.cpp
+++ b/lib/Frontend/PCHWriterStmt.cpp
@@ -418,6 +418,11 @@
case OffsetOfExpr::OffsetOfNode::Identifier:
Writer.AddIdentifierRef(ON.getFieldName(), Record);
break;
+
+ case OffsetOfExpr::OffsetOfNode::Base:
+ // FIXME: Implement this!
+ llvm_unreachable("PCH for offsetof(base-specifier) not implemented");
+ break;
}
}
for (unsigned I = 0, N = E->getNumExpressions(); I != N; ++I)
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 3785848..d8d525e 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -16,6 +16,7 @@
#include "Lookup.h"
#include "AnalysisBasedWarnings.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
@@ -6736,6 +6737,19 @@
return ExprError();
}
+ // If the member was found in a base class, introduce OffsetOfNodes for
+ // the base class indirections.
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
+ /*DetectVirtual=*/false);
+ if (IsDerivedFrom(CurrentType,
+ Context.getTypeDeclType(MemberDecl->getParent()),
+ Paths)) {
+ CXXBasePath &Path = Paths.front();
+ for (CXXBasePath::iterator B = Path.begin(), BEnd = Path.end();
+ B != BEnd; ++B)
+ Comps.push_back(OffsetOfNode(B->Base));
+ }
+
if (cast<RecordDecl>(MemberDecl->getDeclContext())->
isAnonymousStructOrUnion()) {
llvm::SmallVector<FieldDecl*, 4> Path;
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 4e32897..5143b77 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -4223,6 +4223,10 @@
continue;
break;
+
+ case Node::Base:
+ // Will be recomputed during the rebuild.
+ continue;
}
Components.push_back(Comp);