[cfe-commits] r45716 - in /cfe/trunk: Lex/Preprocessor.cpp include/clang/Lex/MultipleIncludeOpt.h test/Preprocessor/mi_opt.c test/Preprocessor/mi_opt.h
Chris Lattner
sabre at nondot.org
Mon Jan 7 11:50:28 PST 2008
Author: lattner
Date: Mon Jan 7 13:50:27 2008
New Revision: 45716
URL: http://llvm.org/viewvc/llvm-project?rev=45716&view=rev
Log:
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!
Added:
cfe/trunk/test/Preprocessor/mi_opt.c
cfe/trunk/test/Preprocessor/mi_opt.h
Modified:
cfe/trunk/Lex/Preprocessor.cpp
cfe/trunk/include/clang/Lex/MultipleIncludeOpt.h
Modified: cfe/trunk/Lex/Preprocessor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/Lex/Preprocessor.cpp?rev=45716&r1=45715&r2=45716&view=diff
==============================================================================
--- cfe/trunk/Lex/Preprocessor.cpp (original)
+++ cfe/trunk/Lex/Preprocessor.cpp Mon Jan 7 13:50:27 2008
@@ -784,6 +784,10 @@
/// expanded as a macro, handle it and return the next token as 'Identifier'.
bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
MacroInfo *MI) {
+ // If this is a macro exapnsion in the "#if !defined(x)" line for the file,
+ // then the macro could expand to different things in other contexts, we need
+ // to disable the optimization in this case.
+ if (CurLexer) CurLexer->MIOpt.ExpandedMacro();
// If this is a builtin macro, like __LINE__ or _Pragma, handle it specially.
if (MI->isBuiltinMacro()) {
Modified: cfe/trunk/include/clang/Lex/MultipleIncludeOpt.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/MultipleIncludeOpt.h?rev=45716&r1=45715&r2=45716&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/MultipleIncludeOpt.h (original)
+++ cfe/trunk/include/clang/Lex/MultipleIncludeOpt.h Mon Jan 7 13:50:27 2008
@@ -29,12 +29,23 @@
/// 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 @@
// 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;
Added: cfe/trunk/test/Preprocessor/mi_opt.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Preprocessor/mi_opt.c?rev=45716&view=auto
==============================================================================
--- cfe/trunk/test/Preprocessor/mi_opt.c (added)
+++ cfe/trunk/test/Preprocessor/mi_opt.c Mon Jan 7 13:50:27 2008
@@ -0,0 +1,11 @@
+// RUN: not clang -fsyntax-only %s
+// PR1900
+// This test should get a redefinition error from m_iopt.h: the MI opt
+// shouldn't apply.
+
+#define MACRO
+#include "mi_opt.h"
+#undef MACRO
+#define MACRO || 1
+#include "mi_opt.h"
+
Added: cfe/trunk/test/Preprocessor/mi_opt.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Preprocessor/mi_opt.h?rev=45716&view=auto
==============================================================================
--- cfe/trunk/test/Preprocessor/mi_opt.h (added)
+++ cfe/trunk/test/Preprocessor/mi_opt.h Mon Jan 7 13:50:27 2008
@@ -0,0 +1,4 @@
+#if !defined foo MACRO
+#define foo
+int x = 2;
+#endif
More information about the cfe-commits
mailing list