From f6d7030f0f99de010dbf2737dc4a58b234e0f4b6 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Tue, 10 Jun 2014 23:34:28 +0000 Subject: [PATCH] Related to PR19992: when the GNU alignof-expression extension is applied to an expression of array-of-unknown-bound type, don't try to complete the array bound, and return the alignment of the element type rather than 1. llvm-svn: 210608 --- clang/lib/AST/ASTContext.cpp | 11 ++++++++--- clang/lib/AST/ExprConstant.cpp | 7 ++++--- clang/lib/Sema/SemaExpr.cpp | 19 +++++++++++++++---- clang/test/SemaCXX/alignof.cpp | 15 ++++++++++++--- 4 files changed, 39 insertions(+), 13 deletions(-) diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 4dff88b..f78f2a9 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -1309,13 +1309,14 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool ForAlignof) const { } else if (const ValueDecl *VD = dyn_cast(D)) { QualType T = VD->getType(); - if (const ReferenceType* RT = T->getAs()) { + if (const ReferenceType *RT = T->getAs()) { if (ForAlignof) T = RT->getPointeeType(); else T = getPointerType(RT->getPointeeType()); } - if (!T->isIncompleteType() && !T->isFunctionType()) { + QualType BaseT = getBaseElementType(T); + if (!BaseT->isIncompleteType() && !T->isFunctionType()) { // Adjust alignments of declarations with array type by the // large-array alignment on the target. if (const ArrayType *arrayType = getAsArrayType(T)) { @@ -1330,8 +1331,12 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool ForAlignof) const { // Keep track of extra alignment requirements on the array itself, then // work with the element type. + // + // FIXME: Computing the preferred type alignment for the array element + // type should not be necessary, but getPreferredTypeAlign returns the + // wrong thing in some cases (such as 'long long[]' on x86_64). Align = std::max(Align, getPreferredTypeAlign(T.getTypePtr())); - T = getBaseElementType(arrayType); + T = BaseT; } Align = std::max(Align, getPreferredTypeAlign(T.getTypePtr())); if (const VarDecl *VD = dyn_cast(D)) { diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index c1468cb..99b289a 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -6910,8 +6910,9 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { } CharUnits IntExprEvaluator::GetAlignOfType(QualType T) { - // C++ [expr.alignof]p3: "When alignof is applied to a reference type, the - // result shall be the alignment of the referenced type." + // C++ [expr.alignof]p3: + // When alignof is applied to a reference type, the result is the + // alignment of the referenced type. if (const ReferenceType *Ref = T->getAs()) T = Ref->getPointeeType(); @@ -6930,7 +6931,7 @@ CharUnits 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.getDeclAlign(DRE->getDecl(), + return Info.Ctx.getDeclAlign(DRE->getDecl(), /*RefAsPointee*/true); if (const MemberExpr *ME = dyn_cast(E)) diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index d2ba82b..041a9eb 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -3341,10 +3341,21 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E, E->getSourceRange(), ExprKind)) return false; - if (RequireCompleteExprType(E, - diag::err_sizeof_alignof_incomplete_type, - ExprKind, E->getSourceRange())) - return true; + // 'alignof' applied to an expression only requires the base element type of + // the expression to be complete. 'sizeof' requires the expression's type to + // be complete (and will attempt to complete it if it's an array of unknown + // bound). + if (ExprKind == UETT_AlignOf) { + if (RequireCompleteType(E->getExprLoc(), + Context.getBaseElementType(E->getType()), + diag::err_sizeof_alignof_incomplete_type, ExprKind, + E->getSourceRange())) + return true; + } else { + if (RequireCompleteExprType(E, diag::err_sizeof_alignof_incomplete_type, + ExprKind, E->getSourceRange())) + return true; + } // Completing the expression's type may have changed it. ExprTy = E->getType(); diff --git a/clang/test/SemaCXX/alignof.cpp b/clang/test/SemaCXX/alignof.cpp index 3b56ae1..011f459 100644 --- a/clang/test/SemaCXX/alignof.cpp +++ b/clang/test/SemaCXX/alignof.cpp @@ -64,7 +64,16 @@ long long int test14[2]; static_assert(alignof(test14) == 8, "foo"); // expected-warning {{'alignof' applied to an expression is a GNU extension}} // PR19992 -alignas(32) extern int test15[]; static_assert(alignof(int[]) == alignof(int), ""); // ok -// FIXME: We should accept this. -static_assert(alignof(test15) == 32, ""); // expected-warning {{GNU extension}} expected-error {{incomplete type}} + +namespace alignof_array_expr { + alignas(32) extern int n[]; + static_assert(alignof(n) == 32, ""); // expected-warning {{GNU extension}} + + template struct S { + static int a[]; + }; + template int S::a[N]; + // ok, does not complete type of S<-1>::a + static_assert(alignof(S<-1>::a) == alignof(int), ""); // expected-warning {{GNU extension}} +} -- 2.7.4