mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-03-02 15:26:29 +00:00
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. llvm-svn: 102571
This commit is contained in:
parent
a5a8f76cea
commit
d170206761
@ -1024,9 +1024,15 @@ public:
|
||||
public:
|
||||
/// \brief The kind of offsetof node we have.
|
||||
enum Kind {
|
||||
/// \brief An index into an array.
|
||||
Array = 0x00,
|
||||
/// \brief A field.
|
||||
Field = 0x01,
|
||||
Identifier = 0x02
|
||||
/// \brief A field in a dependent type, known only by its name.
|
||||
Identifier = 0x02,
|
||||
/// \brief An implicit indirection through a C++ base class, when the
|
||||
/// field found is in a base class.
|
||||
Base = 0x03
|
||||
};
|
||||
|
||||
private:
|
||||
@ -1042,6 +1048,8 @@ public:
|
||||
/// - A FieldDecl*, for references to a known field.
|
||||
/// - An IdentifierInfo*, for references to a field with a given name
|
||||
/// when the class type is dependent.
|
||||
/// - A CXXBaseSpecifier*, for references that look at a field in a
|
||||
/// base class.
|
||||
uintptr_t Data;
|
||||
|
||||
public:
|
||||
@ -1061,6 +1069,10 @@ public:
|
||||
SourceLocation NameLoc)
|
||||
: Range(DotLoc.isValid()? DotLoc : NameLoc, NameLoc),
|
||||
Data(reinterpret_cast<uintptr_t>(Name) | Identifier) { }
|
||||
|
||||
/// \brief Create an offsetof node that refers into a C++ base class.
|
||||
explicit OffsetOfNode(const CXXBaseSpecifier *Base)
|
||||
: Range(), Data(reinterpret_cast<uintptr_t>(Base) | OffsetOfNode::Base) {}
|
||||
|
||||
/// \brief Determine what kind of offsetof node this is.
|
||||
Kind getKind() const {
|
||||
@ -1077,13 +1089,19 @@ public:
|
||||
/// \brief For a field offsetof node, returns the field.
|
||||
FieldDecl *getField() const {
|
||||
assert(getKind() == Field);
|
||||
return reinterpret_cast<FieldDecl *> (Data & ~(uintptr_t)Mask);
|
||||
return reinterpret_cast<FieldDecl *>(Data & ~(uintptr_t)Mask);
|
||||
}
|
||||
|
||||
/// \brief For a field or identifier offsetof node, returns the name of
|
||||
/// the field.
|
||||
IdentifierInfo *getFieldName() const;
|
||||
|
||||
/// \brief For a base class node, returns the base specifier.
|
||||
CXXBaseSpecifier *getBase() const {
|
||||
assert(getKind() == Base);
|
||||
return reinterpret_cast<CXXBaseSpecifier *>(Data & ~(uintptr_t)Mask);
|
||||
}
|
||||
|
||||
/// \brief Retrieve the source range that covers this offsetof node.
|
||||
///
|
||||
/// For an array element node, the source range contains the locations of
|
||||
|
@ -1414,17 +1414,41 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *E) {
|
||||
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);
|
||||
|
@ -718,7 +718,11 @@ void StmtPrinter::VisitOffsetOfExpr(OffsetOfExpr *Node) {
|
||||
PrintedSomething = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Skip implicit base indirections.
|
||||
if (ON.getKind() == OffsetOfExpr::OffsetOfNode::Base)
|
||||
continue;
|
||||
|
||||
// Field or identifier node.
|
||||
IdentifierInfo *Id = ON.getFieldName();
|
||||
if (!Id)
|
||||
|
@ -279,6 +279,10 @@ void StmtProfiler::VisitOffsetOfExpr(OffsetOfExpr *S) {
|
||||
case OffsetOfExpr::OffsetOfNode::Identifier:
|
||||
ID.AddPointer(ON.getFieldName());
|
||||
break;
|
||||
|
||||
case OffsetOfExpr::OffsetOfNode::Base:
|
||||
// These nodes are implicit, and therefore don't need profiling.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -462,6 +462,11 @@ unsigned PCHStmtReader::VisitOffsetOfExpr(OffsetOfExpr *E) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -418,6 +418,11 @@ void PCHStmtWriter::VisitOffsetOfExpr(OffsetOfExpr *E) {
|
||||
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)
|
||||
|
@ -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 @@ Sema::OwningExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc,
|
||||
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;
|
||||
|
@ -4223,6 +4223,10 @@ TreeTransform<Derived>::TransformOffsetOfExpr(OffsetOfExpr *E) {
|
||||
continue;
|
||||
|
||||
break;
|
||||
|
||||
case Node::Base:
|
||||
// Will be recomputed during the rebuild.
|
||||
continue;
|
||||
}
|
||||
|
||||
Components.push_back(Comp);
|
||||
|
@ -1,4 +1,4 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify %s -Winvalid-offsetof
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin10.0.0 -fsyntax-only -verify %s -Winvalid-offsetof
|
||||
|
||||
struct NonPOD {
|
||||
virtual void f();
|
||||
@ -36,3 +36,20 @@ struct has_bitfields {
|
||||
};
|
||||
|
||||
int test3 = __builtin_offsetof(struct has_bitfields, j); // expected-error{{cannot compute offset of bit-field 'j'}}
|
||||
|
||||
// offsetof referring to members of a base class.
|
||||
struct Base1 {
|
||||
int x;
|
||||
};
|
||||
|
||||
struct Base2 {
|
||||
int y;
|
||||
};
|
||||
|
||||
struct Derived2 : public Base1, public Base2 {
|
||||
int z;
|
||||
};
|
||||
|
||||
int derived1[__builtin_offsetof(Derived2, x) == 0? 1 : -1];
|
||||
int derived2[__builtin_offsetof(Derived2, y) == 4? 1 : -1];
|
||||
int derived3[__builtin_offsetof(Derived2, z) == 8? 1 : -1];
|
||||
|
Loading…
x
Reference in New Issue
Block a user