@@ -70,13 +70,29 @@ static bool isInSystemModule(DeclContext *D) {
70
70
return false ;
71
71
}
72
72
73
+ static ValueDecl *
74
+ createMacroConstant (ClangImporter::Implementation &Impl,
75
+ const clang::MacroInfo *macro,
76
+ Identifier name,
77
+ DeclContext *dc,
78
+ Type type,
79
+ const clang::APValue &value,
80
+ ConstantConvertKind convertKind,
81
+ bool isStatic,
82
+ ClangNode ClangN) {
83
+ Impl.ImportedMacroConstants [macro] = {value, type};
84
+ return Impl.createConstant (name, dc, type, value, convertKind, isStatic,
85
+ ClangN);
86
+ }
87
+
73
88
static ValueDecl *importNumericLiteral (ClangImporter::Implementation &Impl,
74
89
DeclContext *DC,
75
90
const clang::MacroInfo *MI,
76
91
Identifier name,
77
92
const clang::Token *signTok,
78
93
const clang::Token &tok,
79
- const clang::MacroInfo *ClangN) {
94
+ const clang::MacroInfo *ClangN,
95
+ const clang::QualType *castType) {
80
96
assert (tok.getKind () == clang::tok::numeric_constant &&
81
97
" not a numeric token" );
82
98
{
@@ -96,12 +112,21 @@ static ValueDecl *importNumericLiteral(ClangImporter::Implementation &Impl,
96
112
97
113
if (const clang::Expr *parsed = parseNumericLiteral<>(Impl, tok)) {
98
114
auto clangTy = parsed->getType ();
99
- auto type = Impl.importType (clangTy, ImportTypeKind::Value,
100
- isInSystemModule (DC),
101
- /* isFullyBridgeable*/ false );
102
- if (!type )
115
+ auto literalType = Impl.importType (clangTy, ImportTypeKind::Value,
116
+ isInSystemModule (DC),
117
+ /* isFullyBridgeable*/ false );
118
+ if (!literalType )
103
119
return nullptr ;
104
120
121
+ Type constantType;
122
+ if (castType) {
123
+ constantType = Impl.importType (*castType, ImportTypeKind::Value,
124
+ isInSystemModule (DC),
125
+ /* isFullyBridgeable*/ false );
126
+ } else {
127
+ constantType = literalType;
128
+ }
129
+
105
130
if (auto *integer = dyn_cast<clang::IntegerLiteral>(parsed)) {
106
131
// Determine the value.
107
132
llvm::APSInt value{integer->getValue (), clangTy->isUnsignedIntegerType ()};
@@ -117,7 +142,8 @@ static ValueDecl *importNumericLiteral(ClangImporter::Implementation &Impl,
117
142
}
118
143
}
119
144
120
- return Impl.createConstant (name, DC, type, clang::APValue (value),
145
+ return createMacroConstant (Impl, MI, name, DC, constantType,
146
+ clang::APValue (value),
121
147
ConstantConvertKind::Coerce,
122
148
/* static*/ false , ClangN);
123
149
}
@@ -134,7 +160,8 @@ static ValueDecl *importNumericLiteral(ClangImporter::Implementation &Impl,
134
160
value.changeSign ();
135
161
}
136
162
137
- return Impl.createConstant (name, DC, type, clang::APValue (value),
163
+ return createMacroConstant (Impl, MI, name, DC, constantType,
164
+ clang::APValue (value),
138
165
ConstantConvertKind::Coerce,
139
166
/* static*/ false , ClangN);
140
167
}
@@ -148,6 +175,13 @@ static bool isStringToken(const clang::Token &tok) {
148
175
tok.is (clang::tok::utf8_string_literal);
149
176
}
150
177
178
+ static bool isBinaryOperator (const clang::Token &tok) {
179
+ return tok.is (clang::tok::amp) ||
180
+ tok.is (clang::tok::pipe) ||
181
+ tok.is (clang::tok::ampamp) ||
182
+ tok.is (clang::tok::pipepipe);
183
+ }
184
+
151
185
// Describes the kind of string literal we're importing.
152
186
enum class MappedStringLiteralKind {
153
187
CString, // "string"
@@ -191,11 +225,12 @@ static ValueDecl *importLiteral(ClangImporter::Implementation &Impl,
191
225
const clang::MacroInfo *MI,
192
226
Identifier name,
193
227
const clang::Token &tok,
194
- const clang::MacroInfo *ClangN) {
228
+ const clang::MacroInfo *ClangN,
229
+ const clang::QualType *castType = nullptr ) {
195
230
switch (tok.getKind ()) {
196
231
case clang::tok::numeric_constant:
197
232
return importNumericLiteral (Impl, DC, MI, name, /* signTok*/ nullptr , tok,
198
- ClangN);
233
+ ClangN, castType );
199
234
200
235
case clang::tok::string_literal:
201
236
case clang::tok::utf8_string_literal:
@@ -228,7 +263,8 @@ static ValueDecl *importMacro(ClangImporter::Implementation &impl,
228
263
DeclContext *DC,
229
264
Identifier name,
230
265
const clang::MacroInfo *macro,
231
- const clang::MacroInfo *ClangN) {
266
+ const clang::MacroInfo *ClangN,
267
+ clang::QualType *castType = nullptr ) {
232
268
if (name.empty ()) return nullptr ;
233
269
234
270
auto numTokens = macro->getNumTokens ();
@@ -243,17 +279,55 @@ static ValueDecl *importMacro(ClangImporter::Implementation &impl,
243
279
numTokens -= 2 ;
244
280
}
245
281
282
+ // Handle tokens starting with a type cast
283
+ bool castTypeIsId = false ;
284
+ clang::QualType castClangType;
285
+ if (numTokens > 3 &&
286
+ tokenI[0 ].is (clang::tok::l_paren) &&
287
+ tokenI[1 ].is (clang::tok::identifier) &&
288
+ tokenI[2 ].is (clang::tok::r_paren)) {
289
+ if (castType) {
290
+ // this is a nested cast
291
+ return nullptr ;
292
+ }
293
+
294
+ auto identifierInfo = tokenI[1 ].getIdentifierInfo ();
295
+ if (identifierInfo->isStr (" id" )) {
296
+ castTypeIsId = true ;
297
+ }
298
+ auto identifierName = identifierInfo->getName ();
299
+ auto &identifier = impl.getClangASTContext ().Idents .get (identifierName);
300
+ auto parsedType = impl.getClangSema ().getTypeName (identifier,
301
+ clang::SourceLocation (),
302
+ /* scope*/ nullptr );
303
+ if (parsedType) {
304
+ castClangType = parsedType.get ();
305
+ castType = &castClangType;
306
+ } else {
307
+ return nullptr ;
308
+ }
309
+ tokenI += 3 ;
310
+ numTokens -= 3 ;
311
+ }
312
+
246
313
// FIXME: Ask Clang to try to parse and evaluate the expansion as a constant
247
314
// expression instead of doing these special-case pattern matches.
248
315
switch (numTokens) {
249
316
case 1 : {
250
317
// Check for a single-token expansion of the form <literal>.
251
318
// TODO: or <identifier>.
252
319
const clang::Token &tok = *tokenI;
253
-
320
+
321
+ if (castTypeIsId && tok.is (clang::tok::numeric_constant)) {
322
+ auto *integerLiteral =
323
+ parseNumericLiteral<clang::IntegerLiteral>(impl, tok);
324
+ if (integerLiteral && integerLiteral->getValue () == 0 )
325
+ return importNil (impl, DC, name, ClangN);
326
+ }
327
+
254
328
// If it's a literal token, we might be able to translate the literal.
255
329
if (tok.isLiteral ()) {
256
- return importLiteral (impl, DC, macro, name, tok, ClangN);
330
+ return importLiteral (impl, DC, macro, name, tok, ClangN, castType );
257
331
}
258
332
259
333
if (tok.is (clang::tok::identifier)) {
@@ -287,9 +361,10 @@ static ValueDecl *importMacro(ClangImporter::Implementation &impl,
287
361
// but are pervasive in C headers anyway.
288
362
clang::Token const &first = tokenI[0 ];
289
363
clang::Token const &second = tokenI[1 ];
290
-
364
+
291
365
if (isSignToken (first) && second.is (clang::tok::numeric_constant))
292
- return importNumericLiteral (impl, DC, macro, name, &first, second, ClangN);
366
+ return importNumericLiteral (impl, DC, macro, name, &first, second, ClangN,
367
+ castType);
293
368
294
369
// We also allow @"string".
295
370
if (first.is (clang::tok::at) && isStringToken (second))
@@ -319,9 +394,76 @@ static ValueDecl *importMacro(ClangImporter::Implementation &impl,
319
394
320
395
llvm::APSInt value{ base->getValue () << shift->getValue (),
321
396
clangTy->isUnsignedIntegerType () };
322
- return impl.createConstant (name, DC, type, clang::APValue (value),
397
+ return createMacroConstant (impl, macro, name, DC, type,
398
+ clang::APValue (value),
323
399
ConstantConvertKind::Coerce, /* static=*/ false ,
324
400
ClangN);
401
+ // Check for a expression of the form (FLAG1 | FLAG2), (FLAG1 & FLAG2),
402
+ // (FLAG1 || FLAG2), or (FLAG1 || FLAG2)
403
+ } else if (tokenI[0 ].is (clang::tok::identifier) &&
404
+ isBinaryOperator (tokenI[1 ]) &&
405
+ tokenI[2 ].is (clang::tok::identifier)) {
406
+ auto firstID = tokenI[0 ].getIdentifierInfo ();
407
+ auto secondID = tokenI[2 ].getIdentifierInfo ();
408
+
409
+ if (firstID->hasMacroDefinition () && secondID->hasMacroDefinition ()) {
410
+ auto firstMacroInfo = impl.getClangPreprocessor ().getMacroInfo (firstID);
411
+ auto secondMacroInfo = impl.getClangPreprocessor ().getMacroInfo (
412
+ secondID);
413
+ auto firstIterator = impl.ImportedMacroConstants .find (firstMacroInfo);
414
+ if (firstIterator == impl.ImportedMacroConstants .end ()) {
415
+ return nullptr ;
416
+ }
417
+ auto secondIterator = impl.ImportedMacroConstants .find (secondMacroInfo);
418
+ if (secondIterator == impl.ImportedMacroConstants .end ()) {
419
+ return nullptr ;
420
+ }
421
+
422
+ auto firstConstant = firstIterator->second ;
423
+ auto secondConstant = secondIterator->second ;
424
+ auto firstValue = firstConstant.first ;
425
+ auto secondValue = secondConstant.first ;
426
+ if (!firstValue.isInt () || !secondValue.isInt ()) {
427
+ return nullptr ;
428
+ }
429
+
430
+ auto firstInteger = firstValue.getInt ();
431
+ auto secondInteger = secondValue.getInt ();
432
+ auto type = firstConstant.second ;
433
+
434
+ clang::APValue value;
435
+ if (tokenI[1 ].is (clang::tok::pipe)) {
436
+ if (firstInteger.getBitWidth () == secondInteger.getBitWidth ()) {
437
+ value = clang::APValue (firstInteger | secondInteger);
438
+ } else {
439
+ return nullptr ;
440
+ }
441
+ } else if (tokenI[1 ].is (clang::tok::amp)) {
442
+ if (firstInteger.getBitWidth () == secondInteger.getBitWidth ()) {
443
+ value = clang::APValue (firstInteger & secondInteger);
444
+ } else {
445
+ return nullptr ;
446
+ }
447
+ } else if (tokenI[1 ].is (clang::tok::pipepipe)) {
448
+ auto firstBool = firstInteger.getBoolValue ();
449
+ auto secondBool = firstInteger.getBoolValue ();
450
+ auto result = firstBool || secondBool;
451
+ value = clang::APValue (result ?
452
+ llvm::APSInt::get (1 ) : llvm::APSInt::get (0 ));
453
+ } else if (tokenI[1 ].is (clang::tok::ampamp)) {
454
+ auto firstBool = firstInteger.getBoolValue ();
455
+ auto secondBool = firstInteger.getBoolValue ();
456
+ auto result = firstBool && secondBool;
457
+ value = clang::APValue (result ?
458
+ llvm::APSInt::get (1 ) : llvm::APSInt::get (0 ));
459
+ } else {
460
+ return nullptr ;
461
+ }
462
+ return createMacroConstant (impl, macro, name, DC, type,
463
+ value,
464
+ ConstantConvertKind::Coerce,
465
+ /* static=*/ false , ClangN);
466
+ }
325
467
}
326
468
break ;
327
469
}
0 commit comments