aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEli Friedman <eli.friedman@gmail.com>2008-05-27 03:33:27 +0000
committerEli Friedman <eli.friedman@gmail.com>2008-05-27 03:33:27 +0000
commit3c0eb160ca1361a82b9f15b3b40a2425adc14d0f (patch)
tree1ba325230d8ddcb4586cdcef43ea08c3e417f875
parentcbadaf6ced6d664015ee409f62ab1bc20ae0bf73 (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.def10
-rw-r--r--include/clang/Parse/AttributeList.h1
-rw-r--r--lib/Parse/AttributeList.cpp1
-rw-r--r--lib/Sema/Sema.h12
-rw-r--r--lib/Sema/SemaDecl.cpp11
-rw-r--r--lib/Sema/SemaType.cpp120
-rw-r--r--test/Sema/mode-attr-test.c15
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}}