diff options
author | Eli Friedman <eli.friedman@gmail.com> | 2008-05-27 03:33:27 +0000 |
---|---|---|
committer | Eli Friedman <eli.friedman@gmail.com> | 2008-05-27 03:33:27 +0000 |
commit | 3c0eb160ca1361a82b9f15b3b40a2425adc14d0f (patch) | |
tree | 1ba325230d8ddcb4586cdcef43ea08c3e417f875 | |
parent | cbadaf6ced6d664015ee409f62ab1bc20ae0bf73 (diff) |
Implementation of gcc mode attribute; this is significant because
it fixes PR2204. Not too much to say about the implementation; it works
in a similar way to the vector size attribute.
At some point, we need to modify the targets to provide information
about the appropriate types.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@51577 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Basic/DiagnosticKinds.def | 10 | ||||
-rw-r--r-- | include/clang/Parse/AttributeList.h | 1 | ||||
-rw-r--r-- | lib/Parse/AttributeList.cpp | 1 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 12 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 11 | ||||
-rw-r--r-- | lib/Sema/SemaType.cpp | 120 | ||||
-rw-r--r-- | test/Sema/mode-attr-test.c | 15 |
7 files changed, 169 insertions, 1 deletions
diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index f1a015c39a..57b49772db 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -584,6 +584,8 @@ DIAG(err_bad_language, ERROR, // Attributes DIAG(err_attribute_wrong_number_arguments, ERROR, "attribute requires %0 argument(s)") +DIAG(err_attribute_missing_parameter_name, ERROR, + "attribute requires unquoted parameter") DIAG(err_attribute_invalid_vector_type, ERROR, "invalid vector type '%0'") DIAG(err_attribute_argument_not_int, ERROR, @@ -632,6 +634,14 @@ DIAG(warn_attribute_ignored_for_field_of_type, WARNING, "'%0' attribute ignored for field of type '%1'") DIAG(warn_attribute_type_not_supported, WARNING, "'%0' attribute argument not supported: '%1'") +DIAG(err_unknown_machine_mode, ERROR, + "unknown machine mode '%0'") +DIAG(err_unsupported_machine_mode, ERROR, + "unsupported machine mode '%0'") +DIAG(err_mode_not_primitive, ERROR, + "mode attribute only supported for integer and floating-point types") +DIAG(err_mode_wrong_type, ERROR, + "type of machine mode does not match type of base type") // Function Parameter Semantic Analysis. DIAG(err_param_with_void_type, ERROR, diff --git a/include/clang/Parse/AttributeList.h b/include/clang/Parse/AttributeList.h index 6453679241..63318dbcb4 100644 --- a/include/clang/Parse/AttributeList.h +++ b/include/clang/Parse/AttributeList.h @@ -52,6 +52,7 @@ public: AT_fastcall, AT_format, AT_malloc, + AT_mode, AT_noinline, AT_nonnull, AT_noreturn, diff --git a/lib/Parse/AttributeList.cpp b/lib/Parse/AttributeList.cpp index 2d8de97f3c..c99722c54a 100644 --- a/lib/Parse/AttributeList.cpp +++ b/lib/Parse/AttributeList.cpp @@ -54,6 +54,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { case 4: if (!memcmp(Str, "weak", 4)) return AT_weak; if (!memcmp(Str, "pure", 4)) return AT_pure; + if (!memcmp(Str, "mode", 4)) return AT_mode; break; case 6: if (!memcmp(Str, "packed", 6)) return AT_packed; diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index e7e6605458..5d9113e99d 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -299,7 +299,13 @@ private: /// The raw attribute contains 1 argument, the id of the address space /// for the type. QualType HandleAddressSpaceTypeAttribute(QualType curType, - AttributeList *rawAttr); + AttributeList *rawAttr); + + /// HandleModeTypeAttribute - this attribute modifies the width of a + /// primitive type. Note that this is a variable attribute, and not + /// a type attribute. + QualType HandleModeTypeAttribute(QualType curType, + AttributeList *rawAttr); // HandleVectorTypeAttribute - this attribute is only applicable to // integral and float scalars, although arrays, pointers, and function @@ -723,6 +729,10 @@ private: // UsualUnaryConversions - promotes integers (C99 6.3.1.1p2) and converts // functions and arrays to their respective pointers (C99 6.3.2.1). Expr *UsualUnaryConversions(Expr *&expr); + + // UsualUnaryConversionType - Same as UsualUnaryConversions, but works + // on types instead of expressions + QualType UsualUnaryConversionType(QualType Ty); // DefaultFunctionArrayConversion - converts functions and arrays // to their respective pointers (C99 6.3.2.1). diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 38dbb9b09a..8b89045a71 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -2384,6 +2384,17 @@ void Sema::HandleDeclAttribute(Decl *New, AttributeList *Attr) { vDecl->setType(newType); } break; + case AttributeList::AT_mode: + if (TypedefDecl *tDecl = dyn_cast<TypedefDecl>(New)) { + QualType newType = HandleModeTypeAttribute(tDecl->getUnderlyingType(), + Attr); + tDecl->setUnderlyingType(newType); + } else if (ValueDecl *vDecl = dyn_cast<ValueDecl>(New)) { + QualType newType = HandleModeTypeAttribute(vDecl->getType(), Attr); + vDecl->setType(newType); + } + // FIXME: Diagnostic? + break; case AttributeList::AT_deprecated: HandleDeprecatedAttribute(New, Attr); break; diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 9bb211bd30..d66b41d8e3 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -579,3 +579,123 @@ QualType Sema::HandleAddressSpaceTypeAttribute(QualType Type, return Context.getASQualType(Type, ASIdx); } +/// HandleModeTypeAttribute - Process a mode attribute on the +/// specified type. +QualType Sema::HandleModeTypeAttribute(QualType Type, + AttributeList *Attr) { + // This attribute isn't documented, but glibc uses it. It changes + // the width of an int or unsigned int to the specified size. + + // Check that there aren't any arguments + if (Attr->getNumArgs() != 0) { + Diag(Attr->getLoc(), diag::err_attribute_wrong_number_arguments, + std::string("0")); + return Type; + } + + IdentifierInfo * Name = Attr->getParameterName(); + if (!Name) { + Diag(Attr->getLoc(), diag::err_attribute_missing_parameter_name); + return Type; + } + const char *Str = Name->getName(); + unsigned Len = Name->getLength(); + + // Normalize the attribute name, __foo__ becomes foo. + if (Len > 4 && Str[0] == '_' && Str[1] == '_' && + Str[Len - 2] == '_' && Str[Len - 1] == '_') { + Str += 2; + Len -= 4; + } + + unsigned DestWidth = 0; + bool IntegerMode = true; + + switch (Len) { + case 2: + if (!memcmp(Str, "QI", 2)) { DestWidth = 8; break; } + if (!memcmp(Str, "HI", 2)) { DestWidth = 16; break; } + if (!memcmp(Str, "SI", 2)) { DestWidth = 32; break; } + if (!memcmp(Str, "DI", 2)) { DestWidth = 64; break; } + if (!memcmp(Str, "TI", 2)) { DestWidth = 128; break; } + if (!memcmp(Str, "SF", 2)) { DestWidth = 32; IntegerMode = false; break; } + if (!memcmp(Str, "DF", 2)) { DestWidth = 64; IntegerMode = false; break; } + if (!memcmp(Str, "XF", 2)) { DestWidth = 96; IntegerMode = false; break; } + if (!memcmp(Str, "TF", 2)) { DestWidth = 128; IntegerMode = false; break; } + break; + case 4: + if (!memcmp(Str, "word", 4)) { + // FIXME: glibc uses this to define register_t; this is + // narrover than a pointer on PIC16 and other embedded + // platforms + DestWidth = Context.getTypeSize(Context.VoidPtrTy); + break; + } + if (!memcmp(Str, "byte", 4)) { + DestWidth = Context.getTypeSize(Context.CharTy); + break; + } + break; + case 7: + if (!memcmp(Str, "pointer", 7)) { + DestWidth = Context.getTypeSize(Context.VoidPtrTy); + IntegerMode = true; + break; + } + break; + } + + // FIXME: Need proper fixed-width types + QualType RetTy; + switch (DestWidth) { + case 0: + Diag(Attr->getLoc(), diag::err_unknown_machine_mode, + std::string(Str, Len)); + return Type; + case 8: + assert(IntegerMode); + if (Type->isSignedIntegerType()) + RetTy = Context.SignedCharTy; + else + RetTy = Context.UnsignedCharTy; + break; + case 16: + assert(IntegerMode); + if (Type->isSignedIntegerType()) + RetTy = Context.ShortTy; + else + RetTy = Context.UnsignedShortTy; + break; + case 32: + if (!IntegerMode) + RetTy = Context.FloatTy; + else if (Type->isSignedIntegerType()) + RetTy = Context.IntTy; + else + RetTy = Context.UnsignedIntTy; + break; + case 64: + if (!IntegerMode) + RetTy = Context.DoubleTy; + else if (Type->isSignedIntegerType()) + RetTy = Context.LongLongTy; + else + RetTy = Context.UnsignedLongLongTy; + break; + default: + Diag(Attr->getLoc(), diag::err_unsupported_machine_mode, + std::string(Str, Len)); + return Type; + } + + if (!Type->getAsBuiltinType()) + Diag(Attr->getLoc(), diag::err_mode_not_primitive); + else if (!(IntegerMode && Type->isIntegerType()) && + !(!IntegerMode && Type->isFloatingType())) { + Diag(Attr->getLoc(), diag::err_mode_wrong_type); + } + + return RetTy; +} + + diff --git a/test/Sema/mode-attr-test.c b/test/Sema/mode-attr-test.c new file mode 100644 index 0000000000..4eb1399071 --- /dev/null +++ b/test/Sema/mode-attr-test.c @@ -0,0 +1,15 @@ +// RUN: clang -fsyntax-only -verify %s + +typedef int i16_1 __attribute((mode(HI))); +int i16_1_test[sizeof(i16_1) == 2 ? 1 : -1]; +typedef int i16_2 __attribute((__mode__(__HI__))); +int i16_2_test[sizeof(i16_1) == 2 ? 1 : -1]; + +typedef float f64 __attribute((mode(DF))); +int f64_test[sizeof(f64) == 8 ? 1 : -1]; + +typedef int invalid_1 __attribute((mode)); // expected-error{{attribute requires unquoted parameter}} +typedef int invalid_2 __attribute((mode())); // expected-error{{attribute requires unquoted parameter}} +typedef int invalid_3 __attribute((mode(II))); // expected-error{{unknown machine mode}} +typedef struct {int i,j,k;} invalid_4 __attribute((mode(SI))); // expected-error{{mode attribute only supported for integer and floating-point types}} +typedef float invalid_5 __attribute((mode(SI))); // expected-error{{type of machine mode does not match type of base type}} |