From d9e2dcdb424f761f7148db63d7ed9cd6ae40c2fe Mon Sep 17 00:00:00 2001 From: Denis Zobnin Date: Tue, 2 Feb 2016 13:50:39 +0000 Subject: [PATCH] Fix for PR8901: attribute "mode" rejected for enums and dependent types. Allow "mode" attribute for enum types, except for vector modes, for compatibility with GCC. Support "mode" attribute with dependent types. Differential Revision: http://reviews.llvm.org/D16219 llvm-svn: 259497 --- clang/include/clang/Basic/Attr.td | 4 +- clang/include/clang/Basic/DiagnosticSemaKinds.td | 4 +- clang/include/clang/Sema/AttributeList.h | 2 +- clang/include/clang/Sema/Sema.h | 4 + clang/lib/Sema/SemaDeclAttr.cpp | 105 +++++++++++++------- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 13 +++ clang/test/CodeGen/attr-mode-enums.c | 45 +++++++++ .../CodeGenCXX/attr-mode-vector-types-tmpl.cpp | 108 +++++++++++++++++++++ clang/test/Sema/attr-mode-enums.c | 51 ++++++++++ clang/test/Sema/attr-mode.c | 4 +- clang/test/SemaCXX/attr-mode-tmpl.cpp | 104 ++++++++++++++++++++ 11 files changed, 403 insertions(+), 41 deletions(-) create mode 100644 clang/test/CodeGen/attr-mode-enums.c create mode 100644 clang/test/CodeGenCXX/attr-mode-vector-types-tmpl.cpp create mode 100644 clang/test/Sema/attr-mode-enums.c create mode 100644 clang/test/SemaCXX/attr-mode-tmpl.cpp diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index dbb83e2..534370b 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -879,8 +879,8 @@ def MipsInterrupt : InheritableAttr, TargetSpecificAttr { def Mode : Attr { let Spellings = [GCC<"mode">]; - let Subjects = SubjectList<[Var, TypedefName, Field], ErrorDiag, - "ExpectedVariableFieldOrTypedef">; + let Subjects = SubjectList<[Var, Enum, TypedefName, Field], ErrorDiag, + "ExpectedVariableEnumFieldOrTypedef">; let Args = [IdentifierArgument<"Mode">]; let Documentation = [Undocumented]; } diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 1d21454..2f059c6 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2448,7 +2448,7 @@ def warn_attribute_wrong_decl_type : Warning< "variables, functions and classes|Objective-C protocols|" "functions and global variables|structs, unions, and typedefs|structs and typedefs|" "interface or protocol declarations|kernel functions|non-K&R-style functions|" - "variables, fields and typedefs}1">, + "variables, enums, fields and typedefs}1">, InGroup; def err_attribute_wrong_decl_type : Error; def warn_type_attribute_wrong_type : Warning< @@ -2858,6 +2858,8 @@ def warn_vector_mode_deprecated : Warning< InGroup; def err_complex_mode_vector_type : Error< "type of machine mode does not support base vector types">; +def err_enum_mode_vector_type : Error< + "mode %0 is not supported for enumeration types">; def warn_attribute_nonnull_no_pointers : Warning< "'nonnull' attribute applied to function with no pointer arguments">, InGroup; diff --git a/clang/include/clang/Sema/AttributeList.h b/clang/include/clang/Sema/AttributeList.h index 1a53a2c..3450680 100644 --- a/clang/include/clang/Sema/AttributeList.h +++ b/clang/include/clang/Sema/AttributeList.h @@ -856,7 +856,7 @@ enum AttributeDeclKind { ExpectedObjectiveCInterfaceOrProtocol, ExpectedKernelFunction, ExpectedFunctionWithProtoType, - ExpectedVariableFieldOrTypedef + ExpectedVariableEnumFieldOrTypedef }; } // end namespace clang diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 074bcf2..745dca8 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -7750,6 +7750,10 @@ public: void AddLaunchBoundsAttr(SourceRange AttrRange, Decl *D, Expr *MaxThreads, Expr *MinBlocks, unsigned SpellingListIndex); + /// AddModeAttr - Adds a mode attribute to a particular declaration. + void AddModeAttr(SourceRange AttrRange, Decl *D, IdentifierInfo *Name, + unsigned SpellingListIndex, bool InInstantiation = false); + //===--------------------------------------------------------------------===// // C++ Coroutines TS // diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index eb8a49c..81a57b2 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -3297,6 +3297,8 @@ bool Sema::checkMSInheritanceAttrOnDefinition( /// attribute. static void parseModeAttrArg(Sema &S, StringRef Str, unsigned &DestWidth, bool &IntegerMode, bool &ComplexMode) { + IntegerMode = true; + ComplexMode = false; switch (Str.size()) { case 2: switch (Str[0]) { @@ -3363,9 +3365,15 @@ static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) { } IdentifierInfo *Name = Attr.getArgAsIdent(0)->Ident; - StringRef Str = Name->getName(); + S.AddModeAttr(Attr.getRange(), D, Name, Attr.getAttributeSpellingListIndex()); +} + +void Sema::AddModeAttr(SourceRange AttrRange, Decl *D, IdentifierInfo *Name, + unsigned SpellingListIndex, bool InInstantiation) { + StringRef Str = Name->getName(); normalizeName(Str); + SourceLocation AttrLoc = AttrRange.getBegin(); unsigned DestWidth = 0; bool IntegerMode = true; @@ -3381,99 +3389,126 @@ static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (VectorStringLength && !Str.substr(1, VectorStringLength).getAsInteger(10, VectorSize) && VectorSize.isPowerOf2()) { - parseModeAttrArg(S, Str.substr(VectorStringLength + 1), DestWidth, + parseModeAttrArg(*this, Str.substr(VectorStringLength + 1), DestWidth, IntegerMode, ComplexMode); - S.Diag(Attr.getLoc(), diag::warn_vector_mode_deprecated); + // Avoid duplicate warning from template instantiation. + if (!InInstantiation) + Diag(AttrLoc, diag::warn_vector_mode_deprecated); } else { VectorSize = 0; } } if (!VectorSize) - parseModeAttrArg(S, Str, DestWidth, IntegerMode, ComplexMode); + parseModeAttrArg(*this, Str, DestWidth, IntegerMode, ComplexMode); + + // FIXME: Sync this with InitializePredefinedMacros; we need to match int8_t + // and friends, at least with glibc. + // FIXME: Make sure floating-point mappings are accurate + // FIXME: Support XF and TF types + if (!DestWidth) { + Diag(AttrLoc, diag::err_machine_mode) << 0 /*Unknown*/ << Name; + return; + } QualType OldTy; if (TypedefNameDecl *TD = dyn_cast(D)) OldTy = TD->getUnderlyingType(); - else + else if (EnumDecl *ED = dyn_cast(D)) { + // Something like 'typedef enum { X } __attribute__((mode(XX))) T;'. + // Try to get type from enum declaration, default to int. + OldTy = ED->getIntegerType(); + if (OldTy.isNull()) + OldTy = Context.IntTy; + } else OldTy = cast(D)->getType(); + if (OldTy->isDependentType()) { + D->addAttr(::new (Context) + ModeAttr(AttrRange, Context, Name, SpellingListIndex)); + return; + } + // Base type can also be a vector type (see PR17453). // Distinguish between base type and base element type. QualType OldElemTy = OldTy; if (const VectorType *VT = OldTy->getAs()) OldElemTy = VT->getElementType(); - if (!OldElemTy->getAs() && !OldElemTy->isComplexType()) - S.Diag(Attr.getLoc(), diag::err_mode_not_primitive); + // GCC allows 'mode' attribute on enumeration types (even incomplete), except + // for vector modes. So, 'enum X __attribute__((mode(QI)));' forms a complete + // type, 'enum { A } __attribute__((mode(V4SI)))' is rejected. + if ((isa(D) || OldElemTy->getAs()) && + VectorSize.getBoolValue()) { + Diag(AttrLoc, diag::err_enum_mode_vector_type) << Name << AttrRange; + return; + } + bool IntegralOrAnyEnumType = + OldElemTy->isIntegralOrEnumerationType() || OldElemTy->getAs(); + + if (!OldElemTy->getAs() && !OldElemTy->isComplexType() && + !IntegralOrAnyEnumType) + Diag(AttrLoc, diag::err_mode_not_primitive); else if (IntegerMode) { - if (!OldElemTy->isIntegralOrEnumerationType()) - S.Diag(Attr.getLoc(), diag::err_mode_wrong_type); + if (!IntegralOrAnyEnumType) + Diag(AttrLoc, diag::err_mode_wrong_type); } else if (ComplexMode) { if (!OldElemTy->isComplexType()) - S.Diag(Attr.getLoc(), diag::err_mode_wrong_type); + Diag(AttrLoc, diag::err_mode_wrong_type); } else { if (!OldElemTy->isFloatingType()) - S.Diag(Attr.getLoc(), diag::err_mode_wrong_type); - } - - // FIXME: Sync this with InitializePredefinedMacros; we need to match int8_t - // and friends, at least with glibc. - // FIXME: Make sure floating-point mappings are accurate - // FIXME: Support XF and TF types - if (!DestWidth) { - S.Diag(Attr.getLoc(), diag::err_machine_mode) << 0 /*Unknown*/ << Name; - return; + Diag(AttrLoc, diag::err_mode_wrong_type); } QualType NewElemTy; if (IntegerMode) - NewElemTy = S.Context.getIntTypeForBitwidth( - DestWidth, OldElemTy->isSignedIntegerType()); + NewElemTy = Context.getIntTypeForBitwidth(DestWidth, + OldElemTy->isSignedIntegerType()); else - NewElemTy = S.Context.getRealTypeForBitwidth(DestWidth); + NewElemTy = Context.getRealTypeForBitwidth(DestWidth); if (NewElemTy.isNull()) { - S.Diag(Attr.getLoc(), diag::err_machine_mode) << 1 /*Unsupported*/ << Name; + Diag(AttrLoc, diag::err_machine_mode) << 1 /*Unsupported*/ << Name; return; } if (ComplexMode) { - NewElemTy = S.Context.getComplexType(NewElemTy); + NewElemTy = Context.getComplexType(NewElemTy); } QualType NewTy = NewElemTy; if (VectorSize.getBoolValue()) { - NewTy = S.Context.getVectorType(NewTy, VectorSize.getZExtValue(), - VectorType::GenericVector); + NewTy = Context.getVectorType(NewTy, VectorSize.getZExtValue(), + VectorType::GenericVector); } else if (const VectorType *OldVT = OldTy->getAs()) { // Complex machine mode does not support base vector types. if (ComplexMode) { - S.Diag(Attr.getLoc(), diag::err_complex_mode_vector_type); + Diag(AttrLoc, diag::err_complex_mode_vector_type); return; } - unsigned NumElements = S.Context.getTypeSize(OldElemTy) * + unsigned NumElements = Context.getTypeSize(OldElemTy) * OldVT->getNumElements() / - S.Context.getTypeSize(NewElemTy); + Context.getTypeSize(NewElemTy); NewTy = - S.Context.getVectorType(NewElemTy, NumElements, OldVT->getVectorKind()); + Context.getVectorType(NewElemTy, NumElements, OldVT->getVectorKind()); } if (NewTy.isNull()) { - S.Diag(Attr.getLoc(), diag::err_mode_wrong_type); + Diag(AttrLoc, diag::err_mode_wrong_type); return; } // Install the new type. if (TypedefNameDecl *TD = dyn_cast(D)) TD->setModedTypeSourceInfo(TD->getTypeSourceInfo(), NewTy); + else if (EnumDecl *ED = dyn_cast(D)) + ED->setIntegerType(NewTy); else cast(D)->setType(NewTy); - D->addAttr(::new (S.Context) - ModeAttr(Attr.getRange(), S.Context, Name, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (Context) + ModeAttr(AttrRange, Context, Name, SpellingListIndex)); } static void handleNoDebugAttr(Sema &S, Decl *D, const AttributeList &Attr) { diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 9403dd9..625760c 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -227,6 +227,14 @@ static void instantiateDependentCUDALaunchBoundsAttr( Attr.getSpellingListIndex()); } +static void +instantiateDependentModeAttr(Sema &S, + const MultiLevelTemplateArgumentList &TemplateArgs, + const ModeAttr &Attr, Decl *New) { + S.AddModeAttr(Attr.getRange(), New, Attr.getMode(), + Attr.getSpellingListIndex(), /*InInstantiation=*/true); +} + void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, const Decl *Tmpl, Decl *New, LateInstantiatedAttrVec *LateAttrs, @@ -265,6 +273,11 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, continue; } + if (const ModeAttr *Mode = dyn_cast(TmplAttr)) { + instantiateDependentModeAttr(*this, TemplateArgs, *Mode, New); + continue; + } + // Existing DLL attribute on the instantiation takes precedence. if (TmplAttr->getKind() == attr::DLLExport || TmplAttr->getKind() == attr::DLLImport) { diff --git a/clang/test/CodeGen/attr-mode-enums.c b/clang/test/CodeGen/attr-mode-enums.c new file mode 100644 index 0000000..4675f6c --- /dev/null +++ b/clang/test/CodeGen/attr-mode-enums.c @@ -0,0 +1,45 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm %s -o - | FileCheck %s + +// Test checks that 'mode' attribute is handled correctly with enums, i. e. code +// 1. "typedef enum { A } __attribute__((mode(HI))) T;" is accepted, +// 2. "enum X __attribute__((mode(QI))) var;" forms a complete integer type. + +int main() { + // CHECK: [[X1:%.+]] = alloca i8 + enum { A1, B1 } __attribute__((mode(QI))) x1 = A1; + + // CHECK: [[X2:%.+]] = alloca i16 + enum { A2, B2 } x2 __attribute__((mode(HI))) = B2; + + // CHECK: [[X3:%.+]] = alloca i32 + typedef enum { A3, B3 } __attribute__((mode(SI))) T3; + T3 x3 = A3; + + // CHECK: [[X4:%.+]] = alloca i64 + typedef enum { A4, B4 } T4 __attribute__((mode(DI))); + T4 x4 = B4; + + // CHECK: [[X5:%.+]] = alloca i8 + typedef enum __attribute__((mode(QI))) { A5, B5 } T5; + T5 x5 = A5; + + // CHECK: [[X6:%.+]] = alloca i8 + typedef enum X __attribute__((mode(QI))) T6; + T6 x6; + + // CHECK: [[X7:%.+]] = alloca i128 + enum { A7, B7 } __attribute__((mode(TI))) x7 = A7; + + // CHECK: [[X8:%.+]] = alloca i8 + enum __attribute__((mode(QI))) { A8, B8 } x8 = B8; + + // CHECK: store i8 0, i8* [[X1]] + // CHECK: store i16 1, i16* [[X2]] + // CHECK: store i32 0, i32* [[X3]] + // CHECK: store i64 1, i64* [[X4]] + // CHECK: store i8 0, i8* [[X5]] + // CHECK: store i128 0, i128* [[X7]] + // CHECK: store i8 1, i8* [[X8]] + + return x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8; +} diff --git a/clang/test/CodeGenCXX/attr-mode-vector-types-tmpl.cpp b/clang/test/CodeGenCXX/attr-mode-vector-types-tmpl.cpp new file mode 100644 index 0000000..6373cf0 --- /dev/null +++ b/clang/test/CodeGenCXX/attr-mode-vector-types-tmpl.cpp @@ -0,0 +1,108 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu %s -emit-llvm -o - | FileCheck %s + +template +void CheckIntScalarTypes() { + // T will be substituted with 'int' and 'enum' types. + + typedef T __attribute__((mode(QI))) T1; + typedef T __attribute__((mode(HI))) T2; + typedef T __attribute__((mode(SI))) T3; + typedef T __attribute__((mode(DI))) T4; + + T1 a1; + T2 a2; + T3 a3; + T4 a4; +} + +template +void CheckIntVectorTypes() { + // T will be substituted with 'int'. + + typedef int __attribute__((mode(QI))) __attribute__((vector_size(8))) VT_11; + typedef T __attribute__((mode(V8QI))) VT_12; + typedef int __attribute__((mode(SI))) __attribute__((vector_size(16))) VT_21; + typedef T __attribute__((mode(V4SI))) VT_22; + typedef int __attribute__((mode(DI))) __attribute__((vector_size(64))) VT_31; + typedef T __attribute__((mode(V8DI))) VT_32; + + VT_11 v11; + VT_12 v12; + + VT_21 v21; + VT_22 v22; + + VT_31 v31; + VT_32 v32; +} + +template +void CheckFloatVectorTypes() { + // T will be substituted with 'float'. + + typedef float __attribute__((mode(SF))) __attribute__((vector_size(128))) VT_41; + typedef T __attribute__((mode(V32SF))) VT_42; + typedef float __attribute__((mode(DF))) __attribute__((vector_size(256))) VT_51; + typedef T __attribute__((mode(V32DF))) VT_52; + + VT_41 v41; + VT_42 v42; + + VT_51 v51; + VT_52 v52; +} + +template +void CheckInstantiationWithModedType() { + T x1; +} + +typedef enum { A1, B1 } EnumTy; +typedef int __attribute__((mode(DI))) Int64Ty1; +typedef enum __attribute__((mode(DI))) { A2 } Int64Ty2; +typedef int __attribute__((mode(V8HI))) IntVecTy1; + +void test() { + + // CHECK: define {{.*}} void @_Z19CheckIntScalarTypesIiEvv() + // CHECK: %{{.+}} = alloca i8 + // CHECK: %{{.+}} = alloca i16 + // CHECK: %{{.+}} = alloca i32 + // CHECK: %{{.+}} = alloca i64 + CheckIntScalarTypes(); + + // CHECK: define {{.*}} void @_Z19CheckIntScalarTypesI6EnumTyEvv() + // CHECK: %{{.+}} = alloca i8 + // CHECK: %{{.+}} = alloca i16 + // CHECK: %{{.+}} = alloca i32 + // CHECK: %{{.+}} = alloca i64 + CheckIntScalarTypes(); + + // CHECK: define {{.*}} void @_Z19CheckIntVectorTypesIiEvv() + // CHECK: %{{.+}} = alloca <8 x i8> + // CHECK: %{{.+}} = alloca <8 x i8> + // CHECK: %{{.+}} = alloca <4 x i32> + // CHECK: %{{.+}} = alloca <4 x i32> + // CHECK: %{{.+}} = alloca <8 x i64> + // CHECK: %{{.+}} = alloca <8 x i64> + CheckIntVectorTypes(); + + // CHECK: define {{.*}} void @_Z21CheckFloatVectorTypesIfEvv() + // CHECK: %{{.+}} = alloca <32 x float> + // CHECK: %{{.+}} = alloca <32 x float> + // CHECK: %{{.+}} = alloca <32 x double> + // CHECK: %{{.+}} = alloca <32 x double> + CheckFloatVectorTypes(); + + // CHECK: define {{.*}} void @_Z31CheckInstantiationWithModedTypeIlEvv() + // CHECK: [[X1:%.+]] = alloca i64 + CheckInstantiationWithModedType(); + + // CHECK: define {{.*}} void @_Z31CheckInstantiationWithModedTypeI8Int64Ty2Evv() + // CHECK: [[X1]] = alloca i64 + CheckInstantiationWithModedType(); + + // CHECK: define {{.*}} void @_Z31CheckInstantiationWithModedTypeIDv8_sEvv() + // CHECK: [[X1]] = alloca <8 x i16> + CheckInstantiationWithModedType(); +} diff --git a/clang/test/Sema/attr-mode-enums.c b/clang/test/Sema/attr-mode-enums.c new file mode 100644 index 0000000..4b98c3b --- /dev/null +++ b/clang/test/Sema/attr-mode-enums.c @@ -0,0 +1,51 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +// Test checks that 'mode' attribute is handled correctly with enums, i. e. code +// 1. "typedef enum { A } __attribute__((mode(HI))) T;" is accepted, +// 2. "enum X __attribute__((mode(QI))) var;" forms a complete integer type. +// 3. "enum { A } __attribute__((mode(V4SI))) var;" is not accepted (vector mode). + +typedef enum { E4 } EnumType; + +int main() { + // Vector mode are not allowed with enums. + typedef enum { E1 } __attribute__((mode(V4QI))) RejectedType1; // expected-error{{mode 'V4QI' is not supported for enumeration types}} + // expected-warning@-1{{specifying vector types with the 'mode' attribute is deprecated}} + typedef enum __attribute__((mode(V8HI))) { E2 } RejectedType2; // expected-error{{mode 'V8HI' is not supported for enumeration types}} + // expected-warning@-1{{deprecated}} + typedef enum E3 __attribute__((mode(V2SI))) RejectedType3; // expected-error{{mode 'V2SI' is not supported for enumeration types}} + // expected-warning@-1{{deprecated}} + typedef EnumType __attribute__((mode(V4DI))) RejectedType4; // expected-error{{mode 'V4DI' is not supported for enumeration types}} + // expected-warning@-1{{deprecated}} + EnumType v1 __attribute__((mode(V4QI))); // expected-error{{mode 'V4QI' is not supported for enumeration types}} + // expected-warning@-1{{deprecated}} + enum __attribute__((mode(V8HI))) { E5 } v2; // expected-error{{mode 'V8HI' is not supported for enumeration types}} + // expected-warning@-1{{deprecated}} + + // Incomplete enums without mode attribute are not allowed. + typedef enum Y IncompleteYType; // expected-note{{forward declaration of 'enum Y'}} + + enum X a1; // expected-error{{variable has incomplete type 'enum X'}} + // expected-note@-1{{forward declaration of 'enum X'}} + IncompleteYType a2; // expected-error{{variable has incomplete type 'IncompleteYType' (aka 'enum Y')}} + + // OK with 'mode' attribute. + typedef enum Y __attribute__((mode(QI))) CompleteYType1; + typedef enum Y CompleteYType2 __attribute__((mode(HI))); + typedef enum { A1, B1 } __attribute__((mode(QI))) CompleteType3; + typedef enum { A2, B2 } CompleteType4 __attribute__((mode(QI))); + typedef enum __attribute__((mode(QI))) { A3, B3 } CompleteType5; + + enum X __attribute__((mode(QI))) a3; + enum X a4 __attribute__((mode(HI))); + IncompleteYType __attribute__((mode(QI))) a5; + IncompleteYType a6 __attribute__((mode(HI))); + CompleteYType1 a7; + CompleteYType2 a8; + CompleteType3 a9; + CompleteType4 a10; + CompleteType5 a11; + enum __attribute__((mode(QI))) { A4, B4 } a12; + + return 0; +} diff --git a/clang/test/Sema/attr-mode.c b/clang/test/Sema/attr-mode.c index 405bfb7..e011549 100644 --- a/clang/test/Sema/attr-mode.c +++ b/clang/test/Sema/attr-mode.c @@ -26,8 +26,8 @@ typedef unsigned unwind_word __attribute((mode(unwind_word))); int **__attribute((mode(QI)))* i32; // expected-error{{mode attribute}} -__attribute__((mode(QI))) int invalid_func() { return 1; } // expected-error{{'mode' attribute only applies to variables, fields and typedefs}} -enum invalid_enum { A1 __attribute__((mode(QI))) }; // expected-error{{'mode' attribute only applies to variables, fields and typedefs}} +__attribute__((mode(QI))) int invalid_func() { return 1; } // expected-error{{'mode' attribute only applies to variables, enums, fields and typedefs}} +enum invalid_enum { A1 __attribute__((mode(QI))) }; // expected-error{{'mode' attribute only applies to variables, enums, fields and typedefs}} typedef _Complex double c32 __attribute((mode(SC))); int c32_test[sizeof(c32) == 8 ? 1 : -1]; diff --git a/clang/test/SemaCXX/attr-mode-tmpl.cpp b/clang/test/SemaCXX/attr-mode-tmpl.cpp new file mode 100644 index 0000000..4e1489a8 --- /dev/null +++ b/clang/test/SemaCXX/attr-mode-tmpl.cpp @@ -0,0 +1,104 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +typedef enum { XX } EnumType; +struct S { int x; }; + +// Check enumerations. Vector modes on enum types must cause an error. +template +void CheckEnumerations() { + // Check that non-vector 'mode' attribute is OK with enumeration types. + typedef T __attribute__((mode(QI))) T1; + typedef T T2 __attribute__((mode(HI))); + typedef T __attribute__((mode(V8SI))) T3; // expected-error{{mode 'V8SI' is not supported for enumeration types}} + // expected-warning@-1{{specifying vector types with the 'mode' attribute is deprecated}} + + typedef enum __attribute__((mode(HI))) { A4, B4 } T4; + typedef enum { A5, B5 } __attribute__((mode(SI))) T5; + typedef enum __attribute__((mode(V2SI))) { A6, B6 } T6; // expected-error{{mode 'V2SI' is not supported for enumeration types}} + // expected-warning@-1{{deprecated}} + typedef enum { A7, B7 } __attribute__((mode(V2QI))) T7; // expected-error{{mode 'V2QI' is not supported for enumeration types}} + // expected-warning@-1{{deprecated}} +} + +// Check that attribute applies only for integer and floating-point types. +// OK when instantiated with 'int', error with structure types, for example. +template +void CheckPrimitiveTypes() { + typedef T __attribute__((mode(QI))) T1; // expected-error{{mode attribute only supported for integer and floating-point types}} + typedef T __attribute__((mode(V2SI))) VT1; // expected-error{{mode attribute only supported for integer and floating-point types}} + // expected-warning@-1{{specifying vector types with the 'mode' attribute is deprecated}} +} + +// Check that attribute supports certain modes. Check that wrong machine modes +// are NOT diagnosed twice during instantiation. +template +void CheckMachineMode() { + typedef T __attribute__((mode(QI))) T1; // expected-error{{type of machine mode does not match type of base type}} + typedef T __attribute__((mode(HI))) T2; // expected-error{{type of machine mode does not match type of base type}} + typedef T __attribute__((mode(SI))) T3; // expected-error{{type of machine mode does not match type of base type}} + typedef T __attribute__((mode(DI))) T4; // expected-error{{type of machine mode does not match type of base type}} + typedef T __attribute__((mode(SF))) T5; // expected-error2{{type of machine mode does not match type of base type}} + typedef T __attribute__((mode(DF))) T6; // expected-error2{{type of machine mode does not match type of base type}} + typedef T __attribute__((mode(II))) T7; // expected-error{{unknown machine mode}} + typedef T __attribute__((mode(12))) T8; // expected-error{{'mode' attribute requires an identifier}} +} + +// Check attributes on function parameters. +template +void CheckParameters(T1 __attribute__((mode(SI))) paramSI, // expected-note2{{ignored: substitution failure}} + T1 __attribute__((mode(V4DI))) paramV4DI, // expected-warning{{deprecated}} + T2 __attribute__((mode(SF))) paramSF, + T2 __attribute__((mode(V4DF))) paramV4DF) { // expected-warning{{deprecated}} +} + + +// Check dependent structure. +template +struct TemplatedStruct { + // Check fields. + T __attribute__((mode(HI))) x1; + T __attribute__((mode(V4HI))) x2; // expected-error{{mode 'V4HI' is not supported for enumeration types}} + // expected-warning@-1{{deprecated}} + + // Check typedefs. + typedef T __attribute__((mode(DI))) T1; + typedef T __attribute__((mode(V8DI))) T2; // expected-error{{mode 'V8DI' is not supported for enumeration types}} + // expected-warning@-1{{deprecated}} + + // Check parameters. + void f1(T __attribute__((mode(QI))) x) {} + void f2(T __attribute__((mode(SF))) x) {} // expected-error2{{type of machine mode does not match type of base type}} + void f3(T __attribute__((mode(V4QI))) x) {} // expected-error{{mode 'V4QI' is not supported for enumeration types}} + // expected-warning@-1{{deprecated}} + + // Check attribute on methods - it is invalid. + __attribute__((mode(QI))) T g1() { return 0; } // expected-error{{'mode' attribute only applies to variables, enums, fields and typedefs}} +}; + + + +int main() { + CheckEnumerations(); + CheckEnumerations(); // expected-note{{in instantiation of}} + + CheckPrimitiveTypes(); + CheckPrimitiveTypes(); // expected-note{{in instantiation of}} + + // 'II' mode is unknown, no matter what we instantiate with. + CheckMachineMode(); // expected-note{{in instantiation of}} + CheckMachineMode(); // expected-note{{in instantiation of}} + CheckMachineMode(); // expected-note{{in instantiation of}} + + int __attribute__((mode(V4DI))) valV4DI; // expected-warning{{deprecated}} + float __attribute__((mode(V4DF))) valV4DF; // expected-warning{{deprecated}} + // OK. + CheckParameters(0, valV4DI, 1.0, valV4DF); + // Enumeral type with vector mode is invalid. + CheckParameters(0, valV4DI, 1.0, valV4DF); // expected-error{{no matching function for call}} + // 'V4DF' mode with 'int' type is invalid. + CheckParameters(0, valV4DI, 1, valV4DF); // expected-error{{no matching function for call}} + + TemplatedStruct s1; // expected-note{{in instantiation of}} + TemplatedStruct s2; // expected-note{{in instantiation of}} + return 0; +} -- 2.7.4