mirror of
https://github.com/NVIDIA/open-gpu-kernel-modules.git
synced 2026-01-30 21:19:49 +00:00
190 lines
9.0 KiB
C++
190 lines
9.0 KiB
C++
/*
|
|
* SPDX-FileCopyrightText: Copyright (c) 1997-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
* SPDX-License-Identifier: MIT
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
* DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
#ifndef __NV_CTASSERT_H
|
|
#define __NV_CTASSERT_H
|
|
|
|
/*****************************************************************************/
|
|
|
|
/* Compile Time assert
|
|
* -------------------
|
|
* Use ct_assert(b) instead of assert(b) whenever the condition 'b' is constant,
|
|
* i.e. when 'b' can be determined at compile time.
|
|
*
|
|
* e.g.: check array size:
|
|
* ct_assert(__GL_ARRAYSIZE(arrayName) == constArraySize);
|
|
* e.g.: check struct size alignment:
|
|
* ct_assert(sizeof(struct xy) % 64 == 0);
|
|
*
|
|
* When available, standard C or C++ language constructs are used:
|
|
* - ISO C++11 defines the static_assert keyword
|
|
* - ISO C11 defines the _Static_assert keyword
|
|
*
|
|
* Note that recent versions of Clang support _Static_assert in all compiler modes
|
|
* - not just C11 mode - so we test for that in addition to checking explicitly for
|
|
* C11 and C++11 support.
|
|
*
|
|
* Those new language standards aren't available on all supported platforms; an
|
|
* alternate method which involves array declarations is employed in that case,
|
|
* described below.
|
|
*
|
|
* In C, there is a restriction where ct_assert() can be placed:
|
|
* It can be placed wherever a variable declaration can be placed, i.e.:
|
|
* - either anywhere at file scope
|
|
* - or inside a function at the beginning of any {} block; it may be mixed
|
|
* with variable declarations.
|
|
* e.g.:
|
|
* void function()
|
|
* {
|
|
* ct_assert(...); <-- ok \
|
|
* int a; |
|
|
* ct_assert(...); <-- ok | declaration section
|
|
* int b; |
|
|
* ct_assert(...); <-- ok /
|
|
*
|
|
* a = 0; -- first statement
|
|
*
|
|
* int c; <-- error
|
|
* ct_assert(...); <-- error
|
|
*
|
|
* {ct_assert(...);} <-- ok (uses its own block for ct_assert())
|
|
* }
|
|
*
|
|
* In CPP, there is no such restriction, i.e. it can be placed at file scope
|
|
* or anywhere inside a function or namespace or class (i.e., wherever
|
|
* a variable declaration may be placed).
|
|
*
|
|
* For C code, the mechanism of this ct_assert() is to declare a prototype
|
|
* of a function (e.g. compile_time_assertion_failed_in_line_555, if current
|
|
* line number is 555), which gets an array as argument:
|
|
* (1) the size of this array is +1, if b != 0 (ok)
|
|
* (2) the size of this array is -1, if b == 0 (error)
|
|
*
|
|
* In case (2) the compiler throws an error.
|
|
* e.g. msvc compiler:
|
|
* error C2118: negative subscript or subscript is too large
|
|
* e.g. gcc 2.95.3:
|
|
* size of array '_compile_time_assertion_failed_in_line_555' is negative
|
|
*
|
|
* In case the condition 'b' is not constant, the msvc compiler throws
|
|
* an error:
|
|
* error C2057: expected constant expression
|
|
* In this case the run time assert() must be used.
|
|
*
|
|
* For C++ code, we use a different technique because the function prototype
|
|
* declaration can have function linkage conflicts. If a single compilation
|
|
* unit has ct_assert() statements on the same line number in two different
|
|
* files, we would have:
|
|
*
|
|
* compile_time_assertion_failed_in_line_777(...); from xxx.cpp
|
|
* compile_time_assertion_failed_in_line_777(...); from xxx.h
|
|
*
|
|
* That is valid C++. But if either declaration were in an extern "C" block,
|
|
* the same function would be declared with two different linkage types and an
|
|
* error would ensue.
|
|
*
|
|
* Instead, ct_assert() for C++ simply declares an array typedef. As in the C
|
|
* version, we will get a compilation error if a typedef with a negative size
|
|
* is specified. Line numbers are not needed because C++ allows redundant
|
|
* typedefs as long as they are all defined the same way. But we tack them on
|
|
* anyway in case the typedef name is reported in compiler errors. C does not
|
|
* permit redundant typedefs, so this version should not be used in true C
|
|
* code. It can be used in extern "C" blocks of C++ code, however. As with
|
|
* the C version, MSVC will throw a "negative subscript" or "expected constant
|
|
* expression" error if the expression asserted is false or non-constant.
|
|
*
|
|
* Notes:
|
|
* - This ct_assert() does *not* generate any code or variable.
|
|
* Therefore there is no need to define it away for RELEASE builds.
|
|
* - The integration of the current source file number (__LINE__) ...
|
|
* ... would be required in C++ to allow multiple use inside the same
|
|
* class/namespace (if we used the C-style expansion), because the id
|
|
* must be unique.
|
|
* ... is nice to have in C or C++ if the compiler's error message contains
|
|
* the id (this is not the case for msvc)
|
|
* - Using three nested macros instead of only one is necessary to get the id
|
|
* compile_time_assertion_failed_in_line_555
|
|
* instead of
|
|
* compile_time_assertion_failed_in_line___LINE__
|
|
*/
|
|
|
|
#if defined(__clang__)
|
|
# ifndef __has_extension
|
|
# define __has_extension __has_feature // Compatibility with Clang pre-3.0 compilers.
|
|
# endif
|
|
# define CLANG_C_STATIC_ASSERT __has_extension(c_static_assert)
|
|
#else
|
|
# define CLANG_C_STATIC_ASSERT 0
|
|
#endif
|
|
|
|
// Adding this macro to fix MISRA 2012 rule 20.12
|
|
#define NV_CTASSERT_STRINGIFY_MACRO(b) #b
|
|
|
|
#if (defined(__cplusplus) && __cplusplus >= 201103L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201103L)
|
|
// ISO C++11 defines the static_assert keyword
|
|
# define ct_assert(b) static_assert((b), "Compile time assertion failed: " NV_CTASSERT_STRINGIFY_MACRO(b))
|
|
# define ct_assert_i(b,line) static_assert((b), "Compile time assertion failed: " NV_CTASSERT_STRINGIFY_MACRO(b)NV_CTASSERT_STRINGIFY_MACRO(line))
|
|
#elif !defined(NVOC) && ((defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) || CLANG_C_STATIC_ASSERT)
|
|
// ISO C11 defines the _Static_assert keyword
|
|
# define ct_assert(b) _Static_assert((b), "Compile time assertion failed: " NV_CTASSERT_STRINGIFY_MACRO(b))
|
|
# define ct_assert_i(b,line) _Static_assert((b), "Compile time assertion failed: " NV_CTASSERT_STRINGIFY_MACRO(b)NV_CTASSERT_STRINGIFY_MACRO(line))
|
|
#else
|
|
// For compilers which don't support ISO C11 or C++11, we fall back to an
|
|
// array (type) declaration
|
|
# define ct_assert(b) ct_assert_i(b,__LINE__)
|
|
# define ct_assert_i(b,line) ct_assert_ii(b,line)
|
|
# ifdef __cplusplus
|
|
# define ct_assert_ii(b,line) typedef char compile_time_assertion_failed_in_line_##line[(b)?1:-1]
|
|
# else
|
|
/*
|
|
* The use of a function prototype "void compile_time_assertion_failed_in_line_##line(..)
|
|
* above violates MISRA-C 2012 Rule 8.6 since the rule disallows a function
|
|
* declaration without a definition. To fix the MISRA rule, the cplusplus style
|
|
* 'typdef char compile_time_assertion_failed_in_line_##line'
|
|
* is acceptable, but doesn't work for typical C code since there can be duplicate
|
|
* line numbers leading to duplicate typedefs which C doesn't allow.
|
|
*
|
|
* The following macro uses the predefined macro __COUNTER__ to create unique
|
|
* typedefs that fixes the MISRA violations. However, not all C compilers support
|
|
* that macro and even for compilers that support it, the underlying code makes
|
|
* use of variably modified identifiers in ct_assert that makes the use of this
|
|
* unviable.
|
|
*
|
|
* For now restrict the use of MACRO only on
|
|
* i) GCC 4.3.0 and above that supports __COUNTER__ macro
|
|
* ii) Specifically the Falcon port of the compiler since the use of variably
|
|
* modified identifiers have been removed on those projects
|
|
*
|
|
* TBD: Enable the macro on MSVC and CLANG pending
|
|
*/
|
|
# if defined(__GNUC__) && ((__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) >= 40300) && defined(GCC_FALCON)
|
|
# define ct_assert_ii(b,line) ct_assert_iii(b,line,__COUNTER__)
|
|
# define ct_assert_iii(b,line,cntr) ct_assert_cntr(b,line,cntr)
|
|
# define ct_assert_cntr(b,line,cntr) typedef char cnt##cntr##_compile_time_assertion_failed_in_line_##line[(b)?1:-1] __attribute__((unused))
|
|
# else
|
|
# define ct_assert_ii(b,line) void compile_time_assertion_failed_in_line_##line(int _compile_time_assertion_failed_in_line_##line[(b) ? 1 : -1])
|
|
# endif
|
|
# endif
|
|
#endif
|
|
|
|
#endif // __NV_CTASSERT_H
|