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:
/// - 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:
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 {
/// \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
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);
PrintedSomething = true;
continue;
}
-
+
+ // Skip implicit base indirections.
+ if (ON.getKind() == OffsetOfExpr::OffsetOfNode::Base)
+ continue;
+
// Field or identifier node.
IdentifierInfo *Id = ON.getFieldName();
if (!Id)
case OffsetOfExpr::OffsetOfNode::Identifier:
ID.AddPointer(ON.getFieldName());
break;
+
+ case OffsetOfExpr::OffsetOfNode::Base:
+ // These nodes are implicit, and therefore don't need profiling.
+ break;
}
}
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;
}
}
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)
#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"
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;
continue;
break;
+
+ case Node::Base:
+ // Will be recomputed during the rebuild.
+ continue;
}
Components.push_back(Comp);
-// 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();
};
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];