Skip to content

Commit f75b735

Browse files
committed
[Clang][Attribute] Improve the AST/diagnoses fidelity of alignas and _Alignas
- Fix diagnoses when the argument to `alignas` or `_Alignas` is an incomplete type. Before: ``` ./alignas.cpp:1:15: error: invalid application of 'alignof' to an incomplete type 'void' class alignas(void) Foo {}; ~^~~~~ 1 error generated. ``` Now: ``` ./alignas.cpp:1:15: error: invalid application of 'alignas' to an incomplete type 'void' class alignas(void) Foo {}; ~^~~~~ 1 error generated. ``` - Improve the AST fidelity of `alignas` and `_Alignas` attribute. Before: ``` AlignedAttr 0x13f07f278 <col:7> alignas `-ConstantExpr 0x13f07f258 <col:15, col:21> 'unsigned long' |-value: Int 8 `-UnaryExprOrTypeTraitExpr 0x13f07f118 <col:15, col:21> 'unsigned long' alignof 'void *' ``` Now: ``` AlignedAttr 0x14288c608 <col:7> alignas 'void *' ``` Reviewed By: erichkeane Differential Revision: https://reviews.llvm.org/D150528
1 parent a2b677e commit f75b735

19 files changed

+389
-181
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,9 @@ Attribute Changes in Clang
256256
the compilation of the foreign language sources (e.g. Swift).
257257
- The ``__has_attribute``, ``__has_c_attribute`` and ``__has_cpp_attribute``
258258
preprocessor operators now return 1 also for attributes defined by plugins.
259+
- Improve the AST fidelity of ``alignas`` and ``_Alignas`` attribute. Before, we
260+
model ``alignas(type-id)`` as though the user wrote ``alignas(alignof(type-id))``,
261+
now we directly use ``alignas(type-id)``.
259262

260263
Improvements to Clang's diagnostics
261264
-----------------------------------
@@ -307,6 +310,10 @@ Improvements to Clang's diagnostics
307310
(`#62850: <https://github.com/llvm/llvm-project/issues/62850>`_).
308311
- Clang now warns when any predefined macro is undefined or redefined, instead
309312
of only some of them.
313+
- Clang now correctly diagnoses when the argument to ``alignas`` or ``_Alignas``
314+
is an incomplete type.
315+
(`#55175: <https://github.com/llvm/llvm-project/issues/55175>`_, and fixes an
316+
incorrect mention of ``alignof`` in a diagnostic about ``alignas``).
310317

311318
Bug Fixes in This Version
312319
-------------------------

clang/include/clang/Parse/Parser.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3004,8 +3004,9 @@ class Parser : public CodeCompletionHandler {
30043004
SourceLocation EndLoc);
30053005
void ParseAtomicSpecifier(DeclSpec &DS);
30063006

3007-
ExprResult ParseAlignArgument(SourceLocation Start,
3008-
SourceLocation &EllipsisLoc);
3007+
ExprResult ParseAlignArgument(StringRef KWName, SourceLocation Start,
3008+
SourceLocation &EllipsisLoc, bool &IsType,
3009+
ParsedType &Ty);
30093010
void ParseAlignmentSpecifier(ParsedAttributes &Attrs,
30103011
SourceLocation *endLoc = nullptr);
30113012
ExprResult ParseExtIntegerArgument();

clang/include/clang/Sema/ParsedAttr.h

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -273,12 +273,13 @@ class ParsedAttr final
273273
/// Constructor for attributes with a single type argument.
274274
ParsedAttr(IdentifierInfo *attrName, SourceRange attrRange,
275275
IdentifierInfo *scopeName, SourceLocation scopeLoc,
276-
ParsedType typeArg, Form formUsed)
276+
ParsedType typeArg, Form formUsed, SourceLocation ellipsisLoc)
277277
: AttributeCommonInfo(attrName, scopeName, attrRange, scopeLoc, formUsed),
278-
NumArgs(0), Invalid(false), UsedAsTypeAttr(false),
279-
IsAvailability(false), IsTypeTagForDatatype(false), IsProperty(false),
280-
HasParsedType(true), HasProcessingCache(false),
281-
IsPragmaClangAttribute(false), Info(ParsedAttrInfo::get(*this)) {
278+
EllipsisLoc(ellipsisLoc), NumArgs(0), Invalid(false),
279+
UsedAsTypeAttr(false), IsAvailability(false),
280+
IsTypeTagForDatatype(false), IsProperty(false), HasParsedType(true),
281+
HasProcessingCache(false), IsPragmaClangAttribute(false),
282+
Info(ParsedAttrInfo::get(*this)) {
282283
new (&getTypeBuffer()) ParsedType(typeArg);
283284
}
284285

@@ -782,13 +783,14 @@ class AttributePool {
782783
SourceRange attrRange,
783784
IdentifierInfo *scopeName,
784785
SourceLocation scopeLoc, ParsedType typeArg,
785-
ParsedAttr::Form formUsed) {
786+
ParsedAttr::Form formUsed,
787+
SourceLocation ellipsisLoc) {
786788
void *memory = allocate(
787789
ParsedAttr::totalSizeToAlloc<ArgsUnion, detail::AvailabilityData,
788790
detail::TypeTagForDatatypeData, ParsedType,
789791
detail::PropertyData>(0, 0, 0, 1, 0));
790792
return add(new (memory) ParsedAttr(attrName, attrRange, scopeName, scopeLoc,
791-
typeArg, formUsed));
793+
typeArg, formUsed, ellipsisLoc));
792794
}
793795

794796
ParsedAttr *
@@ -1001,9 +1003,11 @@ class ParsedAttributes : public ParsedAttributesView {
10011003
/// Add an attribute with a single type argument.
10021004
ParsedAttr *addNewTypeAttr(IdentifierInfo *attrName, SourceRange attrRange,
10031005
IdentifierInfo *scopeName, SourceLocation scopeLoc,
1004-
ParsedType typeArg, ParsedAttr::Form formUsed) {
1005-
ParsedAttr *attr = pool.createTypeAttribute(attrName, attrRange, scopeName,
1006-
scopeLoc, typeArg, formUsed);
1006+
ParsedType typeArg, ParsedAttr::Form formUsed,
1007+
SourceLocation ellipsisLoc = SourceLocation()) {
1008+
ParsedAttr *attr =
1009+
pool.createTypeAttribute(attrName, attrRange, scopeName, scopeLoc,
1010+
typeArg, formUsed, ellipsisLoc);
10071011
addAtEnd(attr);
10081012
return attr;
10091013
}

clang/include/clang/Sema/Sema.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5720,6 +5720,11 @@ class Sema final {
57205720

57215721
bool CheckTypeTraitArity(unsigned Arity, SourceLocation Loc, size_t N);
57225722

5723+
bool ActOnAlignasTypeArgument(StringRef KWName, ParsedType Ty,
5724+
SourceLocation OpLoc, SourceRange R);
5725+
bool CheckAlignasTypeArgument(StringRef KWName, TypeSourceInfo *TInfo,
5726+
SourceLocation OpLoc, SourceRange R);
5727+
57235728
ExprResult CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo,
57245729
SourceLocation OpLoc,
57255730
UnaryExprOrTypeTrait ExprKind,
@@ -5738,7 +5743,8 @@ class Sema final {
57385743
bool CheckUnaryExprOrTypeTraitOperand(Expr *E, UnaryExprOrTypeTrait ExprKind);
57395744
bool CheckUnaryExprOrTypeTraitOperand(QualType ExprType, SourceLocation OpLoc,
57405745
SourceRange ExprRange,
5741-
UnaryExprOrTypeTrait ExprKind);
5746+
UnaryExprOrTypeTrait ExprKind,
5747+
StringRef KWName);
57425748
ExprResult ActOnSizeofParameterPackExpr(Scope *S,
57435749
SourceLocation OpLoc,
57445750
IdentifierInfo &Name,

clang/lib/AST/AttrImpl.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,4 +239,33 @@ void OMPDeclareVariantAttr::printPrettyPragma(
239239
}
240240
}
241241

242+
unsigned AlignedAttr::getAlignment(ASTContext &Ctx) const {
243+
assert(!isAlignmentDependent());
244+
if (getCachedAlignmentValue())
245+
return *getCachedAlignmentValue();
246+
247+
// Handle alignmentType case.
248+
if (!isAlignmentExpr()) {
249+
QualType T = getAlignmentType()->getType();
250+
251+
// C++ [expr.alignof]p3:
252+
// When alignof is applied to a reference type, the result is the
253+
// alignment of the referenced type.
254+
T = T.getNonReferenceType();
255+
256+
if (T.getQualifiers().hasUnaligned())
257+
return Ctx.getCharWidth();
258+
259+
return Ctx.getTypeAlignInChars(T.getTypePtr()).getQuantity() *
260+
Ctx.getCharWidth();
261+
}
262+
263+
// Handle alignmentExpr case.
264+
if (alignmentExpr)
265+
return alignmentExpr->EvaluateKnownConstInt(Ctx).getZExtValue() *
266+
Ctx.getCharWidth();
267+
268+
return Ctx.getTargetDefaultAlignForAttributeAligned();
269+
}
270+
242271
#include "clang/AST/AttrImpl.inc"

clang/lib/AST/ExprConstant.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9025,8 +9025,7 @@ static CharUnits GetAlignOfType(EvalInfo &Info, QualType T,
90259025
// C++ [expr.alignof]p3:
90269026
// When alignof is applied to a reference type, the result is the
90279027
// alignment of the referenced type.
9028-
if (const ReferenceType *Ref = T->getAs<ReferenceType>())
9029-
T = Ref->getPointeeType();
9028+
T = T.getNonReferenceType();
90309029

90319030
if (T.getQualifiers().hasUnaligned())
90329031
return CharUnits::One();

clang/lib/Parse/ParseDecl.cpp

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2984,24 +2984,26 @@ Parser::getDeclSpecContextFromDeclaratorContext(DeclaratorContext Context) {
29842984

29852985
/// ParseAlignArgument - Parse the argument to an alignment-specifier.
29862986
///
2987-
/// FIXME: Simply returns an alignof() expression if the argument is a
2988-
/// type. Ideally, the type should be propagated directly into Sema.
2989-
///
29902987
/// [C11] type-id
29912988
/// [C11] constant-expression
29922989
/// [C++0x] type-id ...[opt]
29932990
/// [C++0x] assignment-expression ...[opt]
2994-
ExprResult Parser::ParseAlignArgument(SourceLocation Start,
2995-
SourceLocation &EllipsisLoc) {
2991+
ExprResult Parser::ParseAlignArgument(StringRef KWName, SourceLocation Start,
2992+
SourceLocation &EllipsisLoc, bool &IsType,
2993+
ParsedType &TypeResult) {
29962994
ExprResult ER;
29972995
if (isTypeIdInParens()) {
29982996
SourceLocation TypeLoc = Tok.getLocation();
29992997
ParsedType Ty = ParseTypeName().get();
30002998
SourceRange TypeRange(Start, Tok.getLocation());
3001-
ER = Actions.ActOnUnaryExprOrTypeTraitExpr(TypeLoc, UETT_AlignOf, true,
3002-
Ty.getAsOpaquePtr(), TypeRange);
3003-
} else
2999+
if (Actions.ActOnAlignasTypeArgument(KWName, Ty, TypeLoc, TypeRange))
3000+
return ExprError();
3001+
TypeResult = Ty;
3002+
IsType = true;
3003+
} else {
30043004
ER = ParseConstantExpression();
3005+
IsType = false;
3006+
}
30053007

30063008
if (getLangOpts().CPlusPlus11)
30073009
TryConsumeToken(tok::ellipsis, EllipsisLoc);
@@ -3021,17 +3023,21 @@ void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs,
30213023
SourceLocation *EndLoc) {
30223024
assert(Tok.isOneOf(tok::kw_alignas, tok::kw__Alignas) &&
30233025
"Not an alignment-specifier!");
3024-
3025-
IdentifierInfo *KWName = Tok.getIdentifierInfo();
3026-
auto Kind = Tok.getKind();
3026+
Token KWTok = Tok;
3027+
IdentifierInfo *KWName = KWTok.getIdentifierInfo();
3028+
auto Kind = KWTok.getKind();
30273029
SourceLocation KWLoc = ConsumeToken();
30283030

30293031
BalancedDelimiterTracker T(*this, tok::l_paren);
30303032
if (T.expectAndConsume())
30313033
return;
30323034

3035+
bool IsType;
3036+
ParsedType TypeResult;
30333037
SourceLocation EllipsisLoc;
3034-
ExprResult ArgExpr = ParseAlignArgument(T.getOpenLocation(), EllipsisLoc);
3038+
ExprResult ArgExpr =
3039+
ParseAlignArgument(PP.getSpelling(KWTok), T.getOpenLocation(),
3040+
EllipsisLoc, IsType, TypeResult);
30353041
if (ArgExpr.isInvalid()) {
30363042
T.skipToEnd();
30373043
return;
@@ -3041,10 +3047,15 @@ void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs,
30413047
if (EndLoc)
30423048
*EndLoc = T.getCloseLocation();
30433049

3044-
ArgsVector ArgExprs;
3045-
ArgExprs.push_back(ArgExpr.get());
3046-
Attrs.addNew(KWName, KWLoc, nullptr, KWLoc, ArgExprs.data(), 1, Kind,
3047-
EllipsisLoc);
3050+
if (IsType) {
3051+
Attrs.addNewTypeAttr(KWName, KWLoc, nullptr, KWLoc, TypeResult, Kind,
3052+
EllipsisLoc);
3053+
} else {
3054+
ArgsVector ArgExprs;
3055+
ArgExprs.push_back(ArgExpr.get());
3056+
Attrs.addNew(KWName, KWLoc, nullptr, KWLoc, ArgExprs.data(), 1, Kind,
3057+
EllipsisLoc);
3058+
}
30483059
}
30493060

30503061
ExprResult Parser::ParseExtIntegerArgument() {

0 commit comments

Comments
 (0)