aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2012-09-25 15:44:52 +0000
committerDouglas Gregor <dgregor@apple.com>2012-09-25 15:44:52 +0000
commitb09de5177ee8101818a59dcd0038c75b190a2509 (patch)
tree5076842d1c2373dc9e4717bebb3b7a879da4b9d9
parent9158a5624154bc43bbbf059c07a2f7b2cd45c1a1 (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.td4
-rw-r--r--include/clang/Lex/Preprocessor.h2
-rw-r--r--lib/Lex/PPMacroExpansion.cpp67
-rw-r--r--test/Modules/Inputs/macros.h9
-rw-r--r--test/Modules/macros.c9
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