diff options
author | Douglas Gregor <dgregor@apple.com> | 2012-09-25 15:44:52 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2012-09-25 15:44:52 +0000 |
commit | b09de5177ee8101818a59dcd0038c75b190a2509 (patch) | |
tree | 5076842d1c2373dc9e4717bebb3b7a879da4b9d9 | |
parent | 9158a5624154bc43bbbf059c07a2f7b2cd45c1a1 (diff) |
Introduce builtin macros to determine whether we're building a
specific module (__building_module(modulename)) and to get the name of
the current module as an identifier (__MODULE__).
Used to help headers behave differently when they're being included as
part of building a module. Oh, the irony.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@164605 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Basic/DiagnosticLexKinds.td | 4 | ||||
-rw-r--r-- | include/clang/Lex/Preprocessor.h | 2 | ||||
-rw-r--r-- | lib/Lex/PPMacroExpansion.cpp | 67 | ||||
-rw-r--r-- | test/Modules/Inputs/macros.h | 9 | ||||
-rw-r--r-- | test/Modules/macros.c | 9 |
5 files changed, 90 insertions, 1 deletions
diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td index b080360fad..fbdf56ce4a 100644 --- a/include/clang/Basic/DiagnosticLexKinds.td +++ b/include/clang/Basic/DiagnosticLexKinds.td @@ -509,5 +509,7 @@ def warn_auto_module_import : Warning< "import of module '%1'">, InGroup<AutoImport>, DefaultIgnore; def warn_uncovered_module_header : Warning< "umbrella header does not include header '%0'">, InGroup<IncompleteUmbrella>; - +def err_expected_id_building_module : Error< + "expected a module name in '__building_module' expression">; + } diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h index 0ddf82e5df..76d8fdb259 100644 --- a/include/clang/Lex/Preprocessor.h +++ b/include/clang/Lex/Preprocessor.h @@ -98,6 +98,8 @@ class Preprocessor : public RefCountedBase<Preprocessor> { IdentifierInfo *Ident__has_include; // __has_include IdentifierInfo *Ident__has_include_next; // __has_include_next IdentifierInfo *Ident__has_warning; // __has_warning + IdentifierInfo *Ident__building_module; // __building_module + IdentifierInfo *Ident__MODULE__; // __MODULE__ SourceLocation DATELoc, TIMELoc; unsigned CounterValue; // Next __COUNTER__ value. diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index 839cec0744..b2d597713b 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -105,6 +105,20 @@ void Preprocessor::RegisterBuiltinMacros() { Ident__has_include_next = RegisterBuiltinMacro(*this, "__has_include_next"); Ident__has_warning = RegisterBuiltinMacro(*this, "__has_warning"); + // Modules. + if (LangOpts.Modules) { + Ident__building_module = RegisterBuiltinMacro(*this, "__building_module"); + + // __MODULE__ + if (!LangOpts.CurrentModule.empty()) + Ident__MODULE__ = RegisterBuiltinMacro(*this, "__MODULE__"); + else + Ident__MODULE__ = 0; + } else { + Ident__building_module = 0; + Ident__MODULE__ = 0; + } + // Microsoft Extensions. if (LangOpts.MicrosoftExt) Ident__pragma = RegisterBuiltinMacro(*this, "__pragma"); @@ -907,6 +921,47 @@ static bool EvaluateHasIncludeNext(Token &Tok, return EvaluateHasIncludeCommon(Tok, II, PP, Lookup); } +/// \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 '('. + if (Tok.isNot(tok::l_paren)) { + PP.Diag(Tok.getLocation(), diag::err_pp_missing_lparen) << II->getName(); + return false; + } + + // Save '(' location for possible missing ')' message. + SourceLocation LParenLoc = Tok.getLocation(); + + // Get the module name. + PP.LexNonComment(Tok); + + // Ensure that we have an identifier. + if (Tok.isNot(tok::identifier)) { + PP.Diag(Tok.getLocation(), diag::err_expected_id_building_module); + return false; + } + + bool Result + = Tok.getIdentifierInfo()->getName() == PP.getLangOpts().CurrentModule; + + // Get ')'. + PP.LexNonComment(Tok); + + // Ensure we have a trailing ). + if (Tok.isNot(tok::r_paren)) { + PP.Diag(Tok.getLocation(), diag::err_pp_missing_rparen) << II->getName(); + PP.Diag(LParenLoc, diag::note_matching) << "("; + return false; + } + + return Result; +} + /// ExpandBuiltinMacro - If an identifier token is read that is to be expanded /// as a builtin macro, handle it and return the next token as 'Tok'. void Preprocessor::ExpandBuiltinMacro(Token &Tok) { @@ -1162,6 +1217,18 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { OS << (int)Value; Tok.setKind(tok::numeric_constant); + } 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); + } else if (II == Ident__MODULE__) { + // The current module as an identifier. + OS << getLangOpts().CurrentModule; + IdentifierInfo *ModuleII = getIdentifierInfo(getLangOpts().CurrentModule); + Tok.setIdentifierInfo(ModuleII); + Tok.setKind(ModuleII->getTokenID()); } else { llvm_unreachable("Unknown identifier!"); } diff --git a/test/Modules/Inputs/macros.h b/test/Modules/Inputs/macros.h index 4f535563ad..27f43c0626 100644 --- a/test/Modules/Inputs/macros.h +++ b/test/Modules/Inputs/macros.h @@ -8,3 +8,12 @@ #__private_macro MODULE int (INTEGER); + +#if !__building_module(macros) +# error Can't include this header without building the 'macros' module. +#endif + +#ifdef __MODULE__ +extern int __MODULE__; +#endif + diff --git a/test/Modules/macros.c b/test/Modules/macros.c index 83e1c66a10..d93ce35a03 100644 --- a/test/Modules/macros.c +++ b/test/Modules/macros.c @@ -27,4 +27,13 @@ DOUBLE *dp = &d; void f() { // CHECK-PREPROCESSED: int i = INTEGER; int i = INTEGER; // the value was exported, the macro was not. + i += macros; // expanded from __MODULE__ within the 'macros' module. } + +#ifdef __MODULE__ +# error Not building a module! +#endif + +#if __building_module(macros) +# error Not building a module +#endif |