]> granicus.if.org Git - php/commitdiff
Partial support for GCC mode attribute.
authorDmitry Stogov <dmitry@zend.com>
Fri, 29 Mar 2019 14:28:57 +0000 (17:28 +0300)
committerDmitry Stogov <dmitry@zend.com>
Fri, 29 Mar 2019 14:28:57 +0000 (17:28 +0300)
ext/ffi/ffi.c
ext/ffi/ffi.g
ext/ffi/ffi_parser.c
ext/ffi/php_ffi.h
ext/ffi/tests/044.phpt [new file with mode: 0644]

index 4ab9f85695c31edeb180b3cb87f2775488c5225e..f062170f42f250bd524e9386eadb0f6dd3105fa3 100644 (file)
@@ -5089,7 +5089,12 @@ void zend_ffi_resolve_const(const char *name, size_t name_len, zend_ffi_val *val
 {
        zend_ffi_symbol *sym;
 
-       if (FFI_G(symbols)) {
+       if (UNEXPECTED(FFI_G(attribute_parsing))) {
+               val->kind = ZEND_FFI_VAL_NAME;
+               val->str = name;
+               val->len = name_len;
+               return;
+       } else if (FFI_G(symbols)) {
                sym = zend_hash_str_find_ptr(FFI_G(symbols), name, name_len);
                if (sym && sym->kind == ZEND_FFI_SYM_CONST) {
                        val->i64 = sym->value;
@@ -6099,6 +6104,60 @@ void zend_ffi_add_attribute_value(zend_ffi_dcl *dcl, const char *name, size_t na
                        }
                        break;
                case attr_mode:
+                       if (n == 0
+                        && (val->kind == ZEND_FFI_VAL_NAME)) {
+                               const char *str = val->str;
+                               size_t len = val->len;
+                               if (len > 4
+                                && str[0] == '_'
+                                && str[1] == '_'
+                                && str[len-2] == '_'
+                                && str[len-1] == '_') {
+                                       str += 2;
+                                       len -= 4;
+                               }
+                               // TODO: Add support for vector type 'VnXX' ???
+                               if (len == 2) {
+                                       if (str[1] == 'I') {
+                                               if (dcl->flags & (ZEND_FFI_DCL_TYPE_SPECIFIERS-(ZEND_FFI_DCL_CHAR|ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_INT|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_LONG_LONG|ZEND_FFI_DCL_SIGNED|ZEND_FFI_DCL_UNSIGNED))) {
+                                                       /* inappropriate type */
+                                               } else if (str[0] == 'Q') {
+                                                       dcl->flags &= ~(ZEND_FFI_DCL_CHAR|ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_INT|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_LONG_LONG);
+                                                       dcl->flags |= ZEND_FFI_DCL_CHAR;
+                                                       break;
+                                               } else if (str[0] == 'H') {
+                                                       dcl->flags &= ~(ZEND_FFI_DCL_CHAR|ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_INT|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_LONG_LONG);
+                                                       dcl->flags |= ZEND_FFI_DCL_SHORT;
+                                                       break;
+                                               } else if (str[0] == 'S') {
+                                                       dcl->flags &= ~(ZEND_FFI_DCL_CHAR|ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_INT|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_LONG_LONG);
+                                                       dcl->flags |= ZEND_FFI_DCL_INT;
+                                                       break;
+                                               } else if (str[0] == 'D') {
+                                                       dcl->flags &= ~(ZEND_FFI_DCL_CHAR|ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_INT|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_LONG_LONG);
+                                                       if (sizeof(long) == 8) {
+                                                               dcl->flags |= ZEND_FFI_DCL_LONG;
+                                                       } else {
+                                                               dcl->flags |= ZEND_FFI_DCL_LONG_LONG;
+                                                       }
+                                                       break;
+                                               }
+                                       } else if (str[1] == 'F') {
+                                               if (dcl->flags & (ZEND_FFI_DCL_TYPE_SPECIFIERS-(ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_FLOAT|ZEND_FFI_DCL_DOUBLE))) {
+                                                       /* inappropriate type */
+                                               } else if (str[0] == 'S') {
+                                                       dcl->flags &= ~(ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_FLOAT|ZEND_FFI_DCL_DOUBLE);
+                                                       dcl->flags |= ZEND_FFI_DCL_FLOAT;
+                                                       break;
+                                               } else if (str[0] == 'D') {
+                                                       dcl->flags &= ~(ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_FLOAT|ZEND_FFI_DCL_DOUBLE);
+                                                       dcl->flags |= ZEND_FFI_DCL_DOUBLE;
+                                                       break;
+                                               }
+                                       }
+                               }
+                       }
+                       zend_ffi_parser_error("unsupported 'mode' value at line %d", FFI_G(line));
                        // TODO: ???
                case attr_unsupported:
                        zend_ffi_parser_error("unsupported attribute '%.*s' at line %d", name_len, name, FFI_G(line));
index a1dde95c6424989775d6e779a4a2d2e7104a0911..2be2f11e7cd5b171aac0dc60975c5a81e98bfe49 100644 (file)
@@ -495,10 +495,13 @@ attrib(zend_ffi_dcl *dcl):
        {size_t name_len;}
        {int n;}
        {zend_ffi_val val;}
+       {zend_bool orig_attribute_parsing;}
        (   ID(&name, &name_len)
                (       /* empty */
                        {zend_ffi_add_attribute(dcl, name, name_len);}
                |       "("
+                       {orig_attribute_parsing = FFI_G(attribute_parsing);}
+                       {FFI_G(attribute_parsing) = 1;}
                        assignment_expression(&val)
                        {zend_ffi_add_attribute_value(dcl, name, name_len, 0, &val);}
                        {n = 0;}
@@ -506,6 +509,7 @@ attrib(zend_ffi_dcl *dcl):
                                assignment_expression(&val)
                                {zend_ffi_add_attribute_value(dcl, name, name_len, ++n, &val);}
                        )*
+                       {FFI_G(attribute_parsing) = orig_attribute_parsing;}
                        ")"
                )
        |       "const"
@@ -874,6 +878,7 @@ SKIP: ( EOL | WS | ONE_LINE_COMMENT | COMMENT )*;
 int zend_ffi_parse_decl(const char *str, size_t len) {
        if (SETJMP(FFI_G(bailout))==0) {
                FFI_G(allow_vla) = 0;
+               FFI_G(attribute_parsing) = 0;
                yy_buf = (unsigned char*)str;
                yy_end = yy_buf + len;
                parse();
@@ -888,6 +893,7 @@ int zend_ffi_parse_type(const char *str, size_t len, zend_ffi_dcl *dcl) {
 
        if (SETJMP(FFI_G(bailout))==0) {
                FFI_G(allow_vla) = 0;
+               FFI_G(attribute_parsing) = 0;
                yy_pos = yy_text = yy_buf = (unsigned char*)str;
                yy_end = yy_buf + len;
                yy_line = 1;
index 94fb11d17b8d9c0f35fbfc02de56dc11247e30a9..816aa49dc83d69249fe51f954532652fa4c8667b 100644 (file)
@@ -2930,6 +2930,7 @@ static int parse_attrib(int sym, zend_ffi_dcl *dcl) {
        size_t name_len;
        int n;
        zend_ffi_val val;
+       zend_bool orig_attribute_parsing;
        if (sym == YY_ID || sym == YY_CONST || sym == YY___CONST || sym == YY___CONST__) {
                if (sym == YY_ID) {
                        sym = parse_ID(sym, &name, &name_len);
@@ -2937,6 +2938,8 @@ static int parse_attrib(int sym, zend_ffi_dcl *dcl) {
                                zend_ffi_add_attribute(dcl, name, name_len);
                        } else if (sym == YY__LPAREN) {
                                sym = get_sym();
+                               orig_attribute_parsing = FFI_G(attribute_parsing);
+                               FFI_G(attribute_parsing) = 1;
                                sym = parse_assignment_expression(sym, &val);
                                zend_ffi_add_attribute_value(dcl, name, name_len, 0, &val);
                                n = 0;
@@ -2945,6 +2948,7 @@ static int parse_attrib(int sym, zend_ffi_dcl *dcl) {
                                        sym = parse_assignment_expression(sym, &val);
                                        zend_ffi_add_attribute_value(dcl, name, name_len, ++n, &val);
                                }
+                               FFI_G(attribute_parsing) = orig_attribute_parsing;
                                if (sym != YY__RPAREN) {
                                        yy_error_sym("')' expected, got", sym);
                                }
@@ -3516,6 +3520,7 @@ static void parse(void) {
 int zend_ffi_parse_decl(const char *str, size_t len) {
        if (SETJMP(FFI_G(bailout))==0) {
                FFI_G(allow_vla) = 0;
+               FFI_G(attribute_parsing) = 0;
                yy_buf = (unsigned char*)str;
                yy_end = yy_buf + len;
                parse();
@@ -3530,6 +3535,7 @@ int zend_ffi_parse_type(const char *str, size_t len, zend_ffi_dcl *dcl) {
 
        if (SETJMP(FFI_G(bailout))==0) {
                FFI_G(allow_vla) = 0;
+               FFI_G(attribute_parsing) = 0;
                yy_pos = yy_text = yy_buf = (unsigned char*)str;
                yy_end = yy_buf + len;
                yy_line = 1;
index 35b512787546489e29068e3cee32cf51e784ec36..664f473d9db995c3817ab1ab3601e3f8cdec7f2d 100644 (file)
@@ -56,6 +56,7 @@ ZEND_BEGIN_MODULE_GLOBALS(ffi)
        HashTable *symbols;
        HashTable *tags;
        zend_bool allow_vla;
+       zend_bool attribute_parsing;
        zend_bool persistent;
        uint32_t  default_type_attr;
 ZEND_END_MODULE_GLOBALS(ffi)
@@ -182,6 +183,7 @@ typedef enum _zend_ffi_val_kind {
        ZEND_FFI_VAL_LONG_DOUBLE,
        ZEND_FFI_VAL_CHAR,
        ZEND_FFI_VAL_STRING,
+       ZEND_FFI_VAL_NAME, /* attribute value */
 } zend_ffi_val_kind;
 
 #ifdef HAVE_LONG_DOUBLE
diff --git a/ext/ffi/tests/044.phpt b/ext/ffi/tests/044.phpt
new file mode 100644 (file)
index 0000000..ab07e23
--- /dev/null
@@ -0,0 +1,30 @@
+--TEST--
+FFI 044: mode attribute
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--INI--
+ffi.enable=1
+--FILE--
+<?php
+$ffi = FFI::cdef("
+typedef int a __attribute__ ((__mode__ (__QI__)));
+typedef int b __attribute__ ((__mode__ (__HI__)));
+typedef int c __attribute__ ((__mode__ (__SI__)));
+typedef int d __attribute__ ((__mode__ (__DI__)));
+typedef float e __attribute__ ((__mode__ (__SF__)));
+typedef float f __attribute__ ((__mode__ (__DF__)));
+");
+var_dump(FFI::sizeof($ffi->new("a")));
+var_dump(FFI::sizeof($ffi->new("b")));
+var_dump(FFI::sizeof($ffi->new("c")));
+var_dump(FFI::sizeof($ffi->new("d")));
+var_dump(FFI::sizeof($ffi->new("e")));
+var_dump(FFI::sizeof($ffi->new("f")));
+?>
+--EXPECT--
+int(1)
+int(2)
+int(4)
+int(8)
+int(4)
+int(8)