yronglin updated this revision to Diff 524159.
yronglin added a comment.
Update
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D150528/new/
https://reviews.llvm.org/D150528
Files:
clang/docs/ReleaseNotes.rst
clang/include/clang/Parse/Parser.h
clang/include/clang/Sema/ParsedAttr.h
clang/include/clang/Sema/Sema.h
clang/lib/AST/AttrImpl.cpp
clang/lib/Parse/ParseDecl.cpp
clang/lib/Sema/SemaDeclAttr.cpp
clang/lib/Sema/SemaExpr.cpp
clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
clang/test/AST/ast-dump-attr.cpp
clang/test/Sema/aix-attr-aligned-vector-warn.c
clang/test/Sema/aix-attr-aligned-vector-warn.cpp
clang/test/Sema/sizeless-1.c
clang/test/SemaCXX/attr-cxx0x.cpp
clang/test/SemaCXX/builtin-align-cxx.cpp
clang/test/SemaCXX/cxx11-attr-print.cpp
clang/test/SemaCXX/sizeless-1.cpp
clang/utils/TableGen/ClangAttrEmitter.cpp
Index: clang/utils/TableGen/ClangAttrEmitter.cpp
===================================================================
--- clang/utils/TableGen/ClangAttrEmitter.cpp
+++ clang/utils/TableGen/ClangAttrEmitter.cpp
@@ -508,6 +508,16 @@
OS << " assert(!is" << getLowerName() << "Expr);\n";
OS << " return " << getLowerName() << "Type;\n";
OS << " }";
+
+ OS << " std::optional<unsigned> 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<unsigned> " << 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 << \"";
}
Index: clang/test/SemaCXX/sizeless-1.cpp
===================================================================
--- clang/test/SemaCXX/sizeless-1.cpp
+++ 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.
Index: clang/test/SemaCXX/cxx11-attr-print.cpp
===================================================================
--- clang/test/SemaCXX/cxx11-attr-print.cpp
+++ 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 <typename T> struct S {
__attribute__((aligned(4))) int m;
alignas(4) int n;
+ alignas(int) int p;
__attribute__((pure)) static int f() {
return 0;
}
Index: clang/test/SemaCXX/builtin-align-cxx.cpp
===================================================================
--- clang/test/SemaCXX/builtin-align-cxx.cpp
+++ clang/test/SemaCXX/builtin-align-cxx.cpp
@@ -238,3 +238,6 @@
static_assert(!__builtin_is_aligned(static_cast<unsigned long>(7), static_cast<signed long>(4)), "");
static_assert(!__builtin_is_aligned(static_cast<signed long>(7), static_cast<unsigned short>(4)), "");
static_assert(!__builtin_is_aligned(static_cast<unsigned short>(7), static_cast<signed long>(4)), "");
+
+// Check the diagnostic message
+_Alignas(void) char align_void_array[1]; // expected-error {{invalid application of '_Alignas' to an incomplete type 'void'}}
Index: clang/test/SemaCXX/attr-cxx0x.cpp
===================================================================
--- clang/test/SemaCXX/attr-cxx0x.cpp
+++ 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'}}
Index: clang/test/Sema/sizeless-1.c
===================================================================
--- clang/test/Sema/sizeless-1.c
+++ 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.
Index: clang/test/Sema/aix-attr-aligned-vector-warn.cpp
===================================================================
--- /dev/null
+++ 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)}}
Index: clang/test/Sema/aix-attr-aligned-vector-warn.c
===================================================================
--- clang/test/Sema/aix-attr-aligned-vector-warn.c
+++ 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) {
Index: clang/test/AST/ast-dump-attr.cpp
===================================================================
--- clang/test/AST/ast-dump-attr.cpp
+++ clang/test/AST/ast-dump-attr.cpp
@@ -129,6 +129,38 @@
// CHECK-NEXT: AlignedAttr{{.*}} Inherited
}
+namespace TestAligns {
+
+template<typename...T> struct my_union {
+ alignas(T...) char buffer[1024];
+};
+
+template<typename...T> struct my_union2 {
+ _Alignas(T...) char buffer[1024];
+};
+
+struct alignas(8) A { char c; };
+struct alignas(4) B { short s; };
+struct C { char a[16]; };
+
+// CHECK: ClassTemplateSpecializationDecl {{.*}} struct my_union
+// CHECK: CXXRecordDecl {{.*}} implicit struct my_union
+// CHECK: FieldDecl {{.*}} buffer 'char[1024]'
+// CHECK-NEXT: AlignedAttr {{.*}} alignas 'TestAligns::A':'TestAligns::A'
+// CHECK-NEXT: AlignedAttr {{.*}} alignas 'TestAligns::B':'TestAligns::B'
+// CHECK-NEXT: AlignedAttr {{.*}} alignas 'TestAligns::C':'TestAligns::C'
+my_union<A, B, C> my_union_val;
+
+// CHECK: ClassTemplateSpecializationDecl {{.*}} struct my_union2
+// CHECK: CXXRecordDecl {{.*}} implicit struct my_union2
+// CHECK: FieldDecl {{.*}} buffer 'char[1024]'
+// CHECK-NEXT: AlignedAttr {{.*}} _Alignas 'TestAligns::A':'TestAligns::A'
+// CHECK-NEXT: AlignedAttr {{.*}} _Alignas 'TestAligns::B':'TestAligns::B'
+// CHECK-NEXT: AlignedAttr {{.*}} _Alignas 'TestAligns::C':'TestAligns::C'
+my_union2<A, B, C> my_union2_val;
+
+} // namespace TestAligns
+
int __attribute__((cdecl)) TestOne(void), TestTwo(void);
// CHECK: FunctionDecl{{.*}}TestOne{{.*}}__attribute__((cdecl))
// CHECK: FunctionDecl{{.*}}TestTwo{{.*}}__attribute__((cdecl))
Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -95,11 +95,14 @@
if (!Result.isInvalid())
S.AddAlignedAttr(New, *Aligned, Result.getAs<Expr>(), IsPackExpansion);
} else {
- TypeSourceInfo *Result = S.SubstType(Aligned->getAlignmentType(),
- TemplateArgs, Aligned->getLocation(),
- DeclarationName());
- if (Result)
- S.AddAlignedAttr(New, *Aligned, Result, IsPackExpansion);
+ if (TypeSourceInfo *Result =
+ S.SubstType(Aligned->getAlignmentType(), TemplateArgs,
+ Aligned->getLocation(), DeclarationName())) {
+ if (!S.CheckAlignasTypeArgument(Aligned->getSpelling(), Result,
+ Aligned->getLocation(),
+ Result->getTypeLoc().getSourceRange()))
+ S.AddAlignedAttr(New, *Aligned, Result, IsPackExpansion);
+ }
}
}
Index: clang/lib/Sema/SemaExpr.cpp
===================================================================
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -4355,70 +4355,6 @@
return false;
}
-/// Check the constraints on operands to unary expression and type
-/// traits.
-///
-/// This will complete any types necessary, and validate the various constraints
-/// on those operands.
-///
-/// The UsualUnaryConversions() function is *not* called by this routine.
-/// C99 6.3.2.1p[2-4] all state:
-/// Except when it is the operand of the sizeof operator ...
-///
-/// C++ [expr.sizeof]p4
-/// The lvalue-to-rvalue, array-to-pointer, and function-to-pointer
-/// standard conversions are not applied to the operand of sizeof.
-///
-/// This policy is followed for all of the unary trait expressions.
-bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType ExprType,
- SourceLocation OpLoc,
- SourceRange ExprRange,
- UnaryExprOrTypeTrait ExprKind) {
- if (ExprType->isDependentType())
- return false;
-
- // C++ [expr.sizeof]p2:
- // When applied to a reference or a reference type, the result
- // is the size of the referenced type.
- // C++11 [expr.alignof]p3:
- // When alignof is applied to a reference type, the result
- // shall be the alignment of the referenced type.
- if (const ReferenceType *Ref = ExprType->getAs<ReferenceType>())
- ExprType = Ref->getPointeeType();
-
- // 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_PreferredAlignOf ||
- ExprKind == UETT_OpenMPRequiredSimdAlign)
- ExprType = Context.getBaseElementType(ExprType);
-
- if (ExprKind == UETT_VecStep)
- return CheckVecStepTraitOperandType(*this, ExprType, OpLoc, ExprRange);
-
- // Explicitly list some types as extensions.
- if (!CheckExtensionTraitOperandType(*this, ExprType, OpLoc, ExprRange,
- ExprKind))
- return false;
-
- if (RequireCompleteSizedType(
- OpLoc, ExprType, diag::err_sizeof_alignof_incomplete_or_sizeless_type,
- getTraitSpelling(ExprKind), ExprRange))
- return true;
-
- if (ExprType->isFunctionType()) {
- Diag(OpLoc, diag::err_sizeof_alignof_function_type)
- << getTraitSpelling(ExprKind) << ExprRange;
- return true;
- }
-
- if (CheckObjCTraitOperandConstraints(*this, ExprType, OpLoc, ExprRange,
- ExprKind))
- return true;
-
- return false;
-}
-
static bool CheckAlignOfExpr(Sema &S, Expr *E, UnaryExprOrTypeTrait ExprKind) {
// Cannot know anything else if the expression is dependent.
if (E->isTypeDependent())
@@ -4596,23 +4532,69 @@
} while (!T.isNull() && T->isVariablyModifiedType());
}
-/// Build a sizeof or alignof expression given a type operand.
-ExprResult
-Sema::CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo,
- SourceLocation OpLoc,
- UnaryExprOrTypeTrait ExprKind,
- SourceRange R) {
- if (!TInfo)
- return ExprError();
+/// Check the constraints on operands to unary expression and type
+/// traits.
+///
+/// This will complete any types necessary, and validate the various constraints
+/// on those operands.
+///
+/// The UsualUnaryConversions() function is *not* called by this routine.
+/// C99 6.3.2.1p[2-4] all state:
+/// Except when it is the operand of the sizeof operator ...
+///
+/// C++ [expr.sizeof]p4
+/// The lvalue-to-rvalue, array-to-pointer, and function-to-pointer
+/// standard conversions are not applied to the operand of sizeof.
+///
+/// This policy is followed for all of the unary trait expressions.
+bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType ExprType,
+ SourceLocation OpLoc,
+ SourceRange ExprRange,
+ UnaryExprOrTypeTrait ExprKind,
+ StringRef KWName) {
+ if (ExprType->isDependentType())
+ return false;
- QualType T = TInfo->getType();
+ // C++ [expr.sizeof]p2:
+ // When applied to a reference or a reference type, the result
+ // is the size of the referenced type.
+ // C++11 [expr.alignof]p3:
+ // When alignof is applied to a reference type, the result
+ // shall be the alignment of the referenced type.
+ if (const ReferenceType *Ref = ExprType->getAs<ReferenceType>())
+ ExprType = Ref->getPointeeType();
- if (!T->isDependentType() &&
- CheckUnaryExprOrTypeTraitOperand(T, OpLoc, R, ExprKind))
- return ExprError();
+ // 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_PreferredAlignOf ||
+ ExprKind == UETT_OpenMPRequiredSimdAlign)
+ ExprType = Context.getBaseElementType(ExprType);
+
+ if (ExprKind == UETT_VecStep)
+ return CheckVecStepTraitOperandType(*this, ExprType, OpLoc, ExprRange);
+
+ // Explicitly list some types as extensions.
+ if (!CheckExtensionTraitOperandType(*this, ExprType, OpLoc, ExprRange,
+ ExprKind))
+ return false;
+
+ if (RequireCompleteSizedType(
+ OpLoc, ExprType, diag::err_sizeof_alignof_incomplete_or_sizeless_type,
+ KWName, ExprRange))
+ return true;
+
+ if (ExprType->isFunctionType()) {
+ Diag(OpLoc, diag::err_sizeof_alignof_function_type) << KWName << ExprRange;
+ return true;
+ }
+
+ if (CheckObjCTraitOperandConstraints(*this, ExprType, OpLoc, ExprRange,
+ ExprKind))
+ return true;
- if (T->isVariablyModifiedType() && FunctionScopes.size() > 1) {
- if (auto *TT = T->getAs<TypedefType>()) {
+ if (ExprType->isVariablyModifiedType() && FunctionScopes.size() > 1) {
+ if (auto *TT = ExprType->getAs<TypedefType>()) {
for (auto I = FunctionScopes.rbegin(),
E = std::prev(FunctionScopes.rend());
I != E; ++I) {
@@ -4629,17 +4611,37 @@
if (DC) {
if (DC->containsDecl(TT->getDecl()))
break;
- captureVariablyModifiedType(Context, T, CSI);
+ captureVariablyModifiedType(Context, ExprType, CSI);
}
}
}
}
- // C99 6.5.3.4p4: the type (an unsigned integer type) is size_t.
+ return false;
+}
+
+/// Build a sizeof or alignof expression given a type operand.
+ExprResult Sema::CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo,
+ SourceLocation OpLoc,
+ UnaryExprOrTypeTrait ExprKind,
+ SourceRange R) {
+ if (!TInfo)
+ return ExprError();
+
+ QualType T = TInfo->getType();
+
+ if (!T->isDependentType() &&
+ CheckUnaryExprOrTypeTraitOperand(T, OpLoc, R, ExprKind,
+ getTraitSpelling(ExprKind)))
+ return ExprError();
+
+ // Adds overload of TransformToPotentiallyEvaluated for TypeSourceInfo to
+ // properly deal with VLAs in nested calls of sizeof and typeof.
if (isUnevaluatedContext() && ExprKind == UETT_SizeOf &&
TInfo->getType()->isVariablyModifiedType())
TInfo = TransformToPotentiallyEvaluated(TInfo);
+ // C99 6.5.3.4p4: the type (an unsigned integer type) is size_t.
return new (Context) UnaryExprOrTypeTraitExpr(
ExprKind, TInfo, Context.getSizeType(), OpLoc, R.getEnd());
}
@@ -4708,6 +4710,29 @@
return Result;
}
+bool Sema::CheckAlignasTypeArgument(StringRef KWName, TypeSourceInfo *TInfo,
+ SourceLocation OpLoc, SourceRange R) {
+ if (!TInfo)
+ return true;
+ return CheckUnaryExprOrTypeTraitOperand(TInfo->getType(), OpLoc, R,
+ UETT_AlignOf, KWName);
+}
+
+/// 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 CheckAlignasTypeArgument(KWName, TInfo, OpLoc, R);
+}
+
static QualType CheckRealImagOperand(Sema &S, ExprResult &V, SourceLocation Loc,
bool IsReal) {
if (V.get()->isTypeDependent())
Index: clang/lib/Sema/SemaDeclAttr.cpp
===================================================================
--- clang/lib/Sema/SemaDeclAttr.cpp
+++ clang/lib/Sema/SemaDeclAttr.cpp
@@ -4333,6 +4333,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 +4378,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<ParmVarDecl>(D)) {
+ DiagKind = 0;
+ } else if (const auto *VD = dyn_cast<VarDecl>(D)) {
+ if (VD->getStorageClass() == SC_Register)
+ DiagKind = 1;
+ if (VD->isExceptionVariable())
+ DiagKind = 2;
+ } else if (const auto *FD = dyn_cast<FieldDecl>(D)) {
+ if (FD->isBitField())
+ DiagKind = 3;
+ } else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
+ if (ED->getLangOpts().CPlusPlus)
+ DiagKind = 4;
+ } else if (!isa<TagDecl>(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<ParmVarDecl>(D)) {
- DiagKind = 0;
- } else if (const auto *VD = dyn_cast<VarDecl>(D)) {
- if (VD->getStorageClass() == SC_Register)
- DiagKind = 1;
- if (VD->isExceptionVariable())
- DiagKind = 2;
- } else if (const auto *FD = dyn_cast<FieldDecl>(D)) {
- if (FD->isBitField())
- DiagKind = 3;
- } else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
- if (ED->getLangOpts().CPlusPlus)
- DiagKind = 4;
- } else if (!isa<TagDecl>(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 +4511,55 @@
AlignedAttr *AA = ::new (Context) AlignedAttr(Context, CI, true, ICE.get());
AA->setPackExpansion(IsPackExpansion);
+ AA->setCachedAlignmentValue(static_cast<unsigned>(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<TypedefNameDecl>(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<VarDecl>(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);
}
Index: clang/lib/Parse/ParseDecl.cpp
===================================================================
--- clang/lib/Parse/ParseDecl.cpp
+++ 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() {
Index: clang/lib/AST/AttrImpl.cpp
===================================================================
--- clang/lib/AST/AttrImpl.cpp
+++ clang/lib/AST/AttrImpl.cpp
@@ -239,4 +239,34 @@
}
}
+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<ReferenceType>())
+ T = Ref->getPointeeType();
+
+ if (T.getQualifiers().hasUnaligned())
+ return Ctx.getCharWidth();
+
+ return Ctx.getTypeAlignInChars(T.getTypePtr()).getQuantity() *
+ Ctx.getCharWidth();
+ };
+ if (!getCachedAlignmentValue())
+ const_cast<AlignedAttr *>(this)->setCachedAlignmentValue(
+ getAlignmentImpl());
+ return *alignmentCache;
+}
+
#include "clang/AST/AttrImpl.inc"
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -5723,6 +5723,11 @@
bool CheckTypeTraitArity(unsigned Arity, SourceLocation Loc, size_t N);
+ bool ActOnAlignasTypeArgument(StringRef KWName, ParsedType Ty,
+ SourceLocation OpLoc, SourceRange R);
+ bool CheckAlignasTypeArgument(StringRef KWName, TypeSourceInfo *TInfo,
+ SourceLocation OpLoc, SourceRange R);
+
ExprResult CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo,
SourceLocation OpLoc,
UnaryExprOrTypeTrait ExprKind,
@@ -5741,7 +5746,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,
Index: clang/include/clang/Sema/ParsedAttr.h
===================================================================
--- clang/include/clang/Sema/ParsedAttr.h
+++ 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<ArgsUnion, detail::AvailabilityData,
detail::TypeTagForDatatypeData, ParsedType,
detail::PropertyData>(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;
}
Index: clang/include/clang/Parse/Parser.h
===================================================================
--- clang/include/clang/Parse/Parser.h
+++ 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();
Index: clang/docs/ReleaseNotes.rst
===================================================================
--- clang/docs/ReleaseNotes.rst
+++ 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: <https://github.com/llvm/llvm-project/issues/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: <https://github.com/llvm/llvm-project/issues/55175>`_, and fixes an
+ incorrect mention of ``alignof`` in a diagnostic about ``alignas``).
Bug Fixes in This Version
-------------------------
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits