forked from OSchip/llvm-project
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:
parent
a3624b6099
commit
22e2e5c423
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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");
|
||||
}
|
Loading…
Reference in New Issue