Intercept sizeof and alignof references before they get into ASTContext methods. This fixes a crash when writing sizeof(Incomplete&), and lets ASTContext's methods do the right thing for CodeGen, which fixes PR5590.

llvm-svn: 89668
This commit is contained in:
Sebastian Redl 2009-11-23 17:18:46 +00:00
parent a3624b6099
commit 22e2e5c423
6 changed files with 56 additions and 17 deletions

View File

@ -810,10 +810,7 @@ public:
/// a data type.
unsigned getPreferredTypeAlign(const Type *T);
/// getDeclAlignInBytes - Return the alignment of the specified decl
/// that should be returned by __alignof(). Note that bitfields do
/// not have a valid alignment, so this method will assert on them.
unsigned getDeclAlignInBytes(const Decl *D);
unsigned getDeclAlignInBytes(const Decl *D, bool RefAsPointee = false);
/// getASTRecordLayout - Get or compute information about the layout of the
/// specified record (struct/union/class), which indicates its size and field

View File

@ -520,7 +520,9 @@ const llvm::fltSemantics &ASTContext::getFloatTypeSemantics(QualType T) const {
/// getDeclAlignInBytes - Return a conservative estimate of the alignment of the
/// specified decl. Note that bitfields do not have a valid alignment, so
/// this method will assert on them.
unsigned ASTContext::getDeclAlignInBytes(const Decl *D) {
/// If @p RefAsPointee, references are treated like their underlying type
/// (for alignof), else they're treated like pointers (for CodeGen).
unsigned ASTContext::getDeclAlignInBytes(const Decl *D, bool RefAsPointee) {
unsigned Align = Target.getCharWidth();
if (const AlignedAttr* AA = D->getAttr<AlignedAttr>())
@ -529,9 +531,12 @@ unsigned ASTContext::getDeclAlignInBytes(const Decl *D) {
if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
QualType T = VD->getType();
if (const ReferenceType* RT = T->getAs<ReferenceType>()) {
unsigned AS = RT->getPointeeType().getAddressSpace();
Align = Target.getPointerAlign(AS);
} else if (!T->isIncompleteType() && !T->isFunctionType()) {
if (RefAsPointee)
T = RT->getPointeeType();
else
T = getPointerType(RT->getPointeeType());
}
if (!T->isIncompleteType() && !T->isFunctionType()) {
// Incomplete or function types default to 1.
while (isa<VariableArrayType>(T) || isa<IncompleteArrayType>(T))
T = cast<ArrayType>(T)->getElementType();
@ -690,19 +695,21 @@ ASTContext::getTypeInfo(const Type *T) {
Align = Target.getPointerAlign(AS);
break;
}
case Type::LValueReference:
case Type::RValueReference: {
// alignof and sizeof should never enter this code path here, so we go
// the pointer route.
unsigned AS = cast<ReferenceType>(T)->getPointeeType().getAddressSpace();
Width = Target.getPointerWidth(AS);
Align = Target.getPointerAlign(AS);
break;
}
case Type::Pointer: {
unsigned AS = cast<PointerType>(T)->getPointeeType().getAddressSpace();
Width = Target.getPointerWidth(AS);
Align = Target.getPointerAlign(AS);
break;
}
case Type::LValueReference:
case Type::RValueReference:
// "When applied to a reference or a reference type, the result is the size
// of the referenced type." C++98 5.3.3p2: expr.sizeof.
// FIXME: This is wrong for struct layout: a reference in a struct has
// pointer size.
return getTypeInfo(cast<ReferenceType>(T)->getPointeeType());
case Type::MemberPointer: {
// FIXME: This is ABI dependent. We use the Itanium C++ ABI.
// http://www.codesourcery.com/public/cxx-abi/abi.html#member-pointers

View File

@ -1244,6 +1244,13 @@ bool IntExprEvaluator::VisitConditionalOperator(const ConditionalOperator *E) {
}
unsigned IntExprEvaluator::GetAlignOfType(QualType T) {
// C++ [expr.sizeof]p2: "When applied to a reference or a reference type,
// the result is the size of the referenced type."
// C++ [expr.alignof]p3: "When alignof is applied to a reference type, the
// result shall be the alignment of the referenced type."
if (const ReferenceType *Ref = T->getAs<ReferenceType>())
T = Ref->getPointeeType();
// Get information about the alignment.
unsigned CharSize = Info.Ctx.Target.getCharWidth();
@ -1257,10 +1264,11 @@ unsigned IntExprEvaluator::GetAlignOfExpr(const Expr *E) {
// alignof decl is always accepted, even if it doesn't make sense: we default
// to 1 in those cases.
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
return Info.Ctx.getDeclAlignInBytes(DRE->getDecl());
return Info.Ctx.getDeclAlignInBytes(DRE->getDecl(), /*RefAsPointee*/true);
if (const MemberExpr *ME = dyn_cast<MemberExpr>(E))
return Info.Ctx.getDeclAlignInBytes(ME->getMemberDecl());
return Info.Ctx.getDeclAlignInBytes(ME->getMemberDecl(),
/*RefAsPointee*/true);
return GetAlignOfType(E->getType());
}
@ -1280,6 +1288,12 @@ bool IntExprEvaluator::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E) {
}
QualType SrcTy = E->getTypeOfArgument();
// C++ [expr.sizeof]p2: "When applied to a reference or a reference type,
// the result is the size of the referenced type."
// C++ [expr.alignof]p3: "When alignof is applied to a reference type, the
// result shall be the alignment of the referenced type."
if (const ReferenceType *Ref = SrcTy->getAs<ReferenceType>())
SrcTy = Ref->getPointeeType();
// sizeof(void), __alignof__(void), sizeof(function) = 1 as a gcc
// extension.

View File

@ -1341,6 +1341,13 @@ bool Sema::CheckSizeOfAlignOfOperand(QualType exprType,
if (exprType->isDependentType())
return false;
// C++ [expr.sizeof]p2: "When applied to a reference or a reference type,
// the result is the size of the referenced type."
// C++ [expr.alignof]p3: "When alignof is applied to a reference type, the
// result shall be the alignment of the referenced type."
if (const ReferenceType *Ref = exprType->getAs<ReferenceType>())
exprType = Ref->getPointeeType();
// C99 6.5.3.4p1:
if (exprType->isFunctionType()) {
// alignof(function) is allowed as an extension.

View File

@ -136,3 +136,8 @@ void f(int &a) {
(a = 10) = 20;
}
}
// PR5590
struct s0;
struct s1 { struct s0 &s0; };
void f0(s1 a) { s1 b = a; }

View File

@ -0,0 +1,9 @@
// RUN: clang-cc -std=c++0x -fsyntax-only -verify %s
struct s0; // expected-note {{forward declaration}}
char ar[sizeof(s0&)]; // expected-error {{invalid application of 'sizeof' to an incomplete type}}
void test() {
char &r = ar[0];
static_assert(alignof(r) == 1, "bad alignment");
static_assert(sizeof(r) == 1, "bad size");
}