| /*{ AutoGen5 template -*- C++ -*- | |
| h | |
| (use-modules (srfi srfi-1)) | |
| }*/ | |
| // Copyright (C) 2023-2026 Free Software Foundation, Inc. | |
| // This file is part of the GNU ISO C++ Library. This library is free | |
| // software; you can redistribute it and/or modify it under the | |
| // terms of the GNU General Public License as published by the | |
| // Free Software Foundation; either version 3, or (at your option) | |
| // any later version. | |
| // This library is distributed in the hope that it will be useful, | |
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| // GNU General Public License for more details. | |
| // Under Section 7 of GPL version 3, you are granted additional | |
| // permissions described in the GCC Runtime Library Exception, version | |
| // 3.1, as published by the Free Software Foundation. | |
| // You should have received a copy of the GNU General Public License and | |
| // a copy of the GCC Runtime Library Exception along with this program; | |
| // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
| // <http://www.gnu.org/licenses/>. | |
| /*{ (dne "// ") }*/ | |
| /** @file bits/version.h | |
| * This is an internal header file, included by other library headers. | |
| * Do not attempt to use it directly. @headername{version} | |
| */ | |
| // Usage guide: | |
| // | |
| // In your usual header, do something like: | |
| // | |
| // #define __glibcxx_want_ranges | |
| // #define __glibcxx_want_concepts | |
| // #include <bits/version.h> | |
| // | |
| // This will generate the FTMs you named, and let you use them in your code as | |
| // if it was user code. All macros are also exposed under __glibcxx_NAME even | |
| // if unwanted, to permit bits and other FTMs to depend on them for conditional | |
| // computation without exposing extra FTMs to user code. | |
| #ifdef _GLIBCXX_SYSHDR | |
| #pragma GCC system_header | |
| #endif | |
| #include <bits/c++config.h> | |
| /*{ | |
| ;; Helper for dealing with autogens redefined (error) | |
| (define (ferror msg . args) | |
| (error (apply format (cons* #f msg args)))) | |
| ;; Helper function that, in the context of a single FTM value, generates the | |
| ;; condition expression that fulfills the specification of this value. See the | |
| ;; comment block in version.def for an explanation of the format this | |
| ;; function parses. | |
| (define (generate-cond) | |
| (define c++min #f) | |
| (define gnu++min #f) | |
| (define gthread #f) | |
| (define hosted #f) | |
| (define c++11-abi #f) | |
| (define extra-cond (get "extra_cond")) | |
| (define conds '()) | |
| (define (prepend x) | |
| (if x (set! conds (cons x conds)))) | |
| (if (string-null? extra-cond) | |
| (set! extra-cond #f)) | |
| (let ((cxxmin (get "cxxmin")) | |
| (gnuxxmin (get "gnuxxmin")) | |
| (getstdcond | |
| (lambda (var) | |
| (let ((ver (get var))) | |
| (if (not (string-null? ver)) | |
| (let ((std-cond (get (format #f "stds[~a]" ver)))) | |
| (if (string-null? std-cond) | |
| (ferror "Standard ~s invalid." ver)) | |
| std-cond) | |
| #f))))) | |
| (set! c++min (getstdcond "cxxmin")) | |
| (set! gnu++min (getstdcond "gnuxxmin"))) | |
| (let ((process-tristate | |
| (lambda (name) | |
| (let ((val (get name))) | |
| (cond | |
| ((equal? val "") #f) ; Don't test | |
| ((equal? val "yes") "") ; Test directly | |
| ((equal? val "no") "!") ; Invert | |
| (else (ferror "Bad ~a value ~a." name val))))))) | |
| (set! gthread (process-tristate "gthread")) | |
| (set! c++11-abi (process-tristate "cxx11abi")) | |
| (set! hosted (process-tristate "hosted"))) | |
| (prepend (if extra-cond (format #f "(~a)" extra-cond) #f)) | |
| (prepend (if hosted (format #f "~a~a" hosted "_GLIBCXX_HOSTED") #f)) | |
| (prepend (if gthread (format #f "~a~a" gthread "defined(_GLIBCXX_HAS_GTHREADS)") #f)) | |
| (prepend (if c++11-abi (format #f "~a~a" c++11-abi "_GLIBCXX_USE_CXX11_ABI") #f)) | |
| (prepend | |
| (let ((strict "defined(__STRICT_ANSI__)") | |
| (c++ "__cplusplus")) | |
| (cond | |
| ((or (and (equal? c++min gnu++min) c++min) | |
| (and (not gnu++min) c++min)) | |
| ;; If we have both values, and they are equal, or we only have gnu++min, | |
| ;; we want to output a simple check. | |
| (format #f "(~a ~a)" c++ c++min)) | |
| ((and gnu++min c++min) | |
| ;; We have differing cases for strict and non-strict modes. | |
| (format #f "((~a && ~a ~a) || (!~a && ~a ~a))" | |
| strict c++ c++min | |
| strict c++ gnu++min)) | |
| ((and gnu++min (not c++min)) | |
| (format #f "(!~a && (~a ~a))" strict c++ gnu++min)) | |
| (else #f)))) | |
| (string-join conds " && " 'strict-infix)) | |
| }*/ | |
| /*{ FOR ftms | |
| }*/#if !defined(__cpp_lib_/*{name}*/) | |
| /*{ FOR values }*//*{ # | |
| This macro block defines two versions of each FTM: | |
| 1. __glibcxx_NAME, which is defined as long its conditions are met, and | |
| 2. __cpp_lib_NAME, which is defined only if __glibcxx_want_NAME is defined | |
| and no_stdname is not set. | |
| This allows FTMs to depend on each other in their definitions without messing | |
| with the exported values. | |
| This can also be used by bits that do not want to expose FTMs that they can't | |
| implement. | |
| }*/# /*{(unless (first-for?) "el")}*/if /*{(generate-cond)}*/ | |
| # define __glibcxx_/*{name}*/ /*{v}*/L | |
| # if defined(__glibcxx_want_all) || defined(__glibcxx_want_/*{name}*/)/*{ | |
| IF (not (exist? "no_stdname")) }*/ | |
| # define /*{ | |
| ;; Compute the name for this FTM based on stdname/name. | |
| (if (exist? "stdname") | |
| (get "stdname") | |
| (format #f "__cpp_lib_~a" (get "name"))) | |
| }*/ /*{v}*/L/*{ | |
| ENDIF no_std_name }*/ | |
| # endif | |
| /*{ ENDFOR values | |
| }*/# endif | |
| #endif /* !defined(__cpp_lib_/*{name}*/) */ | |
| #undef __glibcxx_want_/*{name | |
| }*//*{ (unless (last-for?) "\n\n" "\n")}*/ | |
| /*{ ENDFOR ftms }*//*{ | |
| ;; Helper that generates [LO, HI]. | |
| (define (closed-int-set lo hi) | |
| (iota (+ (- hi lo) 1) lo)) | |
| ;; Sanity checking for duplicates and for value order. | |
| (let ((ht (make-hash-table (count "ftms")))) | |
| (for-each | |
| (lambda (idx) | |
| (let ((name (get (format #f "ftms[~a].name" idx)))) | |
| (if (string-null? name) (ferror "No name for FTM ~a" idx)) | |
| (let ((cur (cdr (or (hash-get-handle ht name) '(1 . 0))))) | |
| (hash-set! ht name (+ cur 1))))) | |
| (closed-int-set (low-lim "ftms") (high-lim "ftms"))) | |
| (if (hash-fold | |
| (lambda (name count prior) | |
| (if (= 1 count) | |
| prior | |
| (begin | |
| (printf "FTM %s appears %d times.\n" name count) | |
| #t))) | |
| #f ht) | |
| (error "Duplicates found."))) | |
| (define (check-value-order ftm key order) | |
| (let ((valmin 999999)) ; TODO(arsen): bump before year 10000 | |
| (for-each | |
| (lambda (vidx) | |
| (let* ((sval (get (format #f "values[~a].~a" vidx key))) | |
| (val (string->number sval))) | |
| (unless (string-null? sval) | |
| (unless val (ferror "Bad value in FTM ~a" ftm)) | |
| (if (order val valmin) | |
| (ferror "Found inverted ~s value in FTM ~a: ~a" key ftm sval)) | |
| (set! valmin val)))) | |
| (closed-int-set (low-lim "values") (high-lim "values"))))) | |
| }*//*{ FOR ftms }*//*{# | |
| Check for values that are in ascending order. Because it is generally the | |
| case that FTMs increase as the values of tests they probe for do, we check | |
| them to prevent simple, silly errors. | |
| We're iterating in a separate FOR block rather than in pure Guile since, for | |
| some reason, high-lim and low-lim do not work with complex names that include | |
| periods and indices (whereas exist? and others do). | |
| }*//*{ | |
| (let ((ftm (get "name"))) | |
| (check-value-order (get "name") "v" >) | |
| (check-value-order (get "name") "cxxmin" >) | |
| (check-value-order (get "name") "gnuxxmin" >)) | |
| }*//*{ ENDFOR ftms }*/ | |
| #undef __glibcxx_want_all |