summaryrefslogtreecommitdiff
path: root/lib/Lex/PPMacroExpansion.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Lex/PPMacroExpansion.cpp')
-rw-r--r--lib/Lex/PPMacroExpansion.cpp420
1 files changed, 241 insertions, 179 deletions
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index 18348df0a39ec..2ade6df9456a6 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -52,6 +52,13 @@ void Preprocessor::appendMacroDirective(IdentifierInfo *II, MacroDirective *MD){
StoredMD.setLatest(MD);
StoredMD.overrideActiveModuleMacros(*this, II);
+ if (needModuleMacros()) {
+ // Track that we created a new macro directive, so we know we should
+ // consider building a ModuleMacro for it when we get to the end of
+ // the module.
+ PendingModuleMacroNames.push_back(II);
+ }
+
// Set up the identifier as having associated macro history.
II->setHasMacroDefinition(true);
if (!MD->isDefined() && LeafModuleMacros.find(II) == LeafModuleMacros.end())
@@ -323,18 +330,11 @@ void Preprocessor::RegisterBuiltinMacros() {
Ident__is_identifier = RegisterBuiltinMacro(*this, "__is_identifier");
// Modules.
- if (LangOpts.Modules) {
- Ident__building_module = RegisterBuiltinMacro(*this, "__building_module");
-
- // __MODULE__
- if (!LangOpts.CurrentModule.empty())
- Ident__MODULE__ = RegisterBuiltinMacro(*this, "__MODULE__");
- else
- Ident__MODULE__ = nullptr;
- } else {
- Ident__building_module = nullptr;
+ Ident__building_module = RegisterBuiltinMacro(*this, "__building_module");
+ if (!LangOpts.CurrentModule.empty())
+ Ident__MODULE__ = RegisterBuiltinMacro(*this, "__MODULE__");
+ else
Ident__MODULE__ = nullptr;
- }
}
/// isTrivialSingleTokenExpansion - Return true if MI, which has a single token
@@ -723,6 +723,7 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
// heap allocations in the common case.
SmallVector<Token, 64> ArgTokens;
bool ContainsCodeCompletionTok = false;
+ bool FoundElidedComma = false;
SourceLocation TooManyArgsLoc;
@@ -754,17 +755,20 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
// Do not lose the EOF/EOD. Return it to the client.
MacroName = Tok;
return nullptr;
- } else {
- // Do not lose the EOF/EOD.
- Token *Toks = new Token[1];
- Toks[0] = Tok;
- EnterTokenStream(Toks, 1, true, true);
- break;
}
+ // Do not lose the EOF/EOD.
+ auto Toks = llvm::make_unique<Token[]>(1);
+ Toks[0] = Tok;
+ EnterTokenStream(std::move(Toks), 1, true);
+ break;
} else if (Tok.is(tok::r_paren)) {
// If we found the ) token, the macro arg list is done.
if (NumParens-- == 0) {
MacroEnd = Tok.getLocation();
+ if (!ArgTokens.empty() &&
+ ArgTokens.back().commaAfterElided()) {
+ FoundElidedComma = true;
+ }
break;
}
} else if (Tok.is(tok::l_paren)) {
@@ -909,7 +913,7 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
// then we have an empty "()" argument empty list. This is fine, even if
// the macro expects one argument (the argument is just empty).
isVarargsElided = MI->isVariadic();
- } else if (MI->isVariadic() &&
+ } else if ((FoundElidedComma || MI->isVariadic()) &&
(NumActuals+1 == MinArgsExpected || // A(x, ...) -> A(X)
(NumActuals == 0 && MinArgsExpected == 2))) {// A(x,...) -> A()
// Varargs where the named vararg parameter is missing: OK as extension.
@@ -1042,9 +1046,8 @@ static void ComputeDATE_TIME(SourceLocation &DATELoc, SourceLocation &TIMELoc,
/// HasFeature - Return true if we recognize and implement the feature
/// specified by the identifier as a standard language feature.
-static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
+static bool HasFeature(const Preprocessor &PP, StringRef Feature) {
const LangOptions &LangOpts = PP.getLangOpts();
- StringRef Feature = II->getName();
// Normalize the feature name, __foo__ becomes foo.
if (Feature.startswith("__") && Feature.endswith("__") && Feature.size() >= 4)
@@ -1062,10 +1065,14 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
.Case("attribute_availability_with_version_underscores", true)
.Case("attribute_availability_tvos", true)
.Case("attribute_availability_watchos", true)
+ .Case("attribute_availability_with_strict", true)
+ .Case("attribute_availability_with_replacement", true)
+ .Case("attribute_availability_in_templates", true)
.Case("attribute_cf_returns_not_retained", true)
.Case("attribute_cf_returns_retained", true)
.Case("attribute_cf_returns_on_parameters", true)
.Case("attribute_deprecated_with_message", true)
+ .Case("attribute_deprecated_with_replacement", true)
.Case("attribute_ext_vector_type", true)
.Case("attribute_ns_returns_not_retained", true)
.Case("attribute_ns_returns_retained", true)
@@ -1086,6 +1093,8 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
.Case("memory_sanitizer", LangOpts.Sanitize.has(SanitizerKind::Memory))
.Case("thread_sanitizer", LangOpts.Sanitize.has(SanitizerKind::Thread))
.Case("dataflow_sanitizer", LangOpts.Sanitize.has(SanitizerKind::DataFlow))
+ .Case("efficiency_sanitizer",
+ LangOpts.Sanitize.hasOneOf(SanitizerKind::Efficiency))
// Objective-C features
.Case("objc_arr", LangOpts.ObjCAutoRefCount) // FIXME: REMOVE?
.Case("objc_arc", LangOpts.ObjCAutoRefCount)
@@ -1114,6 +1123,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
.Case("objc_bridge_id_on_typedefs", true)
.Case("objc_generics", LangOpts.ObjC2)
.Case("objc_generics_variance", LangOpts.ObjC2)
+ .Case("objc_class_property", LangOpts.ObjC2)
// C11 features
.Case("c_alignas", LangOpts.C11)
.Case("c_alignof", LangOpts.C11)
@@ -1177,6 +1187,8 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
// FIXME: Should this be __has_feature or __has_extension?
//.Case("raw_invocation_type", LangOpts.CPlusPlus)
// Type traits
+ // N.B. Additional type traits should not be added to the following list.
+ // Instead, they should be detected by has_extension.
.Case("has_nothrow_assign", LangOpts.CPlusPlus)
.Case("has_nothrow_copy", LangOpts.CPlusPlus)
.Case("has_nothrow_constructor", LangOpts.CPlusPlus)
@@ -1197,7 +1209,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
.Case("is_standard_layout", LangOpts.CPlusPlus)
.Case("is_pod", LangOpts.CPlusPlus)
.Case("is_polymorphic", LangOpts.CPlusPlus)
- .Case("is_sealed", LangOpts.MicrosoftExt)
+ .Case("is_sealed", LangOpts.CPlusPlus && LangOpts.MicrosoftExt)
.Case("is_trivial", LangOpts.CPlusPlus)
.Case("is_trivially_assignable", LangOpts.CPlusPlus)
.Case("is_trivially_constructible", LangOpts.CPlusPlus)
@@ -1213,8 +1225,8 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
/// HasExtension - Return true if we recognize and implement the feature
/// specified by the identifier, either as an extension or a standard language
/// feature.
-static bool HasExtension(const Preprocessor &PP, const IdentifierInfo *II) {
- if (HasFeature(PP, II))
+static bool HasExtension(const Preprocessor &PP, StringRef Extension) {
+ if (HasFeature(PP, Extension))
return true;
// If the use of an extension results in an error diagnostic, extensions are
@@ -1224,7 +1236,6 @@ static bool HasExtension(const Preprocessor &PP, const IdentifierInfo *II) {
return false;
const LangOptions &LangOpts = PP.getLangOpts();
- StringRef Extension = II->getName();
// Normalize the extension name, __foo__ becomes foo.
if (Extension.startswith("__") && Extension.endswith("__") &&
@@ -1408,47 +1419,120 @@ static bool EvaluateHasIncludeNext(Token &Tok,
return EvaluateHasIncludeCommon(Tok, II, PP, Lookup, LookupFromFile);
}
-/// \brief Process __building_module(identifier) expression.
-/// \returns true if we are building the named module, false otherwise.
-static bool EvaluateBuildingModule(Token &Tok,
- IdentifierInfo *II, Preprocessor &PP) {
- // Get '('.
- PP.LexNonComment(Tok);
-
- // Ensure we have a '('.
+/// \brief Process single-argument builtin feature-like macros that return
+/// integer values.
+static void EvaluateFeatureLikeBuiltinMacro(llvm::raw_svector_ostream& OS,
+ Token &Tok, IdentifierInfo *II,
+ Preprocessor &PP,
+ llvm::function_ref<
+ int(Token &Tok,
+ bool &HasLexedNextTok)> Op) {
+ // Parse the initial '('.
+ PP.LexUnexpandedToken(Tok);
if (Tok.isNot(tok::l_paren)) {
PP.Diag(Tok.getLocation(), diag::err_pp_expected_after) << II
<< tok::l_paren;
- return false;
+
+ // Provide a dummy '0' value on output stream to elide further errors.
+ if (!Tok.isOneOf(tok::eof, tok::eod)) {
+ OS << 0;
+ Tok.setKind(tok::numeric_constant);
+ }
+ return;
}
- // Save '(' location for possible missing ')' message.
+ unsigned ParenDepth = 1;
SourceLocation LParenLoc = Tok.getLocation();
+ llvm::Optional<int> Result;
+
+ Token ResultTok;
+ bool SuppressDiagnostic = false;
+ while (true) {
+ // Parse next token.
+ PP.LexUnexpandedToken(Tok);
+
+already_lexed:
+ switch (Tok.getKind()) {
+ case tok::eof:
+ case tok::eod:
+ // Don't provide even a dummy value if the eod or eof marker is
+ // reached. Simply provide a diagnostic.
+ PP.Diag(Tok.getLocation(), diag::err_unterm_macro_invoc);
+ return;
- // Get the module name.
- PP.LexNonComment(Tok);
+ case tok::comma:
+ if (!SuppressDiagnostic) {
+ PP.Diag(Tok.getLocation(), diag::err_too_many_args_in_macro_invoc);
+ SuppressDiagnostic = true;
+ }
+ continue;
- // Ensure that we have an identifier.
- if (Tok.isNot(tok::identifier)) {
- PP.Diag(Tok.getLocation(), diag::err_expected_id_building_module);
- return false;
- }
+ case tok::l_paren:
+ ++ParenDepth;
+ if (Result.hasValue())
+ break;
+ if (!SuppressDiagnostic) {
+ PP.Diag(Tok.getLocation(), diag::err_pp_nested_paren) << II;
+ SuppressDiagnostic = true;
+ }
+ continue;
- bool Result
- = Tok.getIdentifierInfo()->getName() == PP.getLangOpts().CurrentModule;
+ case tok::r_paren:
+ if (--ParenDepth > 0)
+ continue;
+
+ // The last ')' has been reached; return the value if one found or
+ // a diagnostic and a dummy value.
+ if (Result.hasValue())
+ OS << Result.getValue();
+ else {
+ OS << 0;
+ if (!SuppressDiagnostic)
+ PP.Diag(Tok.getLocation(), diag::err_too_few_args_in_macro_invoc);
+ }
+ Tok.setKind(tok::numeric_constant);
+ return;
- // Get ')'.
- PP.LexNonComment(Tok);
+ default: {
+ // Parse the macro argument, if one not found so far.
+ if (Result.hasValue())
+ break;
- // Ensure we have a trailing ).
- if (Tok.isNot(tok::r_paren)) {
- PP.Diag(Tok.getLocation(), diag::err_pp_expected_after) << II
- << tok::r_paren;
- PP.Diag(LParenLoc, diag::note_matching) << tok::l_paren;
- return false;
+ bool HasLexedNextToken = false;
+ Result = Op(Tok, HasLexedNextToken);
+ ResultTok = Tok;
+ if (HasLexedNextToken)
+ goto already_lexed;
+ continue;
+ }
+ }
+
+ // Diagnose missing ')'.
+ if (!SuppressDiagnostic) {
+ if (auto Diag = PP.Diag(Tok.getLocation(), diag::err_pp_expected_after)) {
+ if (IdentifierInfo *LastII = ResultTok.getIdentifierInfo())
+ Diag << LastII;
+ else
+ Diag << ResultTok.getKind();
+ Diag << tok::r_paren << ResultTok.getLocation();
+ }
+ PP.Diag(LParenLoc, diag::note_matching) << tok::l_paren;
+ SuppressDiagnostic = true;
+ }
}
+}
- return Result;
+/// \brief Helper function to return the IdentifierInfo structure of a Token
+/// or generate a diagnostic if none available.
+static IdentifierInfo *ExpectFeatureIdentifierInfo(Token &Tok,
+ Preprocessor &PP,
+ signed DiagID) {
+ IdentifierInfo *II;
+ if (!Tok.isAnnotation() && (II = Tok.getIdentifierInfo()))
+ return II;
+
+ PP.Diag(Tok.getLocation(), DiagID);
+ return nullptr;
}
/// ExpandBuiltinMacro - If an identifier token is read that is to be expanded
@@ -1584,84 +1668,82 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
// __COUNTER__ expands to a simple numeric value.
OS << CounterValue++;
Tok.setKind(tok::numeric_constant);
- } else if (II == Ident__has_feature ||
- II == Ident__has_extension ||
- II == Ident__has_builtin ||
- II == Ident__is_identifier ||
- II == Ident__has_attribute ||
- II == Ident__has_declspec ||
- II == Ident__has_cpp_attribute) {
- // The argument to these builtins should be a parenthesized identifier.
- SourceLocation StartLoc = Tok.getLocation();
-
- bool IsValid = false;
- IdentifierInfo *FeatureII = nullptr;
- IdentifierInfo *ScopeII = nullptr;
-
- // Read the '('.
- LexUnexpandedToken(Tok);
- if (Tok.is(tok::l_paren)) {
- // Read the identifier
- LexUnexpandedToken(Tok);
- if ((FeatureII = Tok.getIdentifierInfo())) {
- // If we're checking __has_cpp_attribute, it is possible to receive a
- // scope token. Read the "::", if it's available.
+ } else if (II == Ident__has_feature) {
+ EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this,
+ [this](Token &Tok, bool &HasLexedNextToken) -> int {
+ IdentifierInfo *II = ExpectFeatureIdentifierInfo(Tok, *this,
+ diag::err_feature_check_malformed);
+ return II && HasFeature(*this, II->getName());
+ });
+ } else if (II == Ident__has_extension) {
+ EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this,
+ [this](Token &Tok, bool &HasLexedNextToken) -> int {
+ IdentifierInfo *II = ExpectFeatureIdentifierInfo(Tok, *this,
+ diag::err_feature_check_malformed);
+ return II && HasExtension(*this, II->getName());
+ });
+ } else if (II == Ident__has_builtin) {
+ EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this,
+ [this](Token &Tok, bool &HasLexedNextToken) -> int {
+ IdentifierInfo *II = ExpectFeatureIdentifierInfo(Tok, *this,
+ diag::err_feature_check_malformed);
+ if (!II)
+ return false;
+ else if (II->getBuiltinID() != 0)
+ return true;
+ else {
+ const LangOptions &LangOpts = getLangOpts();
+ return llvm::StringSwitch<bool>(II->getName())
+ .Case("__make_integer_seq", LangOpts.CPlusPlus)
+ .Case("__type_pack_element", LangOpts.CPlusPlus)
+ .Default(false);
+ }
+ });
+ } else if (II == Ident__is_identifier) {
+ EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this,
+ [](Token &Tok, bool &HasLexedNextToken) -> int {
+ return Tok.is(tok::identifier);
+ });
+ } else if (II == Ident__has_attribute) {
+ EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this,
+ [this](Token &Tok, bool &HasLexedNextToken) -> int {
+ IdentifierInfo *II = ExpectFeatureIdentifierInfo(Tok, *this,
+ diag::err_feature_check_malformed);
+ return II ? hasAttribute(AttrSyntax::GNU, nullptr, II,
+ getTargetInfo(), getLangOpts()) : 0;
+ });
+ } else if (II == Ident__has_declspec) {
+ EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this,
+ [this](Token &Tok, bool &HasLexedNextToken) -> int {
+ IdentifierInfo *II = ExpectFeatureIdentifierInfo(Tok, *this,
+ diag::err_feature_check_malformed);
+ return II ? hasAttribute(AttrSyntax::Declspec, nullptr, II,
+ getTargetInfo(), getLangOpts()) : 0;
+ });
+ } else if (II == Ident__has_cpp_attribute) {
+ EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this,
+ [this](Token &Tok, bool &HasLexedNextToken) -> int {
+ IdentifierInfo *ScopeII = nullptr;
+ IdentifierInfo *II = ExpectFeatureIdentifierInfo(Tok, *this,
+ diag::err_feature_check_malformed);
+ if (!II)
+ return false;
+
+ // It is possible to receive a scope token. Read the "::", if it is
+ // available, and the subsequent identifier.
LexUnexpandedToken(Tok);
- bool IsScopeValid = true;
- if (II == Ident__has_cpp_attribute && Tok.is(tok::coloncolon)) {
+ if (Tok.isNot(tok::coloncolon))
+ HasLexedNextToken = true;
+ else {
+ ScopeII = II;
LexUnexpandedToken(Tok);
- // The first thing we read was not the feature, it was the scope.
- ScopeII = FeatureII;
- if ((FeatureII = Tok.getIdentifierInfo()))
- LexUnexpandedToken(Tok);
- else
- IsScopeValid = false;
+ II = ExpectFeatureIdentifierInfo(Tok, *this,
+ diag::err_feature_check_malformed);
}
- // Read the closing paren.
- if (IsScopeValid && Tok.is(tok::r_paren))
- IsValid = true;
- }
- // Eat tokens until ')'.
- while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::eod) &&
- Tok.isNot(tok::eof))
- LexUnexpandedToken(Tok);
- }
- int Value = 0;
- if (!IsValid)
- Diag(StartLoc, diag::err_feature_check_malformed);
- else if (II == Ident__is_identifier)
- Value = FeatureII->getTokenID() == tok::identifier;
- else if (II == Ident__has_builtin) {
- // Check for a builtin is trivial.
- if (FeatureII->getBuiltinID() != 0) {
- Value = true;
- } else {
- StringRef Feature = FeatureII->getName();
- Value = llvm::StringSwitch<bool>(Feature)
- .Case("__make_integer_seq", getLangOpts().CPlusPlus)
- .Default(false);
- }
- } else if (II == Ident__has_attribute)
- Value = hasAttribute(AttrSyntax::GNU, nullptr, FeatureII,
- getTargetInfo(), getLangOpts());
- else if (II == Ident__has_cpp_attribute)
- Value = hasAttribute(AttrSyntax::CXX, ScopeII, FeatureII,
- getTargetInfo(), getLangOpts());
- else if (II == Ident__has_declspec)
- Value = hasAttribute(AttrSyntax::Declspec, nullptr, FeatureII,
- getTargetInfo(), getLangOpts());
- else if (II == Ident__has_extension)
- Value = HasExtension(*this, FeatureII);
- else {
- assert(II == Ident__has_feature && "Must be feature check");
- Value = HasFeature(*this, FeatureII);
- }
-
- if (!IsValid)
- return;
- OS << Value;
- Tok.setKind(tok::numeric_constant);
+ return II ? hasAttribute(AttrSyntax::CXX, ScopeII, II,
+ getTargetInfo(), getLangOpts()) : 0;
+ });
} else if (II == Ident__has_include ||
II == Ident__has_include_next) {
// The argument to these two builtins should be a parenthesized
@@ -1679,64 +1761,44 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
Tok.setKind(tok::numeric_constant);
} else if (II == Ident__has_warning) {
// The argument should be a parenthesized string literal.
- // The argument to these builtins should be a parenthesized identifier.
- SourceLocation StartLoc = Tok.getLocation();
- bool IsValid = false;
- bool Value = false;
- // Read the '('.
- LexUnexpandedToken(Tok);
- do {
- if (Tok.isNot(tok::l_paren)) {
- Diag(StartLoc, diag::err_warning_check_malformed);
- break;
- }
-
- LexUnexpandedToken(Tok);
- std::string WarningName;
- SourceLocation StrStartLoc = Tok.getLocation();
- if (!FinishLexStringLiteral(Tok, WarningName, "'__has_warning'",
- /*MacroExpansion=*/false)) {
- // Eat tokens until ')'.
- while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::eod) &&
- Tok.isNot(tok::eof))
- LexUnexpandedToken(Tok);
- break;
- }
-
- // Is the end a ')'?
- if (!(IsValid = Tok.is(tok::r_paren))) {
- Diag(StartLoc, diag::err_warning_check_malformed);
- break;
- }
-
- // FIXME: Should we accept "-R..." flags here, or should that be handled
- // by a separate __has_remark?
- if (WarningName.size() < 3 || WarningName[0] != '-' ||
- WarningName[1] != 'W') {
- Diag(StrStartLoc, diag::warn_has_warning_invalid_option);
- break;
- }
+ EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this,
+ [this](Token &Tok, bool &HasLexedNextToken) -> int {
+ std::string WarningName;
+ SourceLocation StrStartLoc = Tok.getLocation();
+
+ HasLexedNextToken = Tok.is(tok::string_literal);
+ if (!FinishLexStringLiteral(Tok, WarningName, "'__has_warning'",
+ /*MacroExpansion=*/false))
+ return false;
+
+ // FIXME: Should we accept "-R..." flags here, or should that be
+ // handled by a separate __has_remark?
+ if (WarningName.size() < 3 || WarningName[0] != '-' ||
+ WarningName[1] != 'W') {
+ Diag(StrStartLoc, diag::warn_has_warning_invalid_option);
+ return false;
+ }
- // Finally, check if the warning flags maps to a diagnostic group.
- // We construct a SmallVector here to talk to getDiagnosticIDs().
- // Although we don't use the result, this isn't a hot path, and not
- // worth special casing.
- SmallVector<diag::kind, 10> Diags;
- Value = !getDiagnostics().getDiagnosticIDs()->
- getDiagnosticsInGroup(diag::Flavor::WarningOrError,
- WarningName.substr(2), Diags);
- } while (false);
-
- if (!IsValid)
- return;
- OS << (int)Value;
- Tok.setKind(tok::numeric_constant);
+ // Finally, check if the warning flags maps to a diagnostic group.
+ // We construct a SmallVector here to talk to getDiagnosticIDs().
+ // Although we don't use the result, this isn't a hot path, and not
+ // worth special casing.
+ SmallVector<diag::kind, 10> Diags;
+ return !getDiagnostics().getDiagnosticIDs()->
+ getDiagnosticsInGroup(diag::Flavor::WarningOrError,
+ WarningName.substr(2), Diags);
+ });
} else if (II == Ident__building_module) {
// The argument to this builtin should be an identifier. The
// builtin evaluates to 1 when that identifier names the module we are
// currently building.
- OS << (int)EvaluateBuildingModule(Tok, II, *this);
- Tok.setKind(tok::numeric_constant);
+ EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this,
+ [this](Token &Tok, bool &HasLexedNextToken) -> int {
+ IdentifierInfo *II = ExpectFeatureIdentifierInfo(Tok, *this,
+ diag::err_expected_id_building_module);
+ return getLangOpts().CompilingModule && II &&
+ (II->getName() == getLangOpts().CurrentModule);
+ });
} else if (II == Ident__MODULE__) {
// The current module as an identifier.
OS << getLangOpts().CurrentModule;