From 5a714a2410fce61a99f7c7825d192cb5bf4d2c31 Mon Sep 17 00:00:00 2001 From: Mohammed Ashraf Date: Sat, 11 Apr 2026 20:19:01 +0000 Subject: [PATCH 1/3] [libc][hdrgen] Extend guard attribute support for types Co-authored-by: un-pixelated --- libc/utils/hdrgen/hdrgen/header.py | 64 +++++++++++-------- libc/utils/hdrgen/hdrgen/type.py | 5 +- libc/utils/hdrgen/hdrgen/yaml_to_classes.py | 16 ++++- .../tests/expected_output/func_guarding.h | 34 ++++++++++ .../tests/expected_output/type_guarding.h | 27 ++++++++ .../hdrgen/tests/input/func_guarding.yaml | 38 +++++++++++ .../hdrgen/tests/input/type_guarding.yaml | 19 ++++++ libc/utils/hdrgen/tests/test_integration.py | 14 ++++ 8 files changed, 188 insertions(+), 29 deletions(-) create mode 100644 libc/utils/hdrgen/tests/expected_output/func_guarding.h create mode 100644 libc/utils/hdrgen/tests/expected_output/type_guarding.h create mode 100644 libc/utils/hdrgen/tests/input/func_guarding.yaml create mode 100644 libc/utils/hdrgen/tests/input/type_guarding.yaml diff --git a/libc/utils/hdrgen/hdrgen/header.py b/libc/utils/hdrgen/hdrgen/header.py index e2ebbdb6e519a..fb97e1129cb1a 100644 --- a/libc/utils/hdrgen/hdrgen/header.py +++ b/libc/utils/hdrgen/hdrgen/header.py @@ -175,6 +175,7 @@ def includes(self): PurePosixPath("llvm-libc-types") / f"{typ.name}.h", ) for typ in self.all_types() + if typ.guard is None } | { PurePosixPath("llvm-libc-macros") / f"{attr.split('(')[0]}.h" @@ -239,7 +240,7 @@ def relpath(file): # It's implicitly emitted here when using the default template so # it can get the right relative path. Custom template files should # all have it explicitly with their right particular relative path. - return [ + content = [ f"#include {file}" for file in ([f'"{relpath(COMMON_HEADER)!s}"'] if with_common else []) + sorted( @@ -248,6 +249,25 @@ def relpath(file): ) ] + # Add guarded types + current_guard = None + has_seen_guard = False + for typ in sorted(self.types): + if typ.guard is None: + continue + if not has_seen_guard: + has_seen_guard = True + content.append("") + path = COMPILER_HEADER_TYPES.get( + typ.name, + PurePosixPath("llvm-libc-types") / f"{typ.name}.h", + ) + current_guard = self.__emit_guard(content, current_guard, typ.guard) + content.append(f'#include "{relpath(path)!s}"') + self.__emit_guard(content, current_guard, None) + + return content + def macro_lines(self): content = [] for macro in sorted(self.macros): @@ -295,32 +315,13 @@ def public_api(self): # elide the blank line between the declarations. if last_name == function.name_without_underscores(): content.pop() - if function.guard == None and current_guard == None: - content.append(str(function) + " __NOEXCEPT;") - content.append("") - else: - if current_guard == None: - current_guard = function.guard - content.append(f"#ifdef {current_guard}") - content.append(str(function) + " __NOEXCEPT;") - content.append("") - elif current_guard == function.guard: - content.append(str(function) + " __NOEXCEPT;") - content.append("") - else: - content.pop() - content.append(f"#endif // {current_guard}") - content.append("") - current_guard = function.guard - if current_guard is not None: - content.append(f"#ifdef {current_guard}") - content.append(str(function) + " __NOEXCEPT;") - content.append("") - last_name = function.name_without_underscores() - if current_guard != None: - content.pop() - content.append(f"#endif // {current_guard}") + current_guard = self.__emit_guard( + content, current_guard, function.guard + ) + content.append(str(function) + " __NOEXCEPT;") content.append("") + last_name = function.name_without_underscores() + self.__emit_guard(content, current_guard, None) # Emit object declarations. content.extend(str(object) for object in self.objects) @@ -338,3 +339,14 @@ def json_data(self): "standards": self.standards, "includes": sorted(str(file) for file in {COMMON_HEADER} | self.includes()), } + + def __emit_guard(self, content, current_guard, new_guard): + if current_guard != new_guard: + if current_guard is not None: + if content[-1] == "": + content.pop() + content.append(f"#endif // {current_guard}") + content.append("") + if new_guard is not None: + content.append(f"#ifdef {new_guard}") + return new_guard diff --git a/libc/utils/hdrgen/hdrgen/type.py b/libc/utils/hdrgen/hdrgen/type.py index 20c1881a9379a..3a1f3e2eefe93 100644 --- a/libc/utils/hdrgen/hdrgen/type.py +++ b/libc/utils/hdrgen/hdrgen/type.py @@ -10,6 +10,7 @@ class Type(Symbol): - # A type so far carries no specific information beyond its name. - def __init__(self, name): + # A type carries its name and an optional guard. + def __init__(self, name, guard=None): super().__init__(name) + self.guard = guard diff --git a/libc/utils/hdrgen/hdrgen/yaml_to_classes.py b/libc/utils/hdrgen/hdrgen/yaml_to_classes.py index 85aa3267b5274..13f75dab60511 100644 --- a/libc/utils/hdrgen/hdrgen/yaml_to_classes.py +++ b/libc/utils/hdrgen/hdrgen/yaml_to_classes.py @@ -52,7 +52,21 @@ def yaml_to_classes(yaml_data, header_class, entry_points=None): types = yaml_data.get("types", []) sorted_types = sorted(types, key=lambda x: x["type_name"]) for type_data in sorted_types: - header.add_type(Type(type_data["type_name"])) + type_name = type_data["type_name"] + type_guard = type_data.get("guard") + # If a type has a guard, the macro it references must exist in + # the same yaml file with a macro_header attribute. + if type_guard is not None and not any( + macro_data["macro_name"] == type_guard + and "macro_header" in macro_data + for macro_data in yaml_data.get("macros", []) + ): + raise ValueError( + f"Type '{type_name}' has guard '{type_guard}' but no macro with " + f"macro_header '{type_guard}' was found in this file." + ) + + header.add_type(Type(type_name, type_guard)) for enum_data in yaml_data.get("enums", []): header.add_enumeration( diff --git a/libc/utils/hdrgen/tests/expected_output/func_guarding.h b/libc/utils/hdrgen/tests/expected_output/func_guarding.h new file mode 100644 index 0000000000000..440710e691d4b --- /dev/null +++ b/libc/utils/hdrgen/tests/expected_output/func_guarding.h @@ -0,0 +1,34 @@ +//===-- Standard C header --===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===---------------------------------------------------------------------===// + +#ifndef _LLVM_LIBC_FUNC_GUARDING_H +#define _LLVM_LIBC_FUNC_GUARDING_H + +#include "__llvm-libc-common.h" + +__BEGIN_C_DECLS + +#ifdef LIBC_TYPES_HAS_FLOAT128 +void func_all_guarded(int) __NOEXCEPT; +#endif // LIBC_TYPES_HAS_FLOAT128 + +#ifdef LIBC_TYPES_HAS_FLOAT16 +int func_guarded_a(int) __NOEXCEPT; + +int func_guarded_b(int) __NOEXCEPT; +#endif // LIBC_TYPES_HAS_FLOAT16 + +#ifdef LIBC_TYPES_HAS_FLOAT128 +int func_guarded_c(int) __NOEXCEPT; +#endif // LIBC_TYPES_HAS_FLOAT128 + +int func_plain(int) __NOEXCEPT; + +__END_C_DECLS + +#endif // _LLVM_LIBC_FUNC_GUARDING_H diff --git a/libc/utils/hdrgen/tests/expected_output/type_guarding.h b/libc/utils/hdrgen/tests/expected_output/type_guarding.h new file mode 100644 index 0000000000000..33a6fbd22d8d0 --- /dev/null +++ b/libc/utils/hdrgen/tests/expected_output/type_guarding.h @@ -0,0 +1,27 @@ +//===-- Standard C header --===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===---------------------------------------------------------------------===// + +#ifndef _LLVM_LIBC_TYPE_GUARDING_MIXED_H +#define _LLVM_LIBC_TYPE_GUARDING_MIXED_H + +#include "__llvm-libc-common.h" +#include "llvm-libc-macros/float16-macro.h" +#include "llvm-libc-macros/size_t-macro.h" +#include "llvm-libc-types/myType.h" +#include + +#ifdef LIBC_TYPES_HAS_FLOAT16 +#include "llvm-libc-types/float16.h" +#endif // LIBC_TYPES_HAS_FLOAT16 + +#ifdef LIBC_TYPES_HAS_SIZE_T +#include "llvm-libc-types/size_t.h" +#include "llvm-libc-types/ssize_t.h" +#endif // LIBC_TYPES_HAS_SIZE_T + +#endif // _LLVM_LIBC_TYPE_GUARDING_MIXED_H diff --git a/libc/utils/hdrgen/tests/input/func_guarding.yaml b/libc/utils/hdrgen/tests/input/func_guarding.yaml new file mode 100644 index 0000000000000..eb4093d235e17 --- /dev/null +++ b/libc/utils/hdrgen/tests/input/func_guarding.yaml @@ -0,0 +1,38 @@ +header: func_guarding.h +standards: + - stdc +functions: + - name: func_plain + return_type: int + arguments: + - type: int + standards: + - stdc + - name: func_guarded_a + return_type: int + arguments: + - type: int + standards: + - stdc + guard: LIBC_TYPES_HAS_FLOAT16 + - name: func_guarded_b + return_type: int + arguments: + - type: int + standards: + - stdc + guard: LIBC_TYPES_HAS_FLOAT16 + - name: func_guarded_c + return_type: int + arguments: + - type: int + standards: + - stdc + guard: LIBC_TYPES_HAS_FLOAT128 + - name: func_all_guarded + return_type: void + arguments: + - type: int + standards: + - stdc + guard: LIBC_TYPES_HAS_FLOAT128 diff --git a/libc/utils/hdrgen/tests/input/type_guarding.yaml b/libc/utils/hdrgen/tests/input/type_guarding.yaml new file mode 100644 index 0000000000000..b1e7fb14e5d3b --- /dev/null +++ b/libc/utils/hdrgen/tests/input/type_guarding.yaml @@ -0,0 +1,19 @@ +header: type_guarding_mixed.h +standards: + - stdc + +macros: + - macro_name: LIBC_TYPES_HAS_SIZE_T + macro_header: size_t-macro.h + - macro_name: LIBC_TYPES_HAS_FLOAT16 + macro_header: float16-macro.h + +types: + - type_name: size_t + guard: LIBC_TYPES_HAS_SIZE_T + - type_name: ssize_t + guard: LIBC_TYPES_HAS_SIZE_T + - type_name: float16 + guard: LIBC_TYPES_HAS_FLOAT16 + - type_name: uint8_t + - type_name: myType diff --git a/libc/utils/hdrgen/tests/test_integration.py b/libc/utils/hdrgen/tests/test_integration.py index 8848afe29d50f..ef7e158952cfc 100644 --- a/libc/utils/hdrgen/tests/test_integration.py +++ b/libc/utils/hdrgen/tests/test_integration.py @@ -96,6 +96,20 @@ def test_generate_macro_only_header(self): self.run_script(yaml_file, output_file) self.compare_files(output_file, expected_output_file) + def test_type_guarding(self): + yaml_file = self.source_dir / "input/type_guarding.yaml" + expected_output_file = self.source_dir / "expected_output/type_guarding.h" + output_file = self.output_dir / "type_guarding.h" + self.run_script(yaml_file, output_file) + self.compare_files(output_file, expected_output_file) + + def test_func_guarding(self): + yaml_file = self.source_dir / "input/func_guarding.yaml" + expected_output_file = self.source_dir / "expected_output/func_guarding.h" + output_file = self.output_dir / "func_guarding.h" + self.run_script(yaml_file, output_file) + self.compare_files(output_file, expected_output_file) + def main(): parser = argparse.ArgumentParser(description="TestHeaderGenIntegration arguments") parser.add_argument( From f11acef2e1296fabf83769a0c998d9276d56ffe0 Mon Sep 17 00:00:00 2001 From: Mohammed Ashraf Date: Sat, 11 Apr 2026 21:12:26 +0000 Subject: [PATCH 2/3] fix format --- libc/utils/hdrgen/hdrgen/header.py | 4 +--- libc/utils/hdrgen/hdrgen/yaml_to_classes.py | 3 +-- libc/utils/hdrgen/tests/test_integration.py | 1 + 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/libc/utils/hdrgen/hdrgen/header.py b/libc/utils/hdrgen/hdrgen/header.py index fb97e1129cb1a..bc682f614bd35 100644 --- a/libc/utils/hdrgen/hdrgen/header.py +++ b/libc/utils/hdrgen/hdrgen/header.py @@ -315,9 +315,7 @@ def public_api(self): # elide the blank line between the declarations. if last_name == function.name_without_underscores(): content.pop() - current_guard = self.__emit_guard( - content, current_guard, function.guard - ) + current_guard = self.__emit_guard(content, current_guard, function.guard) content.append(str(function) + " __NOEXCEPT;") content.append("") last_name = function.name_without_underscores() diff --git a/libc/utils/hdrgen/hdrgen/yaml_to_classes.py b/libc/utils/hdrgen/hdrgen/yaml_to_classes.py index 13f75dab60511..068f8cfa408f5 100644 --- a/libc/utils/hdrgen/hdrgen/yaml_to_classes.py +++ b/libc/utils/hdrgen/hdrgen/yaml_to_classes.py @@ -57,8 +57,7 @@ def yaml_to_classes(yaml_data, header_class, entry_points=None): # If a type has a guard, the macro it references must exist in # the same yaml file with a macro_header attribute. if type_guard is not None and not any( - macro_data["macro_name"] == type_guard - and "macro_header" in macro_data + macro_data["macro_name"] == type_guard and "macro_header" in macro_data for macro_data in yaml_data.get("macros", []) ): raise ValueError( diff --git a/libc/utils/hdrgen/tests/test_integration.py b/libc/utils/hdrgen/tests/test_integration.py index ef7e158952cfc..31a79e5121040 100644 --- a/libc/utils/hdrgen/tests/test_integration.py +++ b/libc/utils/hdrgen/tests/test_integration.py @@ -110,6 +110,7 @@ def test_func_guarding(self): self.run_script(yaml_file, output_file) self.compare_files(output_file, expected_output_file) + def main(): parser = argparse.ArgumentParser(description="TestHeaderGenIntegration arguments") parser.add_argument( From 308f6fac4dad1bf562b80226913eb3928014630f Mon Sep 17 00:00:00 2001 From: Mohammed Ashraf Date: Sat, 11 Apr 2026 23:11:32 +0000 Subject: [PATCH 3/3] fix naming inconsistencies --- libc/utils/hdrgen/tests/expected_output/type_guarding.h | 8 ++++---- libc/utils/hdrgen/tests/input/type_guarding.yaml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libc/utils/hdrgen/tests/expected_output/type_guarding.h b/libc/utils/hdrgen/tests/expected_output/type_guarding.h index 33a6fbd22d8d0..5d21fbc95b246 100644 --- a/libc/utils/hdrgen/tests/expected_output/type_guarding.h +++ b/libc/utils/hdrgen/tests/expected_output/type_guarding.h @@ -1,4 +1,4 @@ -//===-- Standard C header --===// +//===-- Standard C header --===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,8 +6,8 @@ // //===---------------------------------------------------------------------===// -#ifndef _LLVM_LIBC_TYPE_GUARDING_MIXED_H -#define _LLVM_LIBC_TYPE_GUARDING_MIXED_H +#ifndef _LLVM_LIBC_TYPE_GUARDING_H +#define _LLVM_LIBC_TYPE_GUARDING_H #include "__llvm-libc-common.h" #include "llvm-libc-macros/float16-macro.h" @@ -24,4 +24,4 @@ #include "llvm-libc-types/ssize_t.h" #endif // LIBC_TYPES_HAS_SIZE_T -#endif // _LLVM_LIBC_TYPE_GUARDING_MIXED_H +#endif // _LLVM_LIBC_TYPE_GUARDING_H diff --git a/libc/utils/hdrgen/tests/input/type_guarding.yaml b/libc/utils/hdrgen/tests/input/type_guarding.yaml index b1e7fb14e5d3b..b5f8f57b90db2 100644 --- a/libc/utils/hdrgen/tests/input/type_guarding.yaml +++ b/libc/utils/hdrgen/tests/input/type_guarding.yaml @@ -1,4 +1,4 @@ -header: type_guarding_mixed.h +header: type_guarding.h standards: - stdc