Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 36 additions & 26 deletions libc/utils/hdrgen/hdrgen/header.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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(
Expand All @@ -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):
Expand Down Expand Up @@ -295,32 +315,11 @@ 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)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on my other comment, this would look like this:

self.emit_guard(content, current_guard, function.guard)
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)
Expand All @@ -338,3 +337,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):
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function naming, with leading underscores, is not used anywhere else in the file. I don't think it's a good idea to introduce it only for this new function

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you talking about the naming style?
IIRC this is how you make private methods in python (using double underscores).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.

But AFAIK, that sort of naming style is just a convention as Python doesn't have enforceable function visibility in that sense. In any case, pretty much all the functions in this file are "private" as well and they don't have leading underscores. We should choose only one style and make the whole file follow it.

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
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function can only ever return one value, and this value is from one of its inputs. So there's little sense in doing it this way.

I suggest you simply don't return anything from this function, and just use the argument value at the call sites directly.

5 changes: 3 additions & 2 deletions libc/utils/hdrgen/hdrgen/type.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
15 changes: 14 additions & 1 deletion libc/utils/hdrgen/hdrgen/yaml_to_classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,20 @@ 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(
Expand Down
34 changes: 34 additions & 0 deletions libc/utils/hdrgen/tests/expected_output/func_guarding.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//===-- Standard C header <func_guarding.h> --===//
//
// 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
27 changes: 27 additions & 0 deletions libc/utils/hdrgen/tests/expected_output/type_guarding.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//===-- Standard C header <type_guarding.h> --===//
//
// 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_H
#define _LLVM_LIBC_TYPE_GUARDING_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 <stdint.h>

#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_H
38 changes: 38 additions & 0 deletions libc/utils/hdrgen/tests/input/func_guarding.yaml
Original file line number Diff line number Diff line change
@@ -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
19 changes: 19 additions & 0 deletions libc/utils/hdrgen/tests/input/type_guarding.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
header: type_guarding.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
15 changes: 15 additions & 0 deletions libc/utils/hdrgen/tests/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,21 @@ 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(
Expand Down
Loading