diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -276,7 +276,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 @@ -3000,7 +3000,7 @@ SourceLocation EndLoc); void ParseAtomicSpecifier(DeclSpec &DS); - ExprResult ParseAlignArgument(SourceLocation Start, + ExprResult ParseAlignArgument(StringRef KWName, SourceLocation Start, SourceLocation &EllipsisLoc); void ParseAlignmentSpecifier(ParsedAttributes &Attrs, SourceLocation *endLoc = nullptr); 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 @@ -5714,10 +5714,13 @@ bool CheckTypeTraitArity(unsigned Arity, SourceLocation Loc, size_t N); + ExprResult 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 @@ -5732,7 +5735,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/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2989,15 +2989,14 @@ /// [C11] constant-expression /// [C++0x] type-id ...[opt] /// [C++0x] assignment-expression ...[opt] -ExprResult Parser::ParseAlignArgument(SourceLocation Start, +ExprResult Parser::ParseAlignArgument(StringRef KWName, SourceLocation Start, SourceLocation &EllipsisLoc) { 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); + ER = Actions.ActOnAlignasTypeArgument(KWName, Ty, TypeLoc, TypeRange); } else ER = ParseConstantExpression(); @@ -3019,9 +3018,9 @@ 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); @@ -3029,7 +3028,8 @@ return; SourceLocation EllipsisLoc; - ExprResult ArgExpr = ParseAlignArgument(T.getOpenLocation(), EllipsisLoc); + ExprResult ArgExpr = ParseAlignArgument(PP.getSpelling(KWTok), + T.getOpenLocation(), EllipsisLoc); if (ArgExpr.isInvalid()) { T.skipToEnd(); return; 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,23 @@ 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)). +ExprResult Sema::ActOnAlignasTypeArgument(StringRef KWName, ParsedType Ty, + SourceLocation OpLoc, SourceRange R) { + TypeSourceInfo *TInfo; + (void)GetTypeFromParser(ParsedType::getFromOpaquePtr(Ty.getAsOpaquePtr()), + &TInfo); + // FIXME: this loses AST fidelity because we model alignas(type) as though + // the user wrote alignas(alignof(type)). + return CreateUnaryExprOrTypeTraitExpr(TInfo, OpLoc, UETT_AlignOf, KWName, R); +} + 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/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/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.