diff --git a/phpunit/src/CallCacheCodegenTest.php b/phpunit/src/CallCacheCodegenTest.php index 2058c34a..f987fbd0 100644 --- a/phpunit/src/CallCacheCodegenTest.php +++ b/phpunit/src/CallCacheCodegenTest.php @@ -43,6 +43,44 @@ public function testDynamicCallSitesUseRequestLocalTypePhpCaches(): void self::assertStringContainsString('typephp_get_method_call_cache(MethodCallCacheId cache_id)', $extension); } + public function testSlotAccessorsDeclareNoexceptWithoutChangingResolvingLookups(): void + { + global $translator; + $compiler = CompilerTest::create(TYPEPHP_ROOT_PATH); + $translator = $compiler; + $compiler->setBuildMode(CompilerBase::BUILD_MODE_EXT); + $compiler->setTargetName('noexcept_cache_accessors'); + $source = TYPEPHP_ROOT_PATH . '/phpunit/code/call-cache-sites.php'; + $compiler->addFiles([$source]); + $compiler->prepareFile($source); + $compiler->convertFile($source); + $headerFile = tempnam(sys_get_temp_dir(), 'typephp-noexcept-'); + try { + $compiler->genDataDeclarations($headerFile); + $header = file_get_contents($headerFile); + $extension = file_get_contents($compiler->genExtension()); + foreach ([ + 'get_property_cache(PropertyCacheId cache_id)', + 'typephp_get_method_call_cache(MethodCallCacheId cache_id)', + 'typephp_get_function_call_cache(FunctionCallCacheId cache_id)', + ] as $signature) { + self::assertStringContainsString($signature . ' noexcept;', $header); + self::assertStringContainsString($signature . ' noexcept {', $extension); + } + // Resolving lookups may throw and must retain that contract. + self::assertStringContainsString( + 'get_persistent_func(PersistentFuncId func_id, const php::Str &func_name);', + $header, + ); + self::assertStringContainsString( + 'get_persistent_func(PersistentFuncId func_id, const php::Str &func_name) {', + $extension, + ); + } finally { + unlink($headerFile); + } + } + public function testCallArgumentLimitRejectsBrokenUnboundedLowering(): void { $compiler = CompilerTest::create(TYPEPHP_ROOT_PATH); diff --git a/phpunit/src/CompilerBaseApiTest.php b/phpunit/src/CompilerBaseApiTest.php index e06e64cd..48a1450e 100644 --- a/phpunit/src/CompilerBaseApiTest.php +++ b/phpunit/src/CompilerBaseApiTest.php @@ -1499,7 +1499,7 @@ public function testLibraryFunctionHeaderExportsDefaultValueHelpersWithoutLitera $this->assertStringContainsString('extern php::Var _const_var_EXPORTED_ABI_STRING;', $dataHeader); $this->assertStringContainsString('extern php::Var _const_var_EXPORTED_ABI_ARRAY;', $dataHeader); $this->assertStringContainsString( - 'ZEND_ATTRIBUTE_CONST php::Str &get_str(uint32_t index);', + 'ZEND_ATTRIBUTE_CONST php::Str &get_str(uint32_t index) noexcept;', $dataHeader, ); $this->assertStringNotContainsString('_literal_strings', $dataHeader); @@ -1510,6 +1510,7 @@ public function testLibraryFunctionHeaderExportsDefaultValueHelpersWithoutLitera $extension = file_get_contents($extensionFile); $this->assertStringContainsString('php::Str php_exported_defaults_arg_0_default_value() {', $extension); $this->assertStringContainsString('static php::Str _literal_strings[]', $extension); + $this->assertStringContainsString('php::Str &get_str(uint32_t index) noexcept {', $extension); $this->assertStringContainsString('return get_str(', $extension); $this->assertStringContainsString('php::Array php_exported_variadic_arg_0_default_value() {', $extension); } diff --git a/src/Translator.php b/src/Translator.php index b3a465b6..e72f9b65 100644 --- a/src/Translator.php +++ b/src/Translator.php @@ -975,7 +975,7 @@ public function genDataDeclarations(string $file): void if ($this->literalStrings) { $lines[] = 'ZEND_ATTRIBUTE_CONST ' . Type::STR . ' &' - . self::LITERAL_STRING_GETTER . '(uint32_t index);' . PHP_EOL; + . self::LITERAL_STRING_GETTER . '(uint32_t index) noexcept;' . PHP_EOL; } foreach ($this->constants as $name => $constant) { @@ -1003,9 +1003,9 @@ public function genDataDeclarations(string $file): void $lines[] = 'zend_function *get_persistent_func(PersistentFuncId func_id, const php::Str &func_name);'; $lines[] = 'zend_function *get_persistent_method(PersistentFuncId func_id, const php::Str &method_name, PersistentClassId class_id, const php::Str &class_name);'; $lines[] = 'uint32_t get_persistent_prop(PersistentPropertyId prop_id, const php::Str &prop_name, const php::Str &class_name);' . PHP_EOL; - $lines[] = 'php::PropertyCacheSlot &get_property_cache(PropertyCacheId cache_id);' . PHP_EOL; - $lines[] = 'php::MethodCallCacheSlot &typephp_get_method_call_cache(MethodCallCacheId cache_id);' . PHP_EOL; - $lines[] = 'php::FunctionCallCacheSlot &typephp_get_function_call_cache(FunctionCallCacheId cache_id);' . PHP_EOL; + $lines[] = 'php::PropertyCacheSlot &get_property_cache(PropertyCacheId cache_id) noexcept;' . PHP_EOL; + $lines[] = 'php::MethodCallCacheSlot &typephp_get_method_call_cache(MethodCallCacheId cache_id) noexcept;' . PHP_EOL; + $lines[] = 'php::FunctionCallCacheSlot &typephp_get_function_call_cache(FunctionCallCacheId cache_id) noexcept;' . PHP_EOL; foreach ($this->getClassLikesWithConstants() as $classDef) { foreach ($classDef->constants as $constant) { @@ -1275,15 +1275,15 @@ private function doGenExtension(): string return value - 1024; } -php::PropertyCacheSlot &get_property_cache(PropertyCacheId cache_id) { +php::PropertyCacheSlot &get_property_cache(PropertyCacheId cache_id) noexcept { return php_request_cache->property_cache_map[static_cast(cache_id)]; } -php::MethodCallCacheSlot &typephp_get_method_call_cache(MethodCallCacheId cache_id) { +php::MethodCallCacheSlot &typephp_get_method_call_cache(MethodCallCacheId cache_id) noexcept { return php_request_cache->method_call_cache_map[static_cast(cache_id)]; } -php::FunctionCallCacheSlot &typephp_get_function_call_cache(FunctionCallCacheId cache_id) { +php::FunctionCallCacheSlot &typephp_get_function_call_cache(FunctionCallCacheId cache_id) noexcept { return php_request_cache->function_call_cache_map[static_cast(cache_id)]; } CODE; @@ -1302,7 +1302,7 @@ private function doGenExtension(): string } $code .= '};' . PHP_EOL . PHP_EOL; $code .= 'ZEND_ATTRIBUTE_CONST ' . Type::STR . ' &' - . self::LITERAL_STRING_GETTER . '(uint32_t index) {' . PHP_EOL; + . self::LITERAL_STRING_GETTER . '(uint32_t index) noexcept {' . PHP_EOL; $code .= $this->getIndent() . 'return ' . self::LITERAL_STRINGS . '[index];' . PHP_EOL; $code .= '}' . PHP_EOL . PHP_EOL; } else {