diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -247,6 +247,9 @@ the compilation of the foreign language sources (e.g. Swift). - The ``__has_attribute``, ``__has_c_attribute`` and ``__has_cpp_attribute`` preprocessor operators now return 1 also for attributes defined by plugins. +- Improve the AST fidelity of ``alignas`` and ``_Alignas`` attribute. Before, we + model ``alignas(type-id)`` as though the user wrote ``alignas(alignof(type-id))``, + now we directly use ``alignas(type-id)``. Improvements to Clang's diagnostics ----------------------------------- @@ -291,7 +294,10 @@ Clang ABI >= 15. (`#62353: `_, fallout from the non-POD packing ABI fix in LLVM 15). - +- Clang now correctly diagnoses when the argument to ``alignas`` or ``_Alignas`` + is an incomplete type. + (`#55175: `_, and fixes an + incorrect mention of ``alignof`` in a diagnostic about ``alignas``). Bug Fixes in This Version ------------------------- diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -3004,8 +3004,8 @@ SourceLocation EndLoc); void ParseAtomicSpecifier(DeclSpec &DS); - ExprResult ParseAlignArgument(SourceLocation Start, - SourceLocation &EllipsisLoc); + ExprResult ParseAlignArgument(StringRef KWName, SourceLocation Start, + SourceLocation &EllipsisLoc, bool &IsType, ParsedType &Ty); void ParseAlignmentSpecifier(ParsedAttributes &Attrs, SourceLocation *endLoc = nullptr); ExprResult ParseExtIntegerArgument(); diff --git a/clang/include/clang/Sema/ParsedAttr.h b/clang/include/clang/Sema/ParsedAttr.h --- a/clang/include/clang/Sema/ParsedAttr.h +++ b/clang/include/clang/Sema/ParsedAttr.h @@ -273,12 +273,13 @@ /// Constructor for attributes with a single type argument. ParsedAttr(IdentifierInfo *attrName, SourceRange attrRange, IdentifierInfo *scopeName, SourceLocation scopeLoc, - ParsedType typeArg, Form formUsed) + ParsedType typeArg, Form formUsed, SourceLocation ellipsisLoc) : AttributeCommonInfo(attrName, scopeName, attrRange, scopeLoc, formUsed), - NumArgs(0), Invalid(false), UsedAsTypeAttr(false), - IsAvailability(false), IsTypeTagForDatatype(false), IsProperty(false), - HasParsedType(true), HasProcessingCache(false), - IsPragmaClangAttribute(false), Info(ParsedAttrInfo::get(*this)) { + EllipsisLoc(ellipsisLoc), NumArgs(0), Invalid(false), + UsedAsTypeAttr(false), IsAvailability(false), + IsTypeTagForDatatype(false), IsProperty(false), HasParsedType(true), + HasProcessingCache(false), IsPragmaClangAttribute(false), + Info(ParsedAttrInfo::get(*this)) { new (&getTypeBuffer()) ParsedType(typeArg); } @@ -782,13 +783,13 @@ SourceRange attrRange, IdentifierInfo *scopeName, SourceLocation scopeLoc, ParsedType typeArg, - ParsedAttr::Form formUsed) { + ParsedAttr::Form formUsed, SourceLocation ellipsisLoc) { void *memory = allocate( ParsedAttr::totalSizeToAlloc(0, 0, 0, 1, 0)); return add(new (memory) ParsedAttr(attrName, attrRange, scopeName, scopeLoc, - typeArg, formUsed)); + typeArg, formUsed, ellipsisLoc)); } ParsedAttr * @@ -1001,9 +1002,9 @@ /// Add an attribute with a single type argument. ParsedAttr *addNewTypeAttr(IdentifierInfo *attrName, SourceRange attrRange, IdentifierInfo *scopeName, SourceLocation scopeLoc, - ParsedType typeArg, ParsedAttr::Form formUsed) { + ParsedType typeArg, ParsedAttr::Form formUsed, SourceLocation ellipsisLoc = SourceLocation()) { ParsedAttr *attr = pool.createTypeAttribute(attrName, attrRange, scopeName, - scopeLoc, typeArg, formUsed); + scopeLoc, typeArg, formUsed, ellipsisLoc); addAtEnd(attr); return attr; } diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -5723,10 +5723,13 @@ bool CheckTypeTraitArity(unsigned Arity, SourceLocation Loc, size_t N); + bool ActOnAlignasTypeArgument(StringRef KWName, ParsedType Ty, + SourceLocation OpLoc, SourceRange R); + ExprResult CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo, SourceLocation OpLoc, UnaryExprOrTypeTrait ExprKind, - SourceRange R); + StringRef KWName, SourceRange R); ExprResult CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc, UnaryExprOrTypeTrait ExprKind); ExprResult @@ -5741,7 +5744,8 @@ bool CheckUnaryExprOrTypeTraitOperand(Expr *E, UnaryExprOrTypeTrait ExprKind); bool CheckUnaryExprOrTypeTraitOperand(QualType ExprType, SourceLocation OpLoc, SourceRange ExprRange, - UnaryExprOrTypeTrait ExprKind); + UnaryExprOrTypeTrait ExprKind, + StringRef KWName); ExprResult ActOnSizeofParameterPackExpr(Scope *S, SourceLocation OpLoc, IdentifierInfo &Name, diff --git a/clang/lib/AST/AttrImpl.cpp b/clang/lib/AST/AttrImpl.cpp --- a/clang/lib/AST/AttrImpl.cpp +++ b/clang/lib/AST/AttrImpl.cpp @@ -239,4 +239,32 @@ } } +unsigned AlignedAttr::getAlignment(ASTContext &Ctx) const { + assert(!isAlignmentDependent()); + auto getAlignmentImpl = [&]() -> unsigned { + if (isAlignmentExpr()) { + return alignmentExpr + ? alignmentExpr->EvaluateKnownConstInt(Ctx).getZExtValue() * + Ctx.getCharWidth() + : Ctx.getTargetDefaultAlignForAttributeAligned(); + } + QualType T = getAlignmentType()->getType(); + // 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(); + + if (T.getQualifiers().hasUnaligned()) + return Ctx.getCharWidth(); + + return Ctx.getTypeAlignInChars(T.getTypePtr()).getQuantity() * + Ctx.getCharWidth(); + }; + if (!getCachedAlignmentValue()) + const_cast(this)->setCachedAlignmentValue( + getAlignmentImpl()); + return *alignmentCache; +} + #include "clang/AST/AttrImpl.inc" diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2984,24 +2984,25 @@ /// ParseAlignArgument - Parse the argument to an alignment-specifier. /// -/// FIXME: Simply returns an alignof() expression if the argument is a -/// type. Ideally, the type should be propagated directly into Sema. -/// /// [C11] type-id /// [C11] constant-expression /// [C++0x] type-id ...[opt] /// [C++0x] assignment-expression ...[opt] -ExprResult Parser::ParseAlignArgument(SourceLocation Start, - SourceLocation &EllipsisLoc) { +ExprResult Parser::ParseAlignArgument(StringRef KWName, SourceLocation Start, + SourceLocation &EllipsisLoc, bool &IsType, ParsedType &TypeResult) { ExprResult ER; if (isTypeIdInParens()) { SourceLocation TypeLoc = Tok.getLocation(); ParsedType Ty = ParseTypeName().get(); SourceRange TypeRange(Start, Tok.getLocation()); - ER = Actions.ActOnUnaryExprOrTypeTraitExpr(TypeLoc, UETT_AlignOf, true, - Ty.getAsOpaquePtr(), TypeRange); - } else + if (Actions.ActOnAlignasTypeArgument(KWName, Ty, TypeLoc, TypeRange)) + return ExprError(); + TypeResult = Ty; + IsType = true; + } else { ER = ParseConstantExpression(); + IsType = false; + } if (getLangOpts().CPlusPlus11) TryConsumeToken(tok::ellipsis, EllipsisLoc); @@ -3021,17 +3022,20 @@ SourceLocation *EndLoc) { assert(Tok.isOneOf(tok::kw_alignas, tok::kw__Alignas) && "Not an alignment-specifier!"); - - IdentifierInfo *KWName = Tok.getIdentifierInfo(); - auto Kind = Tok.getKind(); + Token KWTok = Tok; + IdentifierInfo *KWName = KWTok.getIdentifierInfo(); + auto Kind = KWTok.getKind(); SourceLocation KWLoc = ConsumeToken(); BalancedDelimiterTracker T(*this, tok::l_paren); if (T.expectAndConsume()) return; + bool IsType; + ParsedType TypeResult; SourceLocation EllipsisLoc; - ExprResult ArgExpr = ParseAlignArgument(T.getOpenLocation(), EllipsisLoc); + ExprResult ArgExpr = ParseAlignArgument(PP.getSpelling(KWTok), + T.getOpenLocation(), EllipsisLoc, IsType, TypeResult); if (ArgExpr.isInvalid()) { T.skipToEnd(); return; @@ -3041,10 +3045,15 @@ if (EndLoc) *EndLoc = T.getCloseLocation(); - ArgsVector ArgExprs; - ArgExprs.push_back(ArgExpr.get()); - Attrs.addNew(KWName, KWLoc, nullptr, KWLoc, ArgExprs.data(), 1, Kind, - EllipsisLoc); + if (IsType) { + Attrs.addNewTypeAttr(KWName, KWLoc, nullptr, KWLoc, TypeResult, Kind, + EllipsisLoc); + } else { + ArgsVector ArgExprs; + ArgExprs.push_back(ArgExpr.get()); + Attrs.addNew(KWName, KWLoc, nullptr, KWLoc, ArgExprs.data(), 1, Kind, + EllipsisLoc); + } } ExprResult Parser::ParseExtIntegerArgument() { diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -38,6 +38,7 @@ #include "clang/Sema/ParsedAttr.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/Sema.h" #include "clang/Sema/SemaInternal.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" @@ -4333,6 +4334,27 @@ } static void handleAlignedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (AL.hasParsedType()) { + const ParsedType &TypeArg = AL.getTypeArg(); + TypeSourceInfo *TInfo; + (void)S.GetTypeFromParser( + ParsedType::getFromOpaquePtr(TypeArg.getAsOpaquePtr()), &TInfo); + if (AL.isPackExpansion() && + !TInfo->getType()->containsUnexpandedParameterPack()) { + S.Diag(AL.getEllipsisLoc(), + diag::err_pack_expansion_without_parameter_packs); + return; + } + + if (!AL.isPackExpansion() && + S.DiagnoseUnexpandedParameterPack(TInfo->getTypeLoc().getBeginLoc(), + TInfo, Sema::UPPC_Expression)) + return; + + S.AddAlignedAttr(D, AL, TInfo, AL.isPackExpansion()); + return; + } + // check the attribute arguments. if (AL.getNumArgs() > 1) { S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1; @@ -4357,53 +4379,63 @@ S.AddAlignedAttr(D, AL, E, AL.isPackExpansion()); } +/// Perform checking of type validity +/// +/// C++11 [dcl.align]p1: +/// An alignment-specifier may be applied to a variable or to a class +/// data member, but it shall not be applied to a bit-field, a function +/// parameter, the formal parameter of a catch clause, or a variable +/// declared with the register storage class specifier. An +/// alignment-specifier may also be applied to the declaration of a class +/// or enumeration type. +/// CWG 2354: +/// CWG agreed to remove permission for alignas to be applied to +/// enumerations. +/// C11 6.7.5/2: +/// An alignment attribute shall not be specified in a declaration of +/// a typedef, or a bit-field, or a function, or a parameter, or an +/// object declared with the register storage-class specifier. +static bool validateAlignasAppliedType(Sema &S, Decl *D, + const AlignedAttr &Attr, + SourceLocation AttrLoc) { + int DiagKind = -1; + if (isa(D)) { + DiagKind = 0; + } else if (const auto *VD = dyn_cast(D)) { + if (VD->getStorageClass() == SC_Register) + DiagKind = 1; + if (VD->isExceptionVariable()) + DiagKind = 2; + } else if (const auto *FD = dyn_cast(D)) { + if (FD->isBitField()) + DiagKind = 3; + } else if (const auto *ED = dyn_cast(D)) { + if (ED->getLangOpts().CPlusPlus) + DiagKind = 4; + } else if (!isa(D)) { + S.Diag(AttrLoc, diag::err_attribute_wrong_decl_type) + << &Attr + << (Attr.isC11() ? ExpectedVariableOrField + : ExpectedVariableFieldOrTag); + return true; + } + if (DiagKind != -1) { + S.Diag(AttrLoc, diag::err_alignas_attribute_wrong_decl_type) + << &Attr << DiagKind; + return true; + } + return false; +} + void Sema::AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E, bool IsPackExpansion) { AlignedAttr TmpAttr(Context, CI, true, E); SourceLocation AttrLoc = CI.getLoc(); // C++11 alignas(...) and C11 _Alignas(...) have additional requirements. - if (TmpAttr.isAlignas()) { - // C++11 [dcl.align]p1: - // An alignment-specifier may be applied to a variable or to a class - // data member, but it shall not be applied to a bit-field, a function - // parameter, the formal parameter of a catch clause, or a variable - // declared with the register storage class specifier. An - // alignment-specifier may also be applied to the declaration of a class - // or enumeration type. - // CWG 2354: - // CWG agreed to remove permission for alignas to be applied to - // enumerations. - // C11 6.7.5/2: - // An alignment attribute shall not be specified in a declaration of - // a typedef, or a bit-field, or a function, or a parameter, or an - // object declared with the register storage-class specifier. - int DiagKind = -1; - if (isa(D)) { - DiagKind = 0; - } else if (const auto *VD = dyn_cast(D)) { - if (VD->getStorageClass() == SC_Register) - DiagKind = 1; - if (VD->isExceptionVariable()) - DiagKind = 2; - } else if (const auto *FD = dyn_cast(D)) { - if (FD->isBitField()) - DiagKind = 3; - } else if (const auto *ED = dyn_cast(D)) { - if (ED->getLangOpts().CPlusPlus) - DiagKind = 4; - } else if (!isa(D)) { - Diag(AttrLoc, diag::err_attribute_wrong_decl_type) << &TmpAttr - << (TmpAttr.isC11() ? ExpectedVariableOrField - : ExpectedVariableFieldOrTag); - return; - } - if (DiagKind != -1) { - Diag(AttrLoc, diag::err_alignas_attribute_wrong_decl_type) - << &TmpAttr << DiagKind; + if (TmpAttr.isAlignas() && + validateAlignasAppliedType(*this, D, TmpAttr, AttrLoc)) return; - } - } if (E->isValueDependent()) { // We can't support a dependent alignment on a non-dependent type, @@ -4480,15 +4512,55 @@ AlignedAttr *AA = ::new (Context) AlignedAttr(Context, CI, true, ICE.get()); AA->setPackExpansion(IsPackExpansion); + AA->setCachedAlignmentValue(static_cast(AlignVal * Context.getCharWidth())); D->addAttr(AA); } void Sema::AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI, TypeSourceInfo *TS, bool IsPackExpansion) { - // FIXME: Cache the number on the AL object if non-dependent? - // FIXME: Perform checking of type validity + AlignedAttr TmpAttr(Context, CI, false, TS); + SourceLocation AttrLoc = CI.getLoc(); + + // C++11 alignas(...) and C11 _Alignas(...) have additional requirements. + if (TmpAttr.isAlignas() && + validateAlignasAppliedType(*this, D, TmpAttr, AttrLoc)) + return; + + if (TS->getType()->isDependentType()) { + // We can't support a dependent alignment on a non-dependent type, + // because we have no way to model that a type is "type-dependent" + // but not dependent in any other way. + if (const auto *TND = dyn_cast(D)) { + if (!TND->getUnderlyingType()->isDependentType()) { + Diag(AttrLoc, diag::err_alignment_dependent_typedef_name) + << TS->getTypeLoc().getSourceRange(); + return; + } + } + + AlignedAttr *AA = ::new (Context) AlignedAttr(Context, CI, false, TS); + AA->setPackExpansion(IsPackExpansion); + D->addAttr(AA); + return; + } + + const auto *VD = dyn_cast(D); + unsigned AlignVal = TmpAttr.getAlignment(Context); + // On AIX, an aligned attribute can not decrease the alignment when applied + // to a variable declaration with vector type. + if (VD && Context.getTargetInfo().getTriple().isOSAIX()) { + const Type *Ty = VD->getType().getTypePtr(); + if (Ty->isVectorType() && + Context.toCharUnitsFromBits(AlignVal).getQuantity() < 16) { + Diag(VD->getLocation(), diag::warn_aligned_attr_underaligned) + << VD->getType() << 16; + return; + } + } + AlignedAttr *AA = ::new (Context) AlignedAttr(Context, CI, false, TS); AA->setPackExpansion(IsPackExpansion); + AA->setCachedAlignmentValue(AlignVal); D->addAttr(AA); } diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -4373,7 +4373,8 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType ExprType, SourceLocation OpLoc, SourceRange ExprRange, - UnaryExprOrTypeTrait ExprKind) { + UnaryExprOrTypeTrait ExprKind, + StringRef KWName) { if (ExprType->isDependentType()) return false; @@ -4403,12 +4404,11 @@ if (RequireCompleteSizedType( OpLoc, ExprType, diag::err_sizeof_alignof_incomplete_or_sizeless_type, - getTraitSpelling(ExprKind), ExprRange)) + KWName, ExprRange)) return true; if (ExprType->isFunctionType()) { - Diag(OpLoc, diag::err_sizeof_alignof_function_type) - << getTraitSpelling(ExprKind) << ExprRange; + Diag(OpLoc, diag::err_sizeof_alignof_function_type) << KWName << ExprRange; return true; } @@ -4597,18 +4597,18 @@ } /// Build a sizeof or alignof expression given a type operand. -ExprResult -Sema::CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo, - SourceLocation OpLoc, - UnaryExprOrTypeTrait ExprKind, - SourceRange R) { +ExprResult Sema::CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo, + SourceLocation OpLoc, + UnaryExprOrTypeTrait ExprKind, + StringRef KWName, + SourceRange R) { if (!TInfo) return ExprError(); QualType T = TInfo->getType(); if (!T->isDependentType() && - CheckUnaryExprOrTypeTraitOperand(T, OpLoc, R, ExprKind)) + CheckUnaryExprOrTypeTraitOperand(T, OpLoc, R, ExprKind, KWName)) return ExprError(); if (T->isVariablyModifiedType() && FunctionScopes.size() > 1) { @@ -4700,7 +4700,8 @@ if (IsType) { TypeSourceInfo *TInfo; (void) GetTypeFromParser(ParsedType::getFromOpaquePtr(TyOrEx), &TInfo); - return CreateUnaryExprOrTypeTraitExpr(TInfo, OpLoc, ExprKind, ArgRange); + return CreateUnaryExprOrTypeTraitExpr(TInfo, OpLoc, ExprKind, + getTraitSpelling(ExprKind), ArgRange); } Expr *ArgEx = (Expr *)TyOrEx; @@ -4708,6 +4709,22 @@ return Result; } +/// ActOnAlignasTypeArgument - Handle @c alignas(type-id) and @c +/// _Alignas(type-name) . +/// [dcl.align] An alignment-specifier of the form +/// alignas(type-id) has the same effect as alignas(alignof(type-id)). +/// +/// [N1570 6.7.5] _Alignas(type-name) is equivalent to +/// _Alignas(_Alignof(type-name)). +bool Sema::ActOnAlignasTypeArgument(StringRef KWName, ParsedType Ty, + SourceLocation OpLoc, SourceRange R) { + TypeSourceInfo *TInfo; + (void)GetTypeFromParser(ParsedType::getFromOpaquePtr(Ty.getAsOpaquePtr()), + &TInfo); + return CreateUnaryExprOrTypeTraitExpr(TInfo, OpLoc, UETT_AlignOf, KWName, R) + .isInvalid(); +} + static QualType CheckRealImagOperand(Sema &S, ExprResult &V, SourceLocation Loc, bool IsReal) { if (V.get()->isTypeDependent()) diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -2674,7 +2674,8 @@ SourceLocation OpLoc, UnaryExprOrTypeTrait ExprKind, SourceRange R) { - return getSema().CreateUnaryExprOrTypeTraitExpr(TInfo, OpLoc, ExprKind, R); + return getSema().CreateUnaryExprOrTypeTraitExpr( + TInfo, OpLoc, ExprKind, getTraitSpelling(ExprKind), R); } /// Build a new sizeof, alignof or vec step expression with an diff --git a/clang/test/Sema/aix-attr-aligned-vector-warn.c b/clang/test/Sema/aix-attr-aligned-vector-warn.c --- a/clang/test/Sema/aix-attr-aligned-vector-warn.c +++ b/clang/test/Sema/aix-attr-aligned-vector-warn.c @@ -6,6 +6,7 @@ typedef vector int __attribute__((aligned(8))) UnderAlignedVI; UnderAlignedVI TypedefedGlobal; +vector int V __attribute__((aligned(8))); // expected-warning {{requested alignment is less than minimum alignment of 16 for type '__vector int' (vector of 4 'int' values)}} vector int V __attribute__((aligned(8))); // expected-warning {{requested alignment is less than minimum alignment of 16 for type '__vector int' (vector of 4 'int' values)}} int localTypedefed(void) { diff --git a/clang/test/Sema/aix-attr-aligned-vector-warn.cpp b/clang/test/Sema/aix-attr-aligned-vector-warn.cpp new file mode 100644 --- /dev/null +++ b/clang/test/Sema/aix-attr-aligned-vector-warn.cpp @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -triple powerpc64-unknown-aix -target-feature +altivec -target-cpu pwr7 -verify -fsyntax-only %s +// RUN: %clang_cc1 -triple powerpc-unknown-aix -target-feature +altivec -target-cpu pwr7 -verify -fsyntax-only %s + +struct alignas(8) Align8 { + void *a, *b; +}; + +alignas(8) vector int V1; // expected-warning {{requested alignment is less than minimum alignment of 16 for type '__vector int' (vector of 4 'int' values)}} +alignas(Align8) vector int V2; // expected-warning {{requested alignment is less than minimum alignment of 16 for type '__vector int' (vector of 4 'int' values)}} diff --git a/clang/test/Sema/sizeless-1.c b/clang/test/Sema/sizeless-1.c --- a/clang/test/Sema/sizeless-1.c +++ b/clang/test/Sema/sizeless-1.c @@ -64,7 +64,7 @@ svint8_t __attribute__((aligned(4))) aligned_int8_2; // expected-error {{'aligned' attribute cannot be applied to sizeless type 'svint8_t'}} svint8_t _Alignas(int) aligned_int8_3; // expected-error {{'_Alignas' attribute cannot be applied to sizeless type 'svint8_t'}} - int _Alignas(svint8_t) aligned_int; // expected-error {{invalid application of 'alignof' to sizeless type 'svint8_t'}} + int _Alignas(svint8_t) aligned_int; // expected-error {{invalid application of '_Alignas' to sizeless type 'svint8_t'}} // Using pointers to sizeless data isn't wrong here, but because the // type is incomplete, it doesn't provide any alignment guarantees. diff --git a/clang/test/SemaCXX/attr-cxx0x.cpp b/clang/test/SemaCXX/attr-cxx0x.cpp --- a/clang/test/SemaCXX/attr-cxx0x.cpp +++ b/clang/test/SemaCXX/attr-cxx0x.cpp @@ -50,3 +50,6 @@ void func(void); alignas(4) auto PR19252 = 0; + +// Check the diagnostic message +class alignas(void) AlignasVoid {}; // expected-error {{invalid application of 'alignas' to an incomplete type 'void'}} diff --git a/clang/test/SemaCXX/builtin-align-cxx.cpp b/clang/test/SemaCXX/builtin-align-cxx.cpp --- a/clang/test/SemaCXX/builtin-align-cxx.cpp +++ b/clang/test/SemaCXX/builtin-align-cxx.cpp @@ -238,3 +238,6 @@ static_assert(!__builtin_is_aligned(static_cast(7), static_cast(4)), ""); static_assert(!__builtin_is_aligned(static_cast(7), static_cast(4)), ""); static_assert(!__builtin_is_aligned(static_cast(7), static_cast(4)), ""); + +// Check the diagnostic message +_Alignas(void) char align_void_array[1]; // expected-error {{invalid application of '_Alignas' to an incomplete type 'void'}} diff --git a/clang/test/SemaCXX/cxx11-attr-print.cpp b/clang/test/SemaCXX/cxx11-attr-print.cpp --- a/clang/test/SemaCXX/cxx11-attr-print.cpp +++ b/clang/test/SemaCXX/cxx11-attr-print.cpp @@ -28,7 +28,7 @@ // CHECK: int cxx11_alignas alignas(4); alignas(4) int cxx11_alignas; -// CHECK: int c11_alignas _Alignas(alignof(int)); +// CHECK: int c11_alignas _Alignas(int); _Alignas(int) int c11_alignas; // CHECK: void foo() __attribute__((const)); @@ -65,11 +65,13 @@ // CHECK: int m __attribute__((aligned(4 // CHECK: int n alignas(4 +// CHECK: int p alignas(int // CHECK: static int f() __attribute__((pure)) // CHECK: static int g() {{\[}}[gnu::pure]] template struct S { __attribute__((aligned(4))) int m; alignas(4) int n; + alignas(int) int p; __attribute__((pure)) static int f() { return 0; } diff --git a/clang/test/SemaCXX/sizeless-1.cpp b/clang/test/SemaCXX/sizeless-1.cpp --- a/clang/test/SemaCXX/sizeless-1.cpp +++ b/clang/test/SemaCXX/sizeless-1.cpp @@ -73,7 +73,7 @@ svint8_t __attribute__((aligned(4))) aligned_int8_2; // expected-error {{'aligned' attribute cannot be applied to sizeless type 'svint8_t'}} svint8_t _Alignas(int) aligned_int8_3; // expected-error {{'_Alignas' attribute cannot be applied to sizeless type 'svint8_t'}} - int _Alignas(svint8_t) aligned_int; // expected-error {{invalid application of 'alignof' to sizeless type 'svint8_t'}} + int _Alignas(svint8_t) aligned_int; // expected-error {{invalid application of '_Alignas' to sizeless type 'svint8_t'}} // Using pointers to sizeless data isn't wrong here, but because the // type is incomplete, it doesn't provide any alignment guarantees. diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp --- a/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -508,6 +508,16 @@ OS << " assert(!is" << getLowerName() << "Expr);\n"; OS << " return " << getLowerName() << "Type;\n"; OS << " }"; + + OS << " std::optional getCached" << getUpperName() + << "Value() const {\n"; + OS << " return " << getLowerName() << "Cache;\n"; + OS << " }"; + + OS << " void setCached" << getUpperName() + << "Value(unsigned AlignVal) {\n"; + OS << " " << getLowerName() << "Cache = AlignVal;\n"; + OS << " }"; } void writeAccessorDefinitions(raw_ostream &OS) const override { @@ -530,21 +540,6 @@ OS << " return " << getLowerName() << "Type->getType()->containsErrors();\n"; OS << "}\n"; - - // FIXME: Do not do the calculation here - // FIXME: Handle types correctly - // A null pointer means maximum alignment - OS << "unsigned " << getAttrName() << "Attr::get" << getUpperName() - << "(ASTContext &Ctx) const {\n"; - OS << " assert(!is" << getUpperName() << "Dependent());\n"; - OS << " if (is" << getLowerName() << "Expr)\n"; - OS << " return " << getLowerName() << "Expr ? " << getLowerName() - << "Expr->EvaluateKnownConstInt(Ctx).getZExtValue()" - << " * Ctx.getCharWidth() : " - << "Ctx.getTargetDefaultAlignForAttributeAligned();\n"; - OS << " else\n"; - OS << " return 0; // FIXME\n"; - OS << "}\n"; } void writeASTVisitorTraversal(raw_ostream &OS) const override { @@ -601,7 +596,8 @@ OS << "union {\n"; OS << "Expr *" << getLowerName() << "Expr;\n"; OS << "TypeSourceInfo *" << getLowerName() << "Type;\n"; - OS << "};"; + OS << "};\n"; + OS << "std::optional " << getLowerName() << "Cache;\n"; } void writePCHReadArgs(raw_ostream &OS) const override { @@ -628,14 +624,17 @@ } std::string getIsOmitted() const override { - return "!is" + getLowerName().str() + "Expr || !" + getLowerName().str() - + "Expr"; + return "!((is" + getLowerName().str() + "Expr && " + + getLowerName().str() + "Expr) || (!is" + getLowerName().str() + + "Expr && " + getLowerName().str() + "Type))"; } void writeValue(raw_ostream &OS) const override { OS << "\";\n"; - OS << " " << getLowerName() - << "Expr->printPretty(OS, nullptr, Policy);\n"; + OS << " if (is" << getLowerName() << "Expr && " << getLowerName() << "Expr)"; + OS << " " << getLowerName() << "Expr->printPretty(OS, nullptr, Policy);\n"; + OS << " if (!is" << getLowerName() << "Expr && " << getLowerName() << "Type)"; + OS << " " << getLowerName() << "Type->getType().print(OS, Policy);\n"; OS << " OS << \""; }