diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index d6c32c27b9d5..6017ef8d6d76 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -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 diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index dc92afdd111b..7422ca859736 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -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()) @@ -529,9 +531,12 @@ unsigned ASTContext::getDeclAlignInBytes(const Decl *D) { if (const ValueDecl *VD = dyn_cast(D)) { QualType T = VD->getType(); if (const ReferenceType* RT = T->getAs()) { - 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(T) || isa(T)) T = cast(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(T)->getPointeeType().getAddressSpace(); + Width = Target.getPointerWidth(AS); + Align = Target.getPointerAlign(AS); + break; + } case Type::Pointer: { unsigned AS = cast(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(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/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 2689859e8e4a..d738afdd81bc 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -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()) + 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(E)) - return Info.Ctx.getDeclAlignInBytes(DRE->getDecl()); + return Info.Ctx.getDeclAlignInBytes(DRE->getDecl(), /*RefAsPointee*/true); if (const MemberExpr *ME = dyn_cast(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()) + SrcTy = Ref->getPointeeType(); // sizeof(void), __alignof__(void), sizeof(function) = 1 as a gcc // extension. diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index d32b3a97cd3c..15b531973720 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -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()) + exprType = Ref->getPointeeType(); + // C99 6.5.3.4p1: if (exprType->isFunctionType()) { // alignof(function) is allowed as an extension. diff --git a/clang/test/CodeGenCXX/references.cpp b/clang/test/CodeGenCXX/references.cpp index 8e0e1cbe84e8..eaaf346d7ccd 100644 --- a/clang/test/CodeGenCXX/references.cpp +++ b/clang/test/CodeGenCXX/references.cpp @@ -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; } diff --git a/clang/test/SemaCXX/alignof-sizeof-reference.cpp b/clang/test/SemaCXX/alignof-sizeof-reference.cpp new file mode 100644 index 000000000000..27d98ab6491e --- /dev/null +++ b/clang/test/SemaCXX/alignof-sizeof-reference.cpp @@ -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"); +}