Skip to content

Commit f3f22bb

Browse files
committed
Add special macro __cppconv_to_identifier(...)
This allows to convert an argument to an identifier, by replacing other characters with an underscore. It is used to convert __has_cpp_attribute(clang::fallthrough) into a single identifier for conditions.
1 parent 7551b85 commit f3f22bb

File tree

6 files changed

+147
-22
lines changed

6 files changed

+147
-22
lines changed

projects/common/prefixinclude.h

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -537,14 +537,14 @@ typedef __builtin_char32_t char32_t;
537537
#undef assert
538538

539539
// https://clang.llvm.org/docs/LanguageExtensions.html
540-
#define __has_builtin(x) __has_builtin_ ## x
541-
#define __has_feature(x) __has_feature_ ## x
542-
#define __has_extension(x) __has_extension_ ## x
543-
#define __has_cpp_attribute(x) __has_cpp_attribute_ ## x
544-
#define __has_c_attribute(x) __has_c_attribute_ ## x
545-
#define __has_attribute(x) __has_attribute_ ## x
546-
#define __has_declspec_attribute(x) __has_declspec_attribute_ ## x
547-
#define __is_identifier(x) __is_identifier ## x
540+
#define __has_builtin(x) __has_builtin_ ## __cppconv_to_identifier(x)
541+
#define __has_feature(x) __has_feature_ ## __cppconv_to_identifier(x)
542+
#define __has_extension(x) __has_extension_ ## __cppconv_to_identifier(x)
543+
#define __has_cpp_attribute(x) __has_cpp_attribute_ ## __cppconv_to_identifier(x)
544+
#define __has_c_attribute(x) __has_c_attribute_ ## __cppconv_to_identifier(x)
545+
#define __has_attribute(x) __has_attribute_ ## __cppconv_to_identifier(x)
546+
#define __has_declspec_attribute(x) __has_declspec_attribute_ ## __cppconv_to_identifier(x)
547+
#define __is_identifier(x) __is_identifier_ ## __cppconv_to_identifier(x)
548548

549549
#undef __int8
550550
#lockdefine __int8

projects/qt5/prefixinclude.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,11 @@ template<int> struct QIntegerForSize
200200
#undef __cpp_lib_invoke
201201
#undef __has_cpp_attribute_nodiscard
202202

203+
#undef Q_FALLTHROUGH
204+
#undef __has_cpp_attribute_clang_fallthrough
205+
#define __has_cpp_attribute_fallthrough 1
206+
#undef __has_cpp_attribute_gnu_fallthrough
207+
203208
#undef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
204209
#undef QT_SHA3_KECCAK_COMPAT
205210

projects/qt6/prefixinclude.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,11 @@ template<int> struct QIntegerForSize
200200
#undef __cpp_lib_invoke
201201
#undef __has_cpp_attribute_nodiscard
202202

203+
#undef Q_FALLTHROUGH
204+
#undef __has_cpp_attribute_clang_fallthrough
205+
#define __has_cpp_attribute_fallthrough 1
206+
#undef __has_cpp_attribute_gnu_fallthrough
207+
203208
#undef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
204209
#undef QT_SHA3_KECCAK_COMPAT
205210

src/cppconv/cppparallelparser.d

Lines changed: 94 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1246,12 +1246,77 @@ class DoubleParallelParser(ParserWrapper) : ParallelParser!(ParserWrapper)
12461246
}
12471247
}
12481248

1249+
string toIdentifierText(Tree toIdentNode, MacroParam[string] paramMap)
1250+
{
1251+
string allText;
1252+
foreach (innerToken; toIdentNode.childs)
1253+
{
1254+
string tokenContent = innerToken.childs[0].content;
1255+
if (paramMap !is null && tokenContent in paramMap)
1256+
{
1257+
foreach (pt; paramMap[tokenContent].tokens)
1258+
allText ~= pt.t.content;
1259+
}
1260+
else
1261+
{
1262+
allText ~= tokenContent;
1263+
}
1264+
}
1265+
// Replace consecutive non-identifier characters with single _
1266+
string identifier;
1267+
bool lastWasSpecial = false;
1268+
foreach (char c; allText)
1269+
{
1270+
if (c.inCharSet!"a-zA-Z0-9_")
1271+
{
1272+
identifier ~= c;
1273+
lastWasSpecial = false;
1274+
}
1275+
else
1276+
{
1277+
if (!lastWasSpecial)
1278+
identifier ~= '_';
1279+
lastWasSpecial = true;
1280+
}
1281+
}
1282+
return identifier;
1283+
}
1284+
12491285
Tree[] parseMacroContent(Tree[] defTokens, bool insidePPExpression)
12501286
{
12511287
Tree[] r;
12521288

12531289
defTokens = defTokens.dup;
12541290

1291+
// Collapse __cppconv_to_identifier(...) into ToIdentifier nodes
1292+
for (size_t i = 0; i < defTokens.length; i++)
1293+
{
1294+
if (defTokens[i].childs[0].isToken
1295+
&& defTokens[i].childs[0].content == "__cppconv_to_identifier"
1296+
&& i + 1 < defTokens.length
1297+
&& defTokens[i + 1].childs[0].content == "(")
1298+
{
1299+
size_t end = i + 2;
1300+
size_t nesting = 1;
1301+
while (end < defTokens.length && defTokens[end].isValid && nesting > 0)
1302+
{
1303+
if (defTokens[end].childs[0].content == "(")
1304+
nesting++;
1305+
else if (defTokens[end].childs[0].content == ")")
1306+
nesting--;
1307+
end++;
1308+
}
1309+
Tree[] innerTokens = defTokens[i + 2 .. end - 1].dup;
1310+
Location.LocationDiff l = defTokens[end - 1].end - defTokens[i].start;
1311+
auto grammarInfo = getDummyGrammarInfo2("ToIdentifier");
1312+
Tree toIdent = Tree("ToIdentifier", grammarInfo.startNonterminalID,
1313+
grammarInfo.startProductionID, NodeType.nonterminal, innerTokens);
1314+
toIdent.grammarInfo = grammarInfo;
1315+
toIdent.setStartEnd(defTokens[i].start, defTokens[i].start + l);
1316+
defTokens = defTokens[0 .. i] ~ toIdent ~ defTokens[end .. $];
1317+
}
1318+
}
1319+
12551320
for (size_t i = 0; i < defTokens.length;)
12561321
{
12571322
if (insidePPExpression && defTokens[i].childs[0].isToken
@@ -1818,6 +1883,15 @@ Tuple!(Tree, Location)[] replaceMacroConcat(ParserWrapper)(Location start, Tree
18181883
{
18191884
analyzeTree(start, lhsTree);
18201885
}
1886+
else if (lhsTree.name == "ToIdentifier")
1887+
{
1888+
string ident = toIdentifierText(lhsTree, paramMap);
1889+
Tree identToken = Tree(ident, SymbolID.max, ProductionID.max, NodeType.token, []);
1890+
identToken.setStartEnd(reparentLocation(lhsTree.start, start.context),
1891+
reparentLocation(lhsTree.end, start.context));
1892+
tokenLists ~= [tuple!(Tree, Location)(identToken,
1893+
reparentLocation(lhsTree.start, start.context))];
1894+
}
18211895
else if (lhsTree.childs[0].content in paramMap)
18221896
{
18231897
Tree nameToken = lhsTree.childs[0];
@@ -1836,7 +1910,16 @@ Tuple!(Tree, Location)[] replaceMacroConcat(ParserWrapper)(Location start, Tree
18361910
start.context), reparentLocation(t.childs[1].end, start.context));
18371911
concatTokens ~= middleChild;
18381912

1839-
if (rhsTree.childs[0].content in paramMap)
1913+
if (rhsTree.name == "ToIdentifier")
1914+
{
1915+
string ident = toIdentifierText(rhsTree, paramMap);
1916+
Tree identToken = Tree(ident, SymbolID.max, ProductionID.max, NodeType.token, []);
1917+
identToken.setStartEnd(reparentLocation(rhsTree.start, start.context),
1918+
reparentLocation(rhsTree.end, start.context));
1919+
tokenLists ~= [tuple!(Tree, Location)(identToken,
1920+
reparentLocation(rhsTree.start, start.context))];
1921+
}
1922+
else if (rhsTree.childs[0].content in paramMap)
18401923
{
18411924
Tree nameToken = rhsTree.childs[0];
18421925
tokenLists ~= mapParams(start, nameToken, paramMap, context,
@@ -1960,7 +2043,8 @@ out
19602043
do
19612044
{
19622045
Tree nameToken;
1963-
if (token.nonterminalID == preprocNonterminalIDFor!"ParamExpansion" || token.name == "ParamConcat")
2046+
if (token.nonterminalID == preprocNonterminalIDFor!"ParamExpansion" || token.name == "ParamConcat"
2047+
|| token.name == "ToIdentifier")
19642048
nameToken = Tree.init;
19652049
else
19662050
nameToken = token.childs[0];
@@ -2063,6 +2147,14 @@ do
20632147
macrosDone, i == replacedTokens.length - 1 && isNextParen, parentParser);
20642148
}
20652149
}
2150+
else if (token.name == "ToIdentifier")
2151+
{
2152+
string ident = toIdentifierText(token, paramMap);
2153+
Tree newToken = Tree(ident, SymbolID.max, ProductionID.max, NodeType.token, []);
2154+
newToken.setStartEnd(start, start + token.inputLength);
2155+
processDirectToken(start, newToken, context, parallelParser, condition,
2156+
macrosDone, isNextParen, parentParser);
2157+
}
20662158
else
20672159
{
20682160
if (argPrescan)

tests/single/test137.cpp

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
1-
#ifndef DEF
2-
#define __LA_FALLTHROUGH __attribute__((fallthrough))
1+
#ifdef ALWAYS_PREDEFINED_IN_TEST
2+
#define __has_cpp_attribute(x) __has_cpp_attribute_ ## __cppconv_to_identifier(x)
3+
#endif
4+
5+
#if __has_cpp_attribute(clang::fallthrough)
6+
#define FALLTHROUGH [[clang::fallthrough]]
7+
#elif __has_cpp_attribute(fallthrough)
8+
#define FALLTHROUGH [[fallthrough]]
9+
#elif defined(DEF)
10+
#define FALLTHROUGH __attribute__((fallthrough))
311
#else
4-
#define __LA_FALLTHROUGH
12+
#define FALLTHROUGH
513
#endif
614

715
void g();
@@ -11,13 +19,16 @@ void f(int level)
1119
{
1220
case 4:
1321
g();
14-
__LA_FALLTHROUGH;
22+
FALLTHROUGH;
1523
case 3:
1624
g();
1725
__attribute__((fallthrough));
1826
case 2:
1927
g();
20-
__LA_FALLTHROUGH;
28+
FALLTHROUGH;
29+
case 5:
30+
g();
31+
[[fallthrough]];
2132
default:
2233
g();
2334
}

tests/single/test137.d

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,18 @@ module test137;
33
import config;
44
import cppconvhelpers;
55

6-
/+ #ifndef DEF
7-
#define __LA_FALLTHROUGH __attribute__((fallthrough))
6+
/+ #ifdef ALWAYS_PREDEFINED_IN_TEST
7+
#define __has_cpp_attribute(x) __has_cpp_attribute_ ## __cppconv_to_identifier(x)
8+
#endif
9+
10+
#if __has_cpp_attribute(clang::fallthrough)
11+
#define FALLTHROUGH [[clang::fallthrough]]
12+
#elif __has_cpp_attribute(fallthrough)
13+
#define FALLTHROUGH [[fallthrough]]
14+
#elif defined(DEF)
15+
#define FALLTHROUGH __attribute__((fallthrough))
816
#else
9-
#define __LA_FALLTHROUGH
17+
#define FALLTHROUGH
1018
#endif +/
1119

1220
void g();
@@ -16,9 +24,9 @@ void f(int level)
1624
{
1725
case 4:
1826
g();
19-
static if (!defined!"DEF")
27+
static if ((defined!"DEF" || (configValue!"__has_cpp_attribute_clang_fallthrough" && defined!"__has_cpp_attribute_clang_fallthrough") || (configValue!"__has_cpp_attribute_fallthrough" && defined!"__has_cpp_attribute_fallthrough")))
2028
{
21-
/+ __LA_FALLTHROUGH; +/
29+
/+ FALLTHROUGH; +/
2230
}
2331
else
2432
{
@@ -30,13 +38,17 @@ case 3:
3038
goto case;
3139
case 2:
3240
g();
33-
static if (!defined!"DEF")
41+
static if ((defined!"DEF" || (configValue!"__has_cpp_attribute_clang_fallthrough" && defined!"__has_cpp_attribute_clang_fallthrough") || (configValue!"__has_cpp_attribute_fallthrough" && defined!"__has_cpp_attribute_fallthrough")))
3442
{
35-
/+ __LA_FALLTHROUGH; +/
43+
/+ FALLTHROUGH; +/
3644
}
3745
else
3846
{
3947
}
48+
goto case;
49+
case 5:
50+
g();
51+
/+ [[fallthrough]]; +/
4052
goto default;
4153
default:
4254
g();

0 commit comments

Comments
 (0)