diff options
author | Dmitry Stogov <dmitry@zend.com> | 2019-03-29 17:28:57 +0300 |
---|---|---|
committer | Dmitry Stogov <dmitry@zend.com> | 2019-03-29 17:28:57 +0300 |
commit | 61ad294f26fa7941a26361a68cf6a01b8a2c3e4f (patch) | |
tree | a13745dfd3b3b0a272bc45711f6664c3d212c910 /ext/ffi | |
parent | 4726c35ca33da837406745f21e2320fb18ae7618 (diff) | |
download | php-git-61ad294f26fa7941a26361a68cf6a01b8a2c3e4f.tar.gz |
Partial support for GCC mode attribute.
Diffstat (limited to 'ext/ffi')
-rw-r--r-- | ext/ffi/ffi.c | 61 | ||||
-rw-r--r-- | ext/ffi/ffi.g | 6 | ||||
-rw-r--r-- | ext/ffi/ffi_parser.c | 6 | ||||
-rw-r--r-- | ext/ffi/php_ffi.h | 2 | ||||
-rw-r--r-- | ext/ffi/tests/044.phpt | 30 |
5 files changed, 104 insertions, 1 deletions
diff --git a/ext/ffi/ffi.c b/ext/ffi/ffi.c index 4ab9f85695..f062170f42 100644 --- a/ext/ffi/ffi.c +++ b/ext/ffi/ffi.c @@ -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)); diff --git a/ext/ffi/ffi.g b/ext/ffi/ffi.g index a1dde95c64..2be2f11e7c 100644 --- a/ext/ffi/ffi.g +++ b/ext/ffi/ffi.g @@ -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; diff --git a/ext/ffi/ffi_parser.c b/ext/ffi/ffi_parser.c index 94fb11d17b..816aa49dc8 100644 --- a/ext/ffi/ffi_parser.c +++ b/ext/ffi/ffi_parser.c @@ -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; diff --git a/ext/ffi/php_ffi.h b/ext/ffi/php_ffi.h index 35b5127875..664f473d9d 100644 --- a/ext/ffi/php_ffi.h +++ b/ext/ffi/php_ffi.h @@ -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 index 0000000000..ab07e23e1b --- /dev/null +++ b/ext/ffi/tests/044.phpt @@ -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) |