@@ -70,13 +70,29 @@ static bool isInSystemModule(DeclContext *D) {
7070 return false ;
7171}
7272
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+
7388static ValueDecl *importNumericLiteral (ClangImporter::Implementation &Impl,
7489 DeclContext *DC,
7590 const clang::MacroInfo *MI,
7691 Identifier name,
7792 const clang::Token *signTok,
7893 const clang::Token &tok,
79- const clang::MacroInfo *ClangN) {
94+ const clang::MacroInfo *ClangN,
95+ const clang::QualType *castType) {
8096 assert (tok.getKind () == clang::tok::numeric_constant &&
8197 " not a numeric token" );
8298 {
@@ -96,12 +112,21 @@ static ValueDecl *importNumericLiteral(ClangImporter::Implementation &Impl,
96112
97113 if (const clang::Expr *parsed = parseNumericLiteral<>(Impl, tok)) {
98114 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 )
103119 return nullptr ;
104120
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+
105130 if (auto *integer = dyn_cast<clang::IntegerLiteral>(parsed)) {
106131 // Determine the value.
107132 llvm::APSInt value{integer->getValue (), clangTy->isUnsignedIntegerType ()};
@@ -117,7 +142,8 @@ static ValueDecl *importNumericLiteral(ClangImporter::Implementation &Impl,
117142 }
118143 }
119144
120- return Impl.createConstant (name, DC, type, clang::APValue (value),
145+ return createMacroConstant (Impl, MI, name, DC, constantType,
146+ clang::APValue (value),
121147 ConstantConvertKind::Coerce,
122148 /* static*/ false , ClangN);
123149 }
@@ -134,7 +160,8 @@ static ValueDecl *importNumericLiteral(ClangImporter::Implementation &Impl,
134160 value.changeSign ();
135161 }
136162
137- return Impl.createConstant (name, DC, type, clang::APValue (value),
163+ return createMacroConstant (Impl, MI, name, DC, constantType,
164+ clang::APValue (value),
138165 ConstantConvertKind::Coerce,
139166 /* static*/ false , ClangN);
140167 }
@@ -148,6 +175,13 @@ static bool isStringToken(const clang::Token &tok) {
148175 tok.is (clang::tok::utf8_string_literal);
149176}
150177
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+
151185// Describes the kind of string literal we're importing.
152186enum class MappedStringLiteralKind {
153187 CString, // "string"
@@ -191,11 +225,12 @@ static ValueDecl *importLiteral(ClangImporter::Implementation &Impl,
191225 const clang::MacroInfo *MI,
192226 Identifier name,
193227 const clang::Token &tok,
194- const clang::MacroInfo *ClangN) {
228+ const clang::MacroInfo *ClangN,
229+ const clang::QualType *castType = nullptr ) {
195230 switch (tok.getKind ()) {
196231 case clang::tok::numeric_constant:
197232 return importNumericLiteral (Impl, DC, MI, name, /* signTok*/ nullptr , tok,
198- ClangN);
233+ ClangN, castType );
199234
200235 case clang::tok::string_literal:
201236 case clang::tok::utf8_string_literal:
@@ -228,7 +263,8 @@ static ValueDecl *importMacro(ClangImporter::Implementation &impl,
228263 DeclContext *DC,
229264 Identifier name,
230265 const clang::MacroInfo *macro,
231- const clang::MacroInfo *ClangN) {
266+ const clang::MacroInfo *ClangN,
267+ clang::QualType *castType = nullptr ) {
232268 if (name.empty ()) return nullptr ;
233269
234270 auto numTokens = macro->getNumTokens ();
@@ -243,17 +279,55 @@ static ValueDecl *importMacro(ClangImporter::Implementation &impl,
243279 numTokens -= 2 ;
244280 }
245281
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+
246313 // FIXME: Ask Clang to try to parse and evaluate the expansion as a constant
247314 // expression instead of doing these special-case pattern matches.
248315 switch (numTokens) {
249316 case 1 : {
250317 // Check for a single-token expansion of the form <literal>.
251318 // TODO: or <identifier>.
252319 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+
254328 // If it's a literal token, we might be able to translate the literal.
255329 if (tok.isLiteral ()) {
256- return importLiteral (impl, DC, macro, name, tok, ClangN);
330+ return importLiteral (impl, DC, macro, name, tok, ClangN, castType );
257331 }
258332
259333 if (tok.is (clang::tok::identifier)) {
@@ -287,9 +361,10 @@ static ValueDecl *importMacro(ClangImporter::Implementation &impl,
287361 // but are pervasive in C headers anyway.
288362 clang::Token const &first = tokenI[0 ];
289363 clang::Token const &second = tokenI[1 ];
290-
364+
291365 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);
293368
294369 // We also allow @"string".
295370 if (first.is (clang::tok::at) && isStringToken (second))
@@ -319,9 +394,76 @@ static ValueDecl *importMacro(ClangImporter::Implementation &impl,
319394
320395 llvm::APSInt value{ base->getValue () << shift->getValue (),
321396 clangTy->isUnsignedIntegerType () };
322- return impl.createConstant (name, DC, type, clang::APValue (value),
397+ return createMacroConstant (impl, macro, name, DC, type,
398+ clang::APValue (value),
323399 ConstantConvertKind::Coerce, /* static=*/ false ,
324400 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+ }
325467 }
326468 break ;
327469 }
0 commit comments