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.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@89668 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index dc92afd..7422ca8 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -520,7 +520,9 @@
/// 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 @@
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 @@
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
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 2689859..d738afd 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -1244,6 +1244,13 @@
}
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 @@
// 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 @@
}
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.