aboutsummaryrefslogtreecommitdiff
path: root/include/clang/Lex/MultipleIncludeOpt.h
diff options
context:
space:
mode:
authorChris Lattner <sabre@nondot.org>2008-01-07 19:50:27 +0000
committerChris Lattner <sabre@nondot.org>2008-01-07 19:50:27 +0000
commit4d730461735cc5cb8ecbd2f6106da9ec234064ad (patch)
tree1755f2c3cde7104c5f8a0e2c04f2a04d267bc572 /include/clang/Lex/MultipleIncludeOpt.h
parenta526c5c67e5a0473c340903ee542ce570119665f (diff)
Fix a nasty corner case that Neil noticed in PR1900, where we would
incorrectly apply the multiple include optimization to files with guards like: #if !defined(x) MACRO where MACRO could expand to different things in different contexts. Thanks Neil! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@45716 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'include/clang/Lex/MultipleIncludeOpt.h')
-rw-r--r--include/clang/Lex/MultipleIncludeOpt.h33
1 files changed, 28 insertions, 5 deletions
diff --git a/include/clang/Lex/MultipleIncludeOpt.h b/include/clang/Lex/MultipleIncludeOpt.h
index 83b995b485..08bb259fda 100644
--- a/include/clang/Lex/MultipleIncludeOpt.h
+++ b/include/clang/Lex/MultipleIncludeOpt.h
@@ -29,12 +29,23 @@ class MultipleIncludeOpt {
/// to false, that way any tokens before the first #ifdef or after the last
/// #endif can be easily detected.
bool ReadAnyTokens;
+
+ /// ReadAnyTokens - This is set to false when a file is first opened and true
+ /// any time a token is returned to the client or a (non-multiple-include)
+ /// directive is parsed. When the final #endif is parsed this is reset back
+ /// to false, that way any tokens before the first #ifdef or after the last
+ /// #endif can be easily detected.
+ bool DidMacroExpansion;
/// TheMacro - The controlling macro for a file, if valid.
///
const IdentifierInfo *TheMacro;
public:
- MultipleIncludeOpt() : ReadAnyTokens(false), TheMacro(0) {}
+ MultipleIncludeOpt() {
+ ReadAnyTokens = false;
+ DidMacroExpansion = false;
+ TheMacro = 0;
+ }
/// Invalidate - Permenantly mark this file as not being suitable for the
/// include-file optimization.
@@ -53,18 +64,30 @@ public:
// If a token is read, remember that we have seen a side-effect in this file.
void ReadToken() { ReadAnyTokens = true; }
+ /// ExpandedMacro - When a macro is expanded with this lexer as the current
+ /// buffer, this method is called to disable the MIOpt if needed.
+ void ExpandedMacro() { DidMacroExpansion = true; }
+
/// EnterTopLevelIFNDEF - When entering a top-level #ifndef directive (or the
/// "#if !defined" equivalent) without any preceding tokens, this method is
/// called.
+ ///
+ /// Note, we don't care about the input value of 'ReadAnyTokens'. The caller
+ /// ensures that this is only called if there are no tokens read before the
+ /// #ifndef. The caller is required to do this, because reading the #if line
+ /// obviously reads in in tokens.
void EnterTopLevelIFNDEF(const IdentifierInfo *M) {
- // Note, we don't care about the input value of 'ReadAnyTokens'. The caller
- // ensures that this is only called if there are no tokens read before the
- // #ifndef.
-
// If the macro is already set, this is after the top-level #endif.
if (TheMacro)
return Invalidate();
+ // If we have already expanded a macro by the end of the #ifndef line, then
+ // there is a macro expansion *in* the #ifndef line. This means that the
+ // condition could evaluate differently when subsequently #included. Reject
+ // this.
+ if (DidMacroExpansion)
+ return Invalidate();
+
// Remember that we're in the #if and that we have the macro.
ReadAnyTokens = true;
TheMacro = M;