? Zend/zend_compile (another copy).c ? Zend/zend_compile (copy).c Index: Zend/zend_compile.c =================================================================== RCS file: /repository/ZendEngine2/zend_compile.c,v retrieving revision 1.647.2.27.2.41.2.31 diff -u -r1.647.2.27.2.41.2.31 zend_compile.c --- Zend/zend_compile.c 13 Dec 2007 10:02:03 -0000 1.647.2.27.2.41.2.31 +++ Zend/zend_compile.c 23 Dec 2007 03:04:34 -0000 @@ -1191,6 +1191,25 @@ efree(lcname); } else { zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); + int alias_clash = 0; + zval **alias; + + /* Function name must not conflict with import names */ + if (CG(current_import) && + zend_hash_find(CG(current_import), lcname, Z_STRLEN(function_name->u.constant)+1, (void**)&alias) == SUCCESS) { + alias_clash = 1; + } + + /* Remember names of defined functions in the current file + (or namespace if using multiple namespaces per file) */ + /* Create the used names table if needed (lazy construction) */ + if (!CG(current_used_names)) { + CG(current_used_names) = emalloc(sizeof(HashTable)); + zend_hash_init(CG(current_used_names), 0, NULL, NULL, 0); + } + /* Nothing is stored in the table, only the index is used. + Maybe a reference to what for and where the name was used can be stored to provide an extended error message */ + zend_hash_add(CG(current_used_names), lcname, Z_STRLEN(function_name->u.constant)+1, NULL, 0, NULL); if (CG(current_namespace)) { /* Prefix function name with current namespcae name */ @@ -1199,12 +1218,24 @@ tmp.u.constant = *CG(current_namespace); zval_copy_ctor(&tmp.u.constant); zend_do_build_namespace_name(&tmp, &tmp, function_name TSRMLS_CC); + function_name = &tmp; op_array.function_name = Z_STRVAL(tmp.u.constant); efree(lcname); name_len = Z_STRLEN(tmp.u.constant); lcname = zend_str_tolower_dup(Z_STRVAL(tmp.u.constant), name_len); } + if (alias_clash) { + /* Check if clashing alias actually points to a different name */ + char *tmp = zend_str_tolower_dup(Z_STRVAL_PP(alias), Z_STRLEN_PP(alias)); + + if (Z_STRLEN_PP(alias) != Z_STRLEN(function_name->u.constant) || + memcmp(tmp, lcname, Z_STRLEN(function_name->u.constant))) { + zend_error(E_COMPILE_ERROR, "Cannot declare function %s because the name is already in use", Z_STRVAL(function_name->u.constant)); + } + efree(tmp); + } + opline->opcode = ZEND_DECLARE_FUNCTION; opline->op1.op_type = IS_CONST; build_runtime_defined_function_key(&opline->op1.u.constant, lcname, name_len TSRMLS_CC); @@ -1380,23 +1411,34 @@ char *lcname; int prefix_len = 0; - if (check_namespace && CG(current_namespace)) { - /* We assume we call function from the current namespace - if it is not prefixed. */ - znode tmp; + lcname = zend_str_tolower_dup(function_name->u.constant.value.str.val, function_name->u.constant.value.str.len); - tmp.op_type = IS_CONST; - tmp.u.constant = *CG(current_namespace); - zval_copy_ctor(&tmp.u.constant); - zend_do_build_namespace_name(&tmp, &tmp, function_name TSRMLS_CC); - *function_name = tmp; + if (check_namespace && (CG(current_import) || CG(current_namespace))) { + zval **alias; - /* In run-time PHP will check for function with full name and - internal function with short name */ - prefix_len = Z_STRLEN_P(CG(current_namespace)) + 2; + if (CG(current_import) && + zend_hash_find(CG(current_import), lcname, Z_STRLEN(function_name->u.constant)+1, (void**)&alias) == SUCCESS) { + /* The given name is an import name. Substitute it. */ + zval_dtor(&function_name->u.constant); + function_name->u.constant = **alias; + zval_copy_ctor(&function_name->u.constant); + } else if (CG(current_namespace)) { + /* We assume we call function from the current namespace + if it is not prefixed and is not an import name. */ + znode tmp; + + tmp.op_type = IS_CONST; + tmp.u.constant = *CG(current_namespace); + zval_copy_ctor(&tmp.u.constant); + zend_do_build_namespace_name(&tmp, &tmp, function_name TSRMLS_CC); + *function_name = tmp; + + /* In run-time PHP will check for function with full name and + internal function with short name */ + prefix_len = Z_STRLEN_P(CG(current_namespace)) + 2; + } } - lcname = zend_str_tolower_dup(function_name->u.constant.value.str.val, function_name->u.constant.value.str.len); if (zend_hash_find(CG(function_table), lcname, function_name->u.constant.value.str.len+1, (void **) &function)==FAILURE) { zend_do_begin_dynamic_function_call(function_name, prefix_len TSRMLS_CC); efree(lcname); @@ -3087,6 +3129,17 @@ error = 1; } + /* Remember names of defined classes in the current file + (or namespace if using multiple namespaces per file) */ + /* Create the used names table if needed (lazy construction) */ + if (!CG(current_used_names)) { + CG(current_used_names) = emalloc(sizeof(HashTable)); + zend_hash_init(CG(current_used_names), 0, NULL, NULL, 0); + } + /* Nothing is stored in the table, only the index is used. + Maybe a reference to what for and where the name was used can be stored to provide an extended error message */ + zend_hash_add(CG(current_used_names), lcname, Z_STRLEN(class_name->u.constant)+1, NULL, 0, NULL); + if (CG(current_namespace)) { /* Prefix class name with name of current namespace */ znode tmp; @@ -4772,6 +4825,11 @@ efree(CG(current_import)); CG(current_import) = NULL; } + if (CG(current_used_names)) { + zend_hash_destroy(CG(current_used_names)); + efree(CG(current_used_names)); + CG(current_used_names) = NULL; + } *CG(current_namespace) = name->u.constant; } @@ -4817,32 +4875,40 @@ zend_error(E_COMPILE_ERROR, "Cannot use %s as %s because '%s' is a special class name", Z_STRVAL_P(ns), Z_STRVAL_P(name), Z_STRVAL_P(name)); } - if (CG(current_namespace)) { - /* Prefix import name with current namespace name to avoid conflicts with classes */ - char *ns_name = emalloc(Z_STRLEN_P(CG(current_namespace)) + 2 + Z_STRLEN_P(name) + 1); - - zend_str_tolower_copy(ns_name, Z_STRVAL_P(CG(current_namespace)), Z_STRLEN_P(CG(current_namespace))); - ns_name[Z_STRLEN_P(CG(current_namespace))] = ':'; - ns_name[Z_STRLEN_P(CG(current_namespace))+1] = ':'; - memcpy(ns_name+Z_STRLEN_P(CG(current_namespace))+2, lcname, Z_STRLEN_P(name)+1); - if (zend_hash_exists(CG(class_table), ns_name, Z_STRLEN_P(CG(current_namespace)) + 2 + Z_STRLEN_P(name)+1)) { - char *tmp = zend_str_tolower_dup(Z_STRVAL_P(ns), Z_STRLEN_P(ns)); - - if (Z_STRLEN_P(ns) != Z_STRLEN_P(CG(current_namespace)) + 2 + Z_STRLEN_P(name) || - memcmp(tmp, ns_name, Z_STRLEN_P(ns))) { - zend_error(E_COMPILE_ERROR, "Cannot use %s as %s because the name is already in use", Z_STRVAL_P(ns), Z_STRVAL_P(name)); + /* Imported name must not conflict with other defined names */ + if (CG(current_used_names) && + zend_hash_exists(CG(current_used_names), lcname, Z_STRLEN_P(name)+1)) { + int alias_clash = 1; + + /* Check if the conflicting import is actually pointing to a different name that the one defined */ + int longname_len = Z_STRLEN_P(ns); + int conflictname_len = Z_STRLEN_P(name); + if (CG(current_namespace)) { + conflictname_len += Z_STRLEN_P(CG(current_namespace)) + 2; + } + if (longname_len == conflictname_len) { + /* Rebuild the conflicting name and compare */ + char *lclongname, *lcconflictname, *tmp; + lclongname = zend_str_tolower_dup(Z_STRVAL_P(ns), Z_STRLEN_P(ns)); + tmp = lcconflictname = emalloc(conflictname_len + 1); + if (CG(current_namespace)) { + zend_str_tolower_copy(tmp, Z_STRVAL_P(CG(current_namespace)), Z_STRLEN_P(CG(current_namespace))); + tmp += Z_STRLEN_P(CG(current_namespace)); + tmp[0] = ':'; + tmp[1] = ':'; + tmp += 2; } - efree(tmp); + memcpy(tmp, lcname, Z_STRLEN_P(name)+1); + if (memcmp(lclongname, lcconflictname, longname_len) == 0) { + alias_clash = 0; + } + efree(lclongname); + efree(lcconflictname); } - efree(ns_name); - } else if (zend_hash_exists(CG(class_table), lcname, Z_STRLEN_P(name)+1)) { - char *tmp = zend_str_tolower_dup(Z_STRVAL_P(ns), Z_STRLEN_P(ns)); - if (Z_STRLEN_P(ns) != Z_STRLEN_P(name) || - memcmp(tmp, lcname, Z_STRLEN_P(ns))) { + if (alias_clash) { zend_error(E_COMPILE_ERROR, "Cannot use %s as %s because the name is already in use", Z_STRVAL_P(ns), Z_STRVAL_P(name)); } - efree(tmp); } if (zend_hash_add(CG(current_import), lcname, Z_STRLEN_P(name)+1, &ns, sizeof(zval*), NULL) != SUCCESS) { @@ -4899,6 +4965,11 @@ efree(CG(current_import)); CG(current_import) = NULL; } + if (CG(current_used_names)) { + zend_hash_destroy(CG(current_used_names)); + efree(CG(current_used_names)); + CG(current_used_names) = NULL; + } } /* }}} */ Index: Zend/zend_globals.h =================================================================== RCS file: /repository/ZendEngine2/zend_globals.h,v retrieving revision 1.141.2.3.2.7.2.4 diff -u -r1.141.2.3.2.7.2.4 zend_globals.h --- Zend/zend_globals.h 20 Nov 2007 09:51:11 -0000 1.141.2.3.2.7.2.4 +++ Zend/zend_globals.h 23 Dec 2007 03:04:34 -0000 @@ -132,6 +132,8 @@ zval *current_namespace; HashTable *current_import; + HashTable *current_used_names; /* Names (class/function/const[TODO]) that + are known to be in use in the current file */ #ifdef ZEND_MULTIBYTE zend_encoding **script_encoding_list;