@@ -1880,6 +1880,248 @@ top-level modification. (This is the reason that it is not permitted to set
18801880``MACRO_INVOCATION_TREE_IN_IL `` to TRUE without also setting
18811881``FULLY_RESOLVED_MACRO_POSITIONS `` to TRUE.)
18821882
1883+ Unicode Version-Dependent Features
1884+ ==================================
1885+
1886+ The front end has three distinct features that depend on the definitions
1887+ and classifications of characters in the Unicode standard and thus might
1888+ need to be updated when new versions of Unicode are released. The following
1889+ subsections discuss each of these features and what is involved in a potential
1890+ update.
1891+
1892+ Classification of Identifier Characters
1893+ ---------------------------------------
1894+
1895+ The front end must, of course, determine whether a given character can
1896+ appear in a C/C++ identifier in order to find the start and end of
1897+ identifier tokens during lexical analysis. There is also a distinction
1898+ between characters that can begin an identifier and those that can appear
1899+ only after the initial character; for example, ``'0' `` cannot be the first
1900+ character of an identifier but it is valid in the succeeding positions.
1901+
1902+ For single-byte character sets, this classification is done using boolean
1903+ arrays indexed by the character value; see the declarations of
1904+ ``is_id_char ``, ``is_id_char_no_mbc ``, and ``char_ends_id `` in
1905+ ``lexical.h `` and their initialization in ``lexical_one_time_init `` in
1906+ ``lexical.c `` for details.
1907+
1908+ The situation is more complicated for multi-byte characters, whether
1909+ appearing directly in the source or via a *universal-character-name *. For
1910+ C++23 (and, because the relevant paper was adopted as a defect report, for
1911+ previous versions as well) and C23, the determination is based on the
1912+ Unicode ``XID_Start `` and ``XID_Continue `` Derived Properties as specified
1913+ in `www.unicode.org/Public/UCD/latest/ucd/DerivedCoreProperties.txt
1914+ <https://www.unicode.org/Public/UCD/latest/ucd/DerivedCoreProperties.txt> `__.
1915+ (Specific versions of this file can be found by replacing ``UCD/latest ``
1916+ with the version number, e.g., ``15.1.0 ``, in the URL.) Earlier versions of
1917+ the C and C++ standards used different methods to specify these
1918+ classifications, however, and the front end continues to support those
1919+ variants for backward compatibility.
1920+
1921+ The mechanism for achieving compatibility with multiple classification
1922+ schemes is the ``UCN_table `` array, defined in ``lexical.c ``. The elements
1923+ of the array are objects of the following struct:
1924+
1925+ .. code :: c++
1926+
1927+ typedef struct a_UCN_range {
1928+ unsigned long start; /* The first character in the range. */
1929+ unsigned long end; / * The last character in the range. */
1930+ a_byte dialects;
1931+ / * A bit set indicating the dialects for which this
1932+ range of characters is accepted. See below for
1933+ the encoding masks. */
1934+ a_byte non_initial_dialects;
1935+ / * A bit set indicating the dialects for which this
1936+ range of characters is not permitted as the
1937+ first character of an identifier. This uses the
1938+ same encoding as dialects. */
1939+ } a_UCN_range;
1940+
1941+ Characters tend to occur in groups, so to reduce the storage requirements
1942+ of the array, each element describes a contiguous range of characters, all
1943+ of which share the same treatment in all of the supported classification
1944+ schemes. The elements of the array are sorted in strictly-ascending order
1945+ of code point so that the array can be efficiently searched using a binary
1946+ search. The ``dialects `` and ``non_initial_dialects `` members are bit sets
1947+ with each bit representing a different language dialect, specifying how the
1948+ characters in the specified range are classified in the various
1949+ dialects. The C++23/C23 dialect is represented by the ``UAX44 `` bit (so
1950+ named because the ``XID_Start `` and ``XID_Continue `` properties are
1951+ described in Unicode Annex #44).
1952+
1953+ From the perspective of updating this table when new versions of Unicode
1954+ are published, the principal requirement of this table is that all members
1955+ of a given character range must be classified the same way in all of the
1956+ supported dialects. A change in the classification of a character in a new
1957+ Unicode version thus typically means that an existing range in the table
1958+ must be split, so that any characters before and/or after the character of
1959+ interest can maintain their previous values while that character's
1960+ ``UAX44 `` bits reflect the new Unicode classification (maintaining the
1961+ previous values for all the other flags). As a specific example, the
1962+ ``DerivedCoreProperties.txt `` file for Unicode version 15.1.0 contained
1963+ (among others) the following changes from version 15.0.0:
1964+
1965+ .. code :: text
1966+
1967+ +2EBF0..2EE5D ; XID_Start # Lo [622] CJK UNIFIED IDEOGRAPH-2EBF0..CJK UNIFIED IDEOGRAPH-2EE5D
1968+ . . .
1969+ +2EBF0..2EE5D ; XID_Continue # Lo [622] CJK UNIFIED IDEOGRAPH-2EBF0..CJK UNIFIED IDEOGRAPH-2EE5D
1970+
1971+ These changes indicate that the characters in the indicated range can now
1972+ appear both within identifiers and as the first character of an
1973+ identifier. These code points were previously contained within the range of
1974+ the following element of the ``UCN_table `` array:
1975+
1976+ .. code :: c++
1977+
1978+ { 0x2ebe1, 0x2f7ff, _ | _ | CPP11 | _ , _ | _ | _ },
1979+
1980+ As a result, the range needed to be split in order to preserve the
1981+ classification of the characters before and after the new 15.1.0 range,
1982+ resulting in the following three elements to replace the existing one:
1983+
1984+ .. code :: c++
1985+
1986+
1987+ { 0x2ebe1, 0x2ebef, _ | _ | CPP11 | _ , _ | _ | _ },
1988+ { 0x2ebf0, 0x2ee5d, _ | _ | CPP11 | UAX44, _ | _ | _ },
1989+ { 0x2ee5e, 0x2f7ff, _ | _ | CPP11 | _ , _ | _ | _ },
1990+
1991+ Note both the addition of the ``UAX44 `` flag in the initializer for
1992+ ``dialects `` and its absence in the initializer for
1993+ ``non_initial_dialects ``, since the latter specifies dialects for which the
1994+ characters are *not * permitted to start an identifier.
1995+
1996+ Detection of Source Code Unicode Vulnerabilities
1997+ ------------------------------------------------
1998+
1999+ One potential avenue of source-level exploits relies on the fact that a
2000+ number of distinct Unicode characters have similar or identical glyphs. For
2001+ example, the Latin, Greek, and Cyrillic alphabets each have a character
2002+ whose visual appearance is "A", even though the code points for those
2003+ characters are different. This permits the creation of programs with
2004+ vulnerabilities that cannot be detected by even a careful code review (by
2005+ hijacking overloaded function calls, for example).
2006+
2007+ Unicode provides a table,
2008+ `www.unicode.org/Public/security/latest/confusables.txt
2009+ <https://www.unicode.org/Public/security/latest/confusables.txt> `__, that
2010+ enumerates such potentially-confused characters (replace "latest" with the
2011+ version number to access the specification for a specific version). This
2012+ table is described in
2013+ `www.unicode.org/reports/tr39/ <https://www.unicode.org/reports/tr39/ >`__.
2014+
2015+ The front end incorporates this data as the array ``confusable_map ``,
2016+ defined in ``lexical.h ``, which is a lightly-massaged version of the
2017+ contents of ``confusables.txt ``. Each element of the array is an object of
2018+ the following struct:
2019+
2020+ .. code :: c++
2021+
2022+ struct a_confusable_map_elem {
2023+ int src_char; /* The numeric value of a Unicode code point whose
2024+ glyph could be confused with that of another
2025+ code point. */
2026+ int prototype[MAX_PROTOTYPE_LENGTH];
2027+ / * The numeric values of the Unicode code points of
2028+ the prototype character(s) for src_char, as
2029+ defined in unicode.org/reports/tr39, "Unicode
2030+ Security Mechanisms", section 4. */
2031+ }; / * a_confusable_map_elem */
2032+
2033+ The elements are in strictly-ascending order of ``src_char ``, to facilitate
2034+ efficient searching using a binary search.
2035+
2036+ Although the entries in ``confusables.txt `` are not in the same order as
2037+ the elements of ``confusable_map ``, that does not present a significant
2038+ issue for updating the front end for new Unicode versions, as the mapping
2039+ from the Unicode data to the corresponding array initializer is
2040+ obvious. For example, a representative line of the version 15.1.0 file is:
2041+
2042+ .. code :: text
2043+
2044+ 2238 ; 002D 0307 ; MA #* ( ∸ → -̇ ) DOT MINUS → HYPHEN-MINUS, COMBINING DOT ABOVE #
2045+
2046+ and the corresponding initializer element is:
2047+
2048+ .. code :: c++
2049+
2050+ { 0x02238, { 0x002D, 0x0307 } },
2051+
2052+ Thus, a simple ``diff `` of two versions of the ``confusables.txt `` file
2053+ provides sufficient information for any required updates.
2054+
2055+ Such updates are expected to be infrequent, in any event, as the base data
2056+ is not likely to change very much over time. If desired, the
2057+ ``edg-make-confusables-data `` script can be used with a given version of
2058+ ``confusables.txt `` to create the entire initializer for
2059+ ``confusable_map ``.
2060+
2061+ Named Unicode Escapes
2062+ ---------------------
2063+
2064+ C++23 introduced the capability of incorporating a given Unicode character
2065+ into the source text by specifying its full name, using the syntax ``\N{ ``\
2066+ *character-name *\ ``} ``. This feature requires the front end to be able to
2067+ distinguish valid *character-name *\ s from invalid ones and to determine the
2068+ code point associated with each valid name.
2069+
2070+ Because Unicode defines tens of thousands of characters, with the average
2071+ name being over thirty characters in length, this task is necessarily
2072+ data-intensive. A naive straightforward approach, e.g., a sorted array of
2073+ character names and code points searched using a binary search, would
2074+ require around 1.5 megabytes of data and up to sixteen probes to match a
2075+ given character name, so it would be fairly inefficient in both data and
2076+ execution time.
2077+
2078+ The approach chosen for the front end implementation of this feature uses a
2079+ fairly straightforward finite state machine (FSM), with each state
2080+ representing the initial substring of characters in one or more character
2081+ names and each transition designating the state that would result for a
2082+ specific character following that initial substring in a valid Unicode
2083+ character name. There are a few simple optimizations to reduce the size of
2084+ the data containing the FSM; sequences of single-transition states are
2085+ compressed into a single state that matches a sequence of characters and
2086+ has a single transition on the final one, and the algorithmically-named
2087+ ranges for CJK and Tangut ideographs are also condensed into single states
2088+ matching the common prefix and specifying their respective ranges of code
2089+ points. Incorporating these optimizations, the storage required for the
2090+ state machine for the names in Unicode 15.1.0 is about 510 kilobytes, much
2091+ less than the naive implementation, and its performance is also much
2092+ better.
2093+
2094+ The data for the Unicode character names and code points comes from two
2095+ files: `www.unicode.org/Public/UCD/latest/ucd/UnicodeData.txt
2096+ <https://www.unicode.org/Public/UCD/latest/ucd/UnicodeData.txt> `__ and
2097+ `www.unicode.org/Public/UCD/latest/ucd/NameAliases.txt
2098+ <https://www.unicode.org/Public/UCD/latest/ucd/NameAliases.txt> `__. (The
2099+ files for specific versions can be found by substituting the version
2100+ number, e.g., ``15.1.0 ``, for ``UCD/latest `` in the URLs.)
2101+
2102+ The data for the state machine in the front end is contained in the array
2103+ ``unicode_name_fsm ``, defined in the file ``unicode_name_fsm.c ``. Because
2104+ this table cannot be edited by hand, there is a utility that produces that
2105+ file in its entirety, with no manual editing required. To run the utility,
2106+ download the two files above from the ``unicode.org `` web site and issue
2107+ the following command:
2108+
2109+ ``process_unicode_names UnicodeData.txt NameAliases.txt `` *output-file version date *
2110+
2111+ where *output-file * is any file name (it must be copied to
2112+ ``unicode_name_fsm.c `` if that file is not updated *in situ *); *version * is
2113+ the Unicode version number (e.g., ``15.1.0 ``); and *date * is the release
2114+ date of the Unicode version (e.g., ``2023-08-28 ``). (The latter two
2115+ command-line arguments are incorporated into the comments in the generated
2116+ source file.)
2117+
2118+ The source for the utility is found in the
2119+ ``dev_tools/cpp_tools/process_unicode_names `` subdirectory. Any changes
2120+ desired in the contents of ``unicode_name_fsm.c `` (such as updating the
2121+ copyright date) should be edited into the utility source in the
2122+ initializer for the ``header_text `` variable, since any manual edits in
2123+ ``unicode_name_fsm.c `` will be overwritten by the next run of the utility.
2124+
18832125.. [#f1 ] Trigraphs and line splices are not undone and so do not appear in the
18842126 output.
18852127 .. [#f2 ] As mentioned previously, the actual newline character is replaced by
0 commit comments