aboutsummaryrefslogtreecommitdiff
path: root/libc/docs/dev/code_style.rst
blob: c76f8874f3aef663b9e58aacdfb437f12da0d026 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
.. _code_style:

===================
The libc code style
===================

Naming style
============

For the large part, the libc project follows the general `coding standards of
the LLVM project <https://llvm.org/docs/CodingStandards.html>`_. The libc
project differs from that standard with respect to the naming style. The
differences are as follows:

#. **Non-const variables** - This includes function arguments, struct and
   class data members, non-const globals and local variables. They all use the
   ``snake_case`` style.
#. **const and constexpr variables** - They use the capitalized
   ``SNAKE_CASE`` irrespective of whether they are local or global.
#. **Function and methods** - They use the ``snake_case`` style like the
   non-const variables.
#. **Internal type names** - These are types which are internal to the libc
   implementation. They use the ``CaptilizedCamelCase`` style.
#. **Public names** - These are the names as prescribed by the standards and
   will follow the style as prescribed by the standards.

Macro style
===========

We define two kinds of macros:

#. **Build defined** macros are generated by `CMake` or `Bazel` and are passed
   down to the compiler with the ``-D`` command line flag. They start with the
   ``LIBC_COPT_`` prefix. They are used to tune the behavior of the libc.
   They either denote an action or define a constant.

#. **Code defined** macros are defined within the ``src/__support/macros``
   folder. They all start with the ``LIBC_`` prefix.

   * ``src/__support/macros/properties/`` - Build related properties like
     target architecture or enabled CPU features defined by introspecting
     compiler defined preprocessor definitions.

     * ``architectures.h`` - Target architecture properties.
       e.g., ``LIBC_TARGET_ARCH_IS_ARM``.
     * ``compiler.h`` - Host compiler properties.
       e.g., ``LIBC_COMPILER_IS_CLANG``.
     * ``cpu_features.h`` - Target cpu feature availability.
       e.g., ``LIBC_TARGET_CPU_HAS_AVX2``.
     * ``types.h`` - Type properties and availability.
       e.g., ``LIBC_COMPILER_HAS_FLOAT128``.
     * ``os.h`` - Target os properties.
       e.g., ``LIBC_TARGET_OS_IS_LINUX``.

   * ``src/__support/macros/config.h`` - Important compiler and platform
     features. Such macros can be used to produce portable code by
     parameterizing compilation based on the presence or lack of a given
     feature. e.g., ``LIBC_HAS_BUILTIN``
   * ``src/__support/macros/attributes.h`` - Attributes for functions, types,
     and variables. e.g., ``LIBC_UNUSED``
   * ``src/__support/macros/optimization.h`` - Portable macros for performance
     optimization. e.g., ``LIBC_LIKELY``, ``LIBC_LOOP_NOUNROLL``

Inline functions and variables defined in header files
======================================================

When defining functions and variables inline in header files, we follow certain
rules:

#. The functions should not be given file-static linkage. There can be class
   static methods defined inline however.
#. Instead of using the ``inline`` keyword, functions should be tagged with the
   ``LIBC_INLINE`` macro and variables should be tagged with the
   ``LIBC_INLINE_VAR`` macro defined in ``src/__support/macros/attributes.h``.
   For example:

   .. code-block:: c++

     LIBC_INLINE_VAR constexpr bool foo = true;

     LIBC_INLINE ReturnType function_defined_inline(ArgType arg) {
       ...
     }

#. The ``LIBC_INLINE`` tag should also be added to functions which have
   definitions that are implicitly inline. Examples of such functions are
   class methods (static and non-static) defined inline and ``constexpr``
   functions.

Setting ``errno`` from runtime code
===================================

Many libc functions set ``errno`` to indicate an error condition. If LLVM's libc
is being used as the only libc, then the ``errno`` from LLVM's libc is affected.
If LLVM's libc is being used in the :ref:`overlay_mode`, then the ``errno`` from
the system libc is affected. When a libc function, which can potentially affect
the ``errno``, is called from a unit test, we do not want the global ``errno``
(as in, the ``errno`` of the process thread running the unit test) to be
affected. If the global ``errno`` is affected, then the operation of the unit
test infrastructure itself can be affected. To avoid perturbing the unit test
infrastructure around the setting of ``errno``, the following rules are to be
followed:

#. A special macro named ``libc_errno`` defined in ``src/errno/libc_errno.h``
   should be used when setting ``errno`` from libc runtime code. For example,
   code to set ``errno`` to ``EINVAL`` should be:

   .. code-block:: c++

    libc_errno = EINVAL;

#. ``errno`` should be set just before returning from the implementation of the
   public function. It should not be set from within helper functions. Helper
   functions should use idiomatic C++ constructs like
   `cpp::optional <https://github.com/llvm/llvm-project/blob/main/libc/src/__support/CPP/optional.h>`_
   and
   `ErrorOr <https://github.com/llvm/llvm-project/blob/main/libc/src/__support/error_or.h>`_
   to return error values.

#. The header file ``src/errno/libc_errno.h`` is shipped as part of the target
   corresponding to the ``errno`` entrypoint ``libc.src.errno.errno``. We do
   not in general allow dependencies between entrypoints. However, the ``errno``
   entrypoint is the only exceptional entrypoint on which other entrypoints
   should explicitly depend on if they set ``errno`` to indicate error
   conditions.

Assertions in libc runtime code
===============================

The libc developers should, and are encouraged to, use assertions freely in
the libc runtime code. However, the assertion should be listed via the macro
``LIBC_ASSERT`` defined in ``src/__support/libc_assert.h``. This macro can be
used from anywhere in the libc runtime code. Internally, all it does is to
print the assertion expression and exit. It does not implement the semantics
of the standard ``assert`` macro. Hence, it can be used from any where in the
libc runtime code without causing any recursive calls or chicken-and-egg
situations.

Allocations in the libc runtime code
====================================

Some libc functions allocate memory. For example, the ``strdup`` function
allocates new memory into which the input string is duplicated. Allocations
are typically done by calling a function from the ``malloc`` family of
functions. Such functions can fail and return an error value to indicate
allocation failure. To conform to standards, the libc should handle
allocation failures gracefully and surface the error conditions to the user
code as appropriate. Since LLVM's libc is implemented in C++, we want
allocations and deallocations to employ C++ operators ``new`` and ``delete``
as they implicitly invoke constructors and destructors respectively. However,
if we use the default ``new`` and ``delete`` operators, the libc will end up
depending on the C++ runtime. To avoid such a dependence, and to handle
allocation failures gracefully, we use special ``new`` and ``delete`` operators
defined in
`src/__support/CPP/new.h <https://github.com/llvm/llvm-project/blob/main/libc/src/__support/CPP/new.h>`_.
Allocations and deallocations using these operators employ a pattern like
this:

.. code-block:: c++

   #include "src/__support/CPP/new.h"

   ...

     LIBC_NAMESPACE::AllocChecker ac;
     auto *obj = new (ac) Type(...);
     if (!ac) {
       // handle allocator failure.
     }
     ...
     delete obj;

The only exception to using the above pattern is if allocating using the
``realloc`` function is of value. In such cases, prefer to use only the
``malloc`` family of functions for allocations and deallocations. Allocation
failures will still need to be handled gracefully. Further, keep in mind that
these functions do not call the constructors and destructors of the
allocated/deallocated objects. So, use these functions carefully and only
when it is absolutely clear that constructor and destructor invocation is
not required.

Warnings in sources
===================

We expect contributions to be free of warnings from the `minimum supported
compiler versions`__ (and newer).

.. __: https://libc.llvm.org/compiler_support.html#minimum-supported-versions