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;
}
}