Skip to content

Commit

Permalink
Fix for PR8901: attribute "mode" rejected for enums and dependent types.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Denis Zobnin committed Feb 2, 2016
1 parent 96fe4ef commit d9e2dcd
Show file tree
Hide file tree
Showing 11 changed files with 403 additions and 41 deletions.
4 changes: 2 additions & 2 deletions clang/include/clang/Basic/Attr.td
Expand Up @@ -879,8 +879,8 @@ def MipsInterrupt : InheritableAttr, TargetSpecificAttr<TargetMips> {

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];
}
Expand Down
4 changes: 3 additions & 1 deletion clang/include/clang/Basic/DiagnosticSemaKinds.td
Expand Up @@ -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<IgnoredAttributes>;
def err_attribute_wrong_decl_type : Error<warn_attribute_wrong_decl_type.Text>;
def warn_type_attribute_wrong_type : Warning<
Expand Down Expand Up @@ -2858,6 +2858,8 @@ def warn_vector_mode_deprecated : Warning<
InGroup<DeprecatedAttributes>;
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<IgnoredAttributes>;
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Sema/AttributeList.h
Expand Up @@ -856,7 +856,7 @@ enum AttributeDeclKind {
ExpectedObjectiveCInterfaceOrProtocol,
ExpectedKernelFunction,
ExpectedFunctionWithProtoType,
ExpectedVariableFieldOrTypedef
ExpectedVariableEnumFieldOrTypedef
};

} // end namespace clang
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/Sema/Sema.h
Expand Up @@ -7750,6 +7750,10 @@ class Sema {
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
//
Expand Down
105 changes: 70 additions & 35 deletions clang/lib/Sema/SemaDeclAttr.cpp
Expand Up @@ -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]) {
Expand Down Expand Up @@ -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;
Expand All @@ -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<TypedefNameDecl>(D))
OldTy = TD->getUnderlyingType();
else
else if (EnumDecl *ED = dyn_cast<EnumDecl>(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<ValueDecl>(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<VectorType>())
OldElemTy = VT->getElementType();

if (!OldElemTy->getAs<BuiltinType>() && !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<EnumDecl>(D) || OldElemTy->getAs<EnumType>()) &&
VectorSize.getBoolValue()) {
Diag(AttrLoc, diag::err_enum_mode_vector_type) << Name << AttrRange;
return;
}
bool IntegralOrAnyEnumType =
OldElemTy->isIntegralOrEnumerationType() || OldElemTy->getAs<EnumType>();

if (!OldElemTy->getAs<BuiltinType>() && !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<VectorType>()) {
// 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<TypedefNameDecl>(D))
TD->setModedTypeSourceInfo(TD->getTypeSourceInfo(), NewTy);
else if (EnumDecl *ED = dyn_cast<EnumDecl>(D))
ED->setIntegerType(NewTy);
else
cast<ValueDecl>(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) {
Expand Down
13 changes: 13 additions & 0 deletions clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Expand Up @@ -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,
Expand Down Expand Up @@ -265,6 +273,11 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
continue;
}

if (const ModeAttr *Mode = dyn_cast<ModeAttr>(TmplAttr)) {
instantiateDependentModeAttr(*this, TemplateArgs, *Mode, New);
continue;
}

// Existing DLL attribute on the instantiation takes precedence.
if (TmplAttr->getKind() == attr::DLLExport ||
TmplAttr->getKind() == attr::DLLImport) {
Expand Down
45 changes: 45 additions & 0 deletions 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;
}

0 comments on commit d9e2dcd

Please sign in to comment.