ubsan updated this revision to Diff 169503.
ubsan added a comment.
add tests
fix nits
Repository:
rC Clang
https://reviews.llvm.org/D53207
Files:
include/clang/ASTMatchers/ASTMatchers.h
include/clang/Basic/LangOptions.h
include/clang/Basic/TypeTraits.h
lib/AST/ASTDumper.cpp
lib/AST/Expr.cpp
lib/AST/ExprConstant.cpp
lib/AST/ItaniumMangle.cpp
lib/AST/StmtPrinter.cpp
lib/Frontend/CompilerInvocation.cpp
lib/Parse/ParseExpr.cpp
lib/Sema/SemaChecking.cpp
lib/Sema/SemaExpr.cpp
test/Sema/align-x86.c
test/SemaCXX/align-x86.cpp
Index: test/SemaCXX/align-x86.cpp
===================================================================
--- /dev/null
+++ test/SemaCXX/align-x86.cpp
@@ -0,0 +1,59 @@
+// RUN: %clang_cc1 -std=c++11 -triple i386-apple-darwin9 -fsyntax-only -verify %s
+// expected-no-diagnostics
+
+#include <complex>
+#include <cstddef>
+
+template <typename T, std::size_t ABI, std::size_t Preferred>
+struct check_alignment {
+ using type = T;
+ static type value;
+
+ static_assert(__alignof__(value) == Preferred, "__alignof__(value) != Preferred");
+ static_assert(__alignof__(type) == Preferred, "__alignof__(type) != Preferred");
+ static_assert(alignof(type) == ABI, "alignof(type) != ABI");
+};
+
+// PR3433
+template struct check_alignment<double, 4, 8>;
+template struct check_alignment<long long, 4, 8>;
+template struct check_alignment<unsigned long long, 4, 8>;
+template struct check_alignment<std::complex<double>, 4, 4>;
+
+// PR6362
+struct __attribute__((packed))
+packed_struct {
+ unsigned int a;
+} g_packedstruct;
+template struct check_alignment<packed_struct, 1, 1>;
+static_assert(__alignof__(g_packedstruct.a) == 1, "__alignof__(packed_struct.member) != 1");
+
+typedef double arr3double[3];
+template struct check_alignment<double[3], 4, 8>;
+
+enum big_enum { x = 18446744073709551615ULL };
+template struct check_alignment<big_enum, 4, 8>;
+
+// PR5637
+
+#define ALIGNED(x) __attribute__((aligned(x)))
+
+typedef ALIGNED(2) struct {
+ char a[3];
+} aligned_before_struct;
+
+static_assert(sizeof(aligned_before_struct) == 3, "");
+static_assert(sizeof(aligned_before_struct[1]) == 4, "");
+static_assert(sizeof(aligned_before_struct[2]) == 6, "");
+static_assert(sizeof(aligned_before_struct[2][1]) == 8, "");
+static_assert(sizeof(aligned_before_struct[1][2]) == 6, "");
+
+typedef struct ALIGNED(2) {
+ char a[3];
+} aligned_after_struct;
+
+static_assert(sizeof(aligned_after_struct) == 4, "");
+static_assert(sizeof(aligned_after_struct[1]) == 4, "");
+static_assert(sizeof(aligned_after_struct[2]) == 8, "");
+static_assert(sizeof(aligned_after_struct[2][1]) == 8, "");
+static_assert(sizeof(aligned_after_struct[1][2]) == 8, "");
Index: test/Sema/align-x86.c
===================================================================
--- test/Sema/align-x86.c
+++ test/Sema/align-x86.c
@@ -1,34 +1,33 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c11 -triple i386-apple-darwin9 -fsyntax-only -verify %s
// expected-no-diagnostics
-// PR3433
-double g1;
-short chk1[__alignof__(g1) == 8 ? 1 : -1];
-short chk2[__alignof__(double) == 8 ? 1 : -1];
-
-long long g2;
-short chk1[__alignof__(g2) == 8 ? 1 : -1];
-short chk2[__alignof__(long long) == 8 ? 1 : -1];
+#define STATIC_ASSERT(cond) _Static_assert(cond, #cond)
-unsigned long long g5;
-short chk1[__alignof__(g5) == 8 ? 1 : -1];
-short chk2[__alignof__(unsigned long long) == 8 ? 1 : -1];
+// PR3433
+#define CHECK_ALIGNMENT(type, name, abi, pref) \
+ type name; \
+ STATIC_ASSERT(__alignof__(name) == pref); \
+ STATIC_ASSERT(__alignof__(type) == pref); \
+ STATIC_ASSERT(_Alignof(type) == abi)
-_Complex double g3;
-short chk1[__alignof__(g3) == 8 ? 1 : -1];
-short chk2[__alignof__(_Complex double) == 8 ? 1 : -1];
+CHECK_ALIGNMENT(double, g_double, 4, 8);
+CHECK_ALIGNMENT(long long, g_longlong, 4, 8);
+CHECK_ALIGNMENT(unsigned long long, g_ulonglong, 4, 8);
+CHECK_ALIGNMENT(_Complex double, g_complexdouble, 4, 8);
// PR6362
-struct __attribute__((packed)) {unsigned int a;} g4;
-short chk1[__alignof__(g4) == 1 ? 1 : -1];
-short chk2[__alignof__(g4.a) == 1 ? 1 : -1];
+struct __attribute__((packed))
+packed_struct {
+ unsigned int a;
+};
+CHECK_ALIGNMENT(struct packed_struct, g_packedstruct, 1, 1);
+STATIC_ASSERT(__alignof__(g_packedstruct.a) == 1);
-double g6[3];
-short chk1[__alignof__(g6) == 8 ? 1 : -1];
-short chk2[__alignof__(double[3]) == 8 ? 1 : -1];
+typedef double arr3double[3];
+CHECK_ALIGNMENT(arr3double, g_arr3double, 4, 8);
-enum { x = 18446744073709551615ULL } g7;
-short chk1[__alignof__(g7) == 8 ? 1 : -1];
+enum big_enum { x = 18446744073709551615ULL };
+CHECK_ALIGNMENT(big_enum, g_bigenum, 4, 8);
// PR5637
@@ -36,20 +35,20 @@
typedef ALIGNED(2) struct {
char a[3];
-} T;
+} aligned_before_struct;
-short chk1[sizeof(T) == 3 ? 1 : -1];
-short chk2[sizeof(T[1]) == 4 ? 1 : -1];
-short chk3[sizeof(T[2]) == 6 ? 1 : -1];
-short chk4[sizeof(T[2][1]) == 8 ? 1 : -1];
-short chk5[sizeof(T[1][2]) == 6 ? 1 : -1];
+STATIC_ASSERT(sizeof(aligned_before_struct) == 3);
+STATIC_ASSERT(sizeof(aligned_before_struct[1]) == 4);
+STATIC_ASSERT(sizeof(aligned_before_struct[2]) == 6);
+STATIC_ASSERT(sizeof(aligned_before_struct[2][1]) == 8);
+STATIC_ASSERT(sizeof(aligned_before_struct[1][2]) == 6);
typedef struct ALIGNED(2) {
char a[3];
-} T2;
+} aligned_after_struct;
-short chk1[sizeof(T2) == 4 ? 1 : -1];
-short chk2[sizeof(T2[1]) == 4 ? 1 : -1];
-short chk3[sizeof(T2[2]) == 8 ? 1 : -1];
-short chk4[sizeof(T2[2][1]) == 8 ? 1 : -1];
-short chk5[sizeof(T2[1][2]) == 8 ? 1 : -1];
+STATIC_ASSERT(sizeof(aligned_after_struct) == 4);
+STATIC_ASSERT(sizeof(aligned_after_struct[1]) == 4);
+STATIC_ASSERT(sizeof(aligned_after_struct[2]) == 8);
+STATIC_ASSERT(sizeof(aligned_after_struct[2][1]) == 8);
+STATIC_ASSERT(sizeof(aligned_after_struct[1][2]) == 8);
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -3596,7 +3596,8 @@
// C99 6.5.3.4p1:
if (T->isFunctionType() &&
- (TraitKind == UETT_SizeOf || TraitKind == UETT_AlignOf)) {
+ (TraitKind == UETT_SizeOf || TraitKind == UETT_AlignOf ||
+ TraitKind == UETT_PreferredAlignOf)) {
// sizeof(function)/alignof(function) is allowed as an extension.
S.Diag(Loc, diag::ext_sizeof_alignof_function_type)
<< TraitKind << ArgRange;
@@ -3674,7 +3675,7 @@
// 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 (ExprKind == UETT_AlignOf || ExprKind == UETT_PreferredAlignOf) {
if (RequireCompleteType(E->getExprLoc(),
Context.getBaseElementType(E->getType()),
diag::err_sizeof_alignof_incomplete_type, ExprKind,
@@ -3698,7 +3699,8 @@
// The operand for sizeof and alignof is in an unevaluated expression context,
// so side effects could result in unintended consequences.
- if ((ExprKind == UETT_SizeOf || ExprKind == UETT_AlignOf) &&
+ if ((ExprKind == UETT_SizeOf || ExprKind == UETT_AlignOf ||
+ ExprKind == UETT_PreferredAlignOf) &&
!inTemplateInstantiation() && E->HasSideEffects(Context, false))
Diag(E->getExprLoc(), diag::warn_side_effects_unevaluated_context);
@@ -3767,7 +3769,8 @@
// C11 6.5.3.4/3, C++11 [expr.alignof]p3:
// When alignof or _Alignof is applied to an array type, the result
// is the alignment of the element type.
- if (ExprKind == UETT_AlignOf || ExprKind == UETT_OpenMPRequiredSimdAlign)
+ if (ExprKind == UETT_AlignOf || ExprKind == UETT_PreferredAlignOf ||
+ ExprKind == UETT_OpenMPRequiredSimdAlign)
ExprType = Context.getBaseElementType(ExprType);
if (ExprKind == UETT_VecStep)
@@ -4046,14 +4049,14 @@
bool isInvalid = false;
if (E->isTypeDependent()) {
// Delay type-checking for type-dependent expressions.
- } else if (ExprKind == UETT_AlignOf) {
+ } else if (ExprKind == UETT_AlignOf || ExprKind == UETT_PreferredAlignOf) {
isInvalid = CheckAlignOfExpr(*this, E);
} else if (ExprKind == UETT_VecStep) {
isInvalid = CheckVecStepExpr(E);
} else if (ExprKind == UETT_OpenMPRequiredSimdAlign) {
Diag(E->getExprLoc(), diag::err_openmp_default_simd_align_expr);
isInvalid = true;
- } else if (E->refersToBitField()) { // C99 6.5.3.4p1.
+ } else if (E->refersToBitField()) { // C99 6.5.3.4p1.
Diag(E->getExprLoc(), diag::err_sizeof_alignof_typeof_bitfield) << 0;
isInvalid = true;
} else {
Index: lib/Sema/SemaChecking.cpp
===================================================================
--- lib/Sema/SemaChecking.cpp
+++ lib/Sema/SemaChecking.cpp
@@ -5695,7 +5695,8 @@
if (!Arg->isTypeDependent() && !Arg->isValueDependent()) {
if (const auto *UE =
dyn_cast<UnaryExprOrTypeTraitExpr>(Arg->IgnoreParenImpCasts()))
- if (UE->getKind() == UETT_AlignOf)
+ if (UE->getKind() == UETT_AlignOf ||
+ UE->getKind() == UETT_PreferredAlignOf)
Diag(TheCall->getBeginLoc(), diag::warn_alloca_align_alignof)
<< Arg->getSourceRange();
Index: lib/Parse/ParseExpr.cpp
===================================================================
--- lib/Parse/ParseExpr.cpp
+++ lib/Parse/ParseExpr.cpp
@@ -2022,7 +2022,9 @@
CastRange);
UnaryExprOrTypeTrait ExprKind = UETT_SizeOf;
- if (OpTok.isOneOf(tok::kw_alignof, tok::kw___alignof, tok::kw__Alignof))
+ if (OpTok.is(tok::kw___alignof))
+ ExprKind = UETT_PreferredAlignOf;
+ else if (OpTok.isOneOf(tok::kw_alignof, tok::kw__Alignof))
ExprKind = UETT_AlignOf;
else if (OpTok.is(tok::kw_vec_step))
ExprKind = UETT_VecStep;
Index: lib/Frontend/CompilerInvocation.cpp
===================================================================
--- lib/Frontend/CompilerInvocation.cpp
+++ lib/Frontend/CompilerInvocation.cpp
@@ -2812,6 +2812,8 @@
Opts.setClangABICompat(LangOptions::ClangABI::Ver4);
else if (Major <= 6)
Opts.setClangABICompat(LangOptions::ClangABI::Ver6);
+ else if (Major <= 7)
+ Opts.setClangABICompat(LangOptions::ClangABI::Ver7);
} else if (Ver != "latest") {
Diags.Report(diag::err_drv_invalid_value)
<< A->getAsString(Args) << A->getValue();
Index: lib/AST/StmtPrinter.cpp
===================================================================
--- lib/AST/StmtPrinter.cpp
+++ lib/AST/StmtPrinter.cpp
@@ -1686,6 +1686,9 @@
else
OS << "__alignof";
break;
+ case UETT_PreferredAlignOf:
+ OS << "__alignof";
+ break;
case UETT_VecStep:
OS << "vec_step";
break;
Index: lib/AST/ItaniumMangle.cpp
===================================================================
--- lib/AST/ItaniumMangle.cpp
+++ lib/AST/ItaniumMangle.cpp
@@ -3881,6 +3881,7 @@
case UETT_SizeOf:
Out << 's';
break;
+ case UETT_PreferredAlignOf:
case UETT_AlignOf:
Out << 'a';
break;
Index: lib/AST/ExprConstant.cpp
===================================================================
--- lib/AST/ExprConstant.cpp
+++ lib/AST/ExprConstant.cpp
@@ -5946,21 +5946,33 @@
return ExprEvaluatorBaseTy::VisitCastExpr(E);
}
-static CharUnits GetAlignOfType(EvalInfo &Info, QualType T) {
+static CharUnits GetAlignOfType(EvalInfo &Info, QualType T,
+ bool PreferredAlignOf) {
// 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<ReferenceType>())
T = Ref->getPointeeType();
- // __alignof is defined to return the preferred alignment.
if (T.getQualifiers().hasUnaligned())
return CharUnits::One();
- return Info.Ctx.toCharUnitsFromBits(
- Info.Ctx.getPreferredTypeAlign(T.getTypePtr()));
+
+ const bool AlignOfReturnsPreferred =
+ Info.Ctx.getLangOpts().getClangABICompat() <= LangOptions::ClangABI::Ver7;
+ // __alignof is defined to return the preferred alignment.
+ // before 8, clang returned the preferred alignment for alignof and _Alignof
+ // as well
+ if (PreferredAlignOf || AlignOfReturnsPreferred)
+ return Info.Ctx.toCharUnitsFromBits(
+ Info.Ctx.getPreferredTypeAlign(T.getTypePtr()));
+ // alignof (C++) and _Alignof (C11) are defined to return the ABI alignment
+ // see https://bugs.llvm.org/show_bug.cgi?id=26547 for explanation
+ else
+ return Info.Ctx.getTypeAlignInChars(T.getTypePtr());
}
-static CharUnits GetAlignOfExpr(EvalInfo &Info, const Expr *E) {
+static CharUnits GetAlignOfExpr(EvalInfo &Info, const Expr *E,
+ bool PreferredAlignOf) {
E = E->IgnoreParens();
// The kinds of expressions that we have special-case logic here for
@@ -5977,7 +5989,7 @@
return Info.Ctx.getDeclAlign(ME->getMemberDecl(),
/*RefAsPointee*/true);
- return GetAlignOfType(Info, E->getType());
+ return GetAlignOfType(Info, E->getType(), PreferredAlignOf);
}
// To be clear: this happily visits unsupported builtins. Better name welcomed.
@@ -6039,7 +6051,7 @@
BaseAlignment = Info.Ctx.getDeclAlign(VD);
} else {
BaseAlignment =
- GetAlignOfExpr(Info, OffsetResult.Base.get<const Expr*>());
+ GetAlignOfExpr(Info, OffsetResult.Base.get<const Expr *>(), false);
}
if (BaseAlignment < Align) {
@@ -9357,12 +9369,18 @@
/// a result as the expression's type.
bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr(
const UnaryExprOrTypeTraitExpr *E) {
- switch(E->getKind()) {
+ const auto Kind = E->getKind();
+ switch (Kind) {
+ case UETT_PreferredAlignOf:
case UETT_AlignOf: {
if (E->isArgumentType())
- return Success(GetAlignOfType(Info, E->getArgumentType()), E);
+ return Success(GetAlignOfType(Info, E->getArgumentType(),
+ Kind == UETT_PreferredAlignOf),
+ E);
else
- return Success(GetAlignOfExpr(Info, E->getArgumentExpr()), E);
+ return Success(GetAlignOfExpr(Info, E->getArgumentExpr(),
+ Kind == UETT_PreferredAlignOf),
+ E);
}
case UETT_VecStep: {
Index: lib/AST/Expr.cpp
===================================================================
--- lib/AST/Expr.cpp
+++ lib/AST/Expr.cpp
@@ -1446,7 +1446,7 @@
// Check to see if we are in the situation where alignof(decl) should be
// dependent because decl's alignment is dependent.
- if (ExprKind == UETT_AlignOf) {
+ if (ExprKind == UETT_AlignOf || ExprKind == UETT_PreferredAlignOf) {
if (!isValueDependent() || !isInstantiationDependent()) {
E = E->IgnoreParens();
Index: lib/AST/ASTDumper.cpp
===================================================================
--- lib/AST/ASTDumper.cpp
+++ lib/AST/ASTDumper.cpp
@@ -2272,6 +2272,9 @@
case UETT_SizeOf:
OS << " sizeof";
break;
+ case UETT_PreferredAlignOf:
+ OS << " __alignof";
+ break;
case UETT_AlignOf:
OS << " alignof";
break;
Index: include/clang/Basic/TypeTraits.h
===================================================================
--- include/clang/Basic/TypeTraits.h
+++ include/clang/Basic/TypeTraits.h
@@ -96,6 +96,12 @@
/// Names for the "expression or type" traits.
enum UnaryExprOrTypeTrait {
UETT_SizeOf,
+ /// Used for GCC's __alignof.
+ /// __alignof returns the preferred alignment of a type, the alignment
+ /// clang will attempt to give an object of the type if allowed by ABI.
+ UETT_PreferredAlignOf,
+ /// Used for C's _Alignof and C++'s alignof.
+ /// _Alignof and alignof return the required ABI alignment.
UETT_AlignOf,
UETT_VecStep,
UETT_OpenMPRequiredSimdAlign,
Index: include/clang/Basic/LangOptions.h
===================================================================
--- include/clang/Basic/LangOptions.h
+++ include/clang/Basic/LangOptions.h
@@ -124,6 +124,12 @@
/// whether we reuse base class tail padding in some ABIs.
Ver6,
+ /// Attempt to be ABI-compatible with code generated by Clang 7.0.x
+ /// (SVN r338536). This causes alignof (C++) and _Alignof (C11) to be
+ /// compatible with __alignof (i.e., return the preferred alignment)
+ /// rather than returning the required alignment.
+ Ver7,
+
/// Conform to the underlying platform's C and C++ ABIs as closely
/// as we can.
Latest
Index: include/clang/ASTMatchers/ASTMatchers.h
===================================================================
--- include/clang/ASTMatchers/ASTMatchers.h
+++ include/clang/ASTMatchers/ASTMatchers.h
@@ -2425,8 +2425,9 @@
/// alignof.
inline internal::Matcher<Stmt> alignOfExpr(
const internal::Matcher<UnaryExprOrTypeTraitExpr> &InnerMatcher) {
- return stmt(unaryExprOrTypeTraitExpr(allOf(
- ofKind(UETT_AlignOf), InnerMatcher)));
+ return stmt(unaryExprOrTypeTraitExpr(
+ allOf(anyOf(ofKind(UETT_AlignOf), ofKind(UETT_PreferredAlignOf)),
+ InnerMatcher)));
}
/// Same as unaryExprOrTypeTraitExpr, but only matching
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits