[PATCH] D34263: [preprocessor] When preprocessor option 'SingleFileParseMode' is enabled, parse all directive blocks if the condition uses undefined macros

2017-06-20 Thread Phabricator via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL305797: [preprocessor] When preprocessor option 
'SingleFileParseMode' is enabled, parseā€¦ (authored by akirtzidis).

Changed prior to commit:
  https://reviews.llvm.org/D34263?vs=103067=103206#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D34263

Files:
  cfe/trunk/include/clang/Lex/Preprocessor.h
  cfe/trunk/include/clang/Lex/PreprocessorOptions.h
  cfe/trunk/lib/Lex/PPDirectives.cpp
  cfe/trunk/lib/Lex/PPExpressions.cpp
  cfe/trunk/test/Index/singe-file-parse.m
  cfe/trunk/test/Index/single-file-parse.m

Index: cfe/trunk/include/clang/Lex/PreprocessorOptions.h
===
--- cfe/trunk/include/clang/Lex/PreprocessorOptions.h
+++ cfe/trunk/include/clang/Lex/PreprocessorOptions.h
@@ -96,6 +96,10 @@
   std::string TokenCache;
 
   /// When enabled, preprocessor is in a mode for parsing a single file only.
+  ///
+  /// Disables #includes of other files and if there are unresolved identifiers
+  /// in preprocessor directive conditions it causes all blocks to be parsed so
+  /// that the client can get the maximum amount of information from the parser.
   bool SingleFileParseMode = false;
 
   /// When enabled, the preprocessor will construct editor placeholder tokens.
Index: cfe/trunk/include/clang/Lex/Preprocessor.h
===
--- cfe/trunk/include/clang/Lex/Preprocessor.h
+++ cfe/trunk/include/clang/Lex/Preprocessor.h
@@ -1835,11 +1835,20 @@
   /// \brief A fast PTH version of SkipExcludedConditionalBlock.
   void PTHSkipExcludedConditionalBlock();
 
+  /// Information about the result for evaluating an expression for a
+  /// preprocessor directive.
+  struct DirectiveEvalResult {
+/// Whether the expression was evaluated as true or not.
+bool Conditional;
+/// True if the expression contained identifiers that were undefined.
+bool IncludedUndefinedIds;
+  };
+
   /// \brief Evaluate an integer constant expression that may occur after a
-  /// \#if or \#elif directive and return it as a bool.
+  /// \#if or \#elif directive and return a \p DirectiveEvalResult object.
   ///
   /// If the expression is equivalent to "!defined(X)" return X in IfNDefMacro.
-  bool EvaluateDirectiveExpression(IdentifierInfo *);
+  DirectiveEvalResult EvaluateDirectiveExpression(IdentifierInfo *);
 
   /// \brief Install the standard preprocessor pragmas:
   /// \#pragma GCC poison/system_header/dependency and \#pragma once.
Index: cfe/trunk/test/Index/single-file-parse.m
===
--- cfe/trunk/test/Index/single-file-parse.m
+++ cfe/trunk/test/Index/single-file-parse.m
@@ -0,0 +1,111 @@
+// RUN: c-index-test -single-file-parse %s | FileCheck %s
+
+#include 
+
+// CHECK-NOT: TypedefDecl=intptr_t
+
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=MyCls
+@interface MyCls
+// CHECK: [[@LINE+1]]:8: ObjCInstanceMethodDecl=some_meth
+-(void)some_meth;
+@end
+
+#if 1
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test1
+@interface Test1 @end
+#else
+// CHECK-NOT: [[@LINE+1]]:12:
+@interface Test2 @end
+#endif
+
+#if 0
+// CHECK-NOT: [[@LINE+1]]:12:
+@interface Test3 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test4
+@interface Test4 @end
+#endif
+
+#if SOMETHING_NOT_DEFINED
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test5
+@interface Test5 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test6
+@interface Test6 @end
+#endif
+
+#define SOMETHING_DEFINED 1
+#if SOMETHING_DEFINED
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test7
+@interface Test7 @end
+#else
+// CHECK-NOT: [[@LINE+1]]:12:
+@interface Test8 @end
+#endif
+
+#if defined(SOMETHING_NOT_DEFINED)
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test9
+@interface Test9 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test10
+@interface Test10 @end
+#endif
+
+#if defined(SOMETHING_DEFINED)
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test11
+@interface Test11 @end
+#else
+// CHECK-NOT: [[@LINE+1]]:12:
+@interface Test12 @end
+#endif
+
+#if SOMETHING_NOT_DEFINED1
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test13
+@interface Test13 @end
+#elif SOMETHING_NOT_DEFINED2
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test14
+@interface Test14 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test15
+@interface Test15 @end
+#endif
+
+#ifdef SOMETHING_NOT_DEFINED
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test19
+@interface Test19 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test20
+@interface Test20 @end
+#endif
+
+#ifdef SOMETHING_DEFINED
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test21
+@interface Test21 @end
+#else
+// CHECK-NOT: [[@LINE+1]]:12:
+@interface Test22 @end
+#endif
+
+#ifndef SOMETHING_NOT_DEFINED
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test23
+@interface Test23 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test24
+@interface 

[PATCH] D34263: [preprocessor] When preprocessor option 'SingleFileParseMode' is enabled, parse all directive blocks if the condition uses undefined macros

2017-06-20 Thread Vladimir Voskresensky via Phabricator via cfe-commits
voskresensky.vladimir added a comment.

> Here's an example to clarify the difference:

Thanks for the example. You are right, I missed this difference in patch.


https://reviews.llvm.org/D34263



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D34263: [preprocessor] When preprocessor option 'SingleFileParseMode' is enabled, parse all directive blocks if the condition uses undefined macros

2017-06-20 Thread Manuel Klimek via Phabricator via cfe-commits
klimek added a comment.

In https://reviews.llvm.org/D34263#784168, @akyrtzi wrote:

> In https://reviews.llvm.org/D34263#783694, @klimek wrote:
>
> > how many patches for single file mode are coming down the road, though? I'm 
> > somewhat concerned about the overall complexity it'll add to clang.
>
>
> There is no other patch for using this preprocessor option. Any related 
> improvements down the road will be about general improvements for error 
> recovery, for example things like this:
>
> - Introduce an `UnresolvedTypename` type instead of changing unresolved types 
> to `int`.
> - For `@interace A : B`, don't completely drop `B` from the super-class list 
> of `A` if it is unresolved. These kind of improvements are not conditional.


That's great! I was always hoping we'd get some diag improvements out of these 
:D


https://reviews.llvm.org/D34263



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D34263: [preprocessor] When preprocessor option 'SingleFileParseMode' is enabled, parse all directive blocks if the condition uses undefined macros

2017-06-20 Thread Manuel Klimek via Phabricator via cfe-commits
klimek accepted this revision.
klimek added a comment.
This revision is now accepted and ready to land.

oh, and lg from my side


https://reviews.llvm.org/D34263



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D34263: [preprocessor] When preprocessor option 'SingleFileParseMode' is enabled, parse all directive blocks if the condition uses undefined macros

2017-06-19 Thread Argyrios Kyrtzidis via Phabricator via cfe-commits
akyrtzi updated this revision to Diff 103067.
akyrtzi added a comment.

Update doc-comment for `Preprocessor::EvaluateDirectiveExpression`


https://reviews.llvm.org/D34263

Files:
  include/clang/Lex/Preprocessor.h
  include/clang/Lex/PreprocessorOptions.h
  lib/Lex/PPDirectives.cpp
  lib/Lex/PPExpressions.cpp
  test/Index/singe-file-parse.m

Index: test/Index/singe-file-parse.m
===
--- test/Index/singe-file-parse.m
+++ test/Index/singe-file-parse.m
@@ -9,3 +9,103 @@
 // CHECK: [[@LINE+1]]:8: ObjCInstanceMethodDecl=some_meth
 -(void)some_meth;
 @end
+
+#if 1
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test1
+@interface Test1 @end
+#else
+// CHECK-NOT: [[@LINE+1]]:12:
+@interface Test2 @end
+#endif
+
+#if 0
+// CHECK-NOT: [[@LINE+1]]:12:
+@interface Test3 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test4
+@interface Test4 @end
+#endif
+
+#if SOMETHING_NOT_DEFINED
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test5
+@interface Test5 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test6
+@interface Test6 @end
+#endif
+
+#define SOMETHING_DEFINED 1
+#if SOMETHING_DEFINED
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test7
+@interface Test7 @end
+#else
+// CHECK-NOT: [[@LINE+1]]:12:
+@interface Test8 @end
+#endif
+
+#if defined(SOMETHING_NOT_DEFINED)
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test9
+@interface Test9 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test10
+@interface Test10 @end
+#endif
+
+#if defined(SOMETHING_DEFINED)
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test11
+@interface Test11 @end
+#else
+// CHECK-NOT: [[@LINE+1]]:12:
+@interface Test12 @end
+#endif
+
+#if SOMETHING_NOT_DEFINED1
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test13
+@interface Test13 @end
+#elif SOMETHING_NOT_DEFINED2
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test14
+@interface Test14 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test15
+@interface Test15 @end
+#endif
+
+#ifdef SOMETHING_NOT_DEFINED
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test19
+@interface Test19 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test20
+@interface Test20 @end
+#endif
+
+#ifdef SOMETHING_DEFINED
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test21
+@interface Test21 @end
+#else
+// CHECK-NOT: [[@LINE+1]]:12:
+@interface Test22 @end
+#endif
+
+#ifndef SOMETHING_NOT_DEFINED
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test23
+@interface Test23 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test24
+@interface Test24 @end
+#endif
+
+#ifndef SOMETHING_DEFINED
+// CHECK-NOT: [[@LINE+1]]:12:
+@interface Test25 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test26
+@interface Test26 @end
+#endif
+
+#if 1 < SOMETHING_NOT_DEFINED
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test27
+@interface Test27 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test28
+@interface Test28 @end
+#endif
Index: lib/Lex/PPExpressions.cpp
===
--- lib/Lex/PPExpressions.cpp
+++ lib/Lex/PPExpressions.cpp
@@ -73,6 +73,7 @@
 
 static bool EvaluateDirectiveSubExpr(PPValue , unsigned MinPrec,
  Token , bool ValueLive,
+ bool ,
  Preprocessor );
 
 /// DefinedTracker - This struct is used while parsing expressions to keep track
@@ -93,6 +94,7 @@
   /// TheMacro - When the state is DefinedMacro or NotDefinedMacro, this
   /// indicates the macro that was checked.
   IdentifierInfo *TheMacro;
+  bool IncludedUndefinedIds = false;
 };
 
 /// EvaluateDefined - Process a 'defined(sym)' expression.
@@ -128,6 +130,7 @@
   MacroDefinition Macro = PP.getMacroDefinition(II);
   Result.Val = !!Macro;
   Result.Val.setIsUnsigned(false); // Result is signed intmax_t.
+  DT.IncludedUndefinedIds = !Macro;
 
   // If there is a macro, mark it used.
   if (Result.Val != 0 && ValueLive)
@@ -255,6 +258,8 @@
 Result.Val.setIsUnsigned(false);  // "0" is signed intmax_t 0.
 Result.setIdentifier(II);
 Result.setRange(PeekTok.getLocation());
+DT.IncludedUndefinedIds = (II->getTokenID() != tok::kw_true &&
+   II->getTokenID() != tok::kw_false);
 PP.LexNonComment(PeekTok);
 return false;
   }
@@ -400,7 +405,8 @@
   // Just use DT unmodified as our result.
 } else {
   // Otherwise, we have something like (x+y), and we consumed '(x'.
-  if (EvaluateDirectiveSubExpr(Result, 1, PeekTok, ValueLive, PP))
+  if (EvaluateDirectiveSubExpr(Result, 1, PeekTok, ValueLive,
+   DT.IncludedUndefinedIds, PP))
 return true;
 
   if (PeekTok.isNot(tok::r_paren)) {
@@ -532,6 +538,7 @@
 /// evaluation, such as division by zero warnings.
 static bool EvaluateDirectiveSubExpr(PPValue , unsigned MinPrec,
  Token , bool ValueLive,
+

[PATCH] D34263: [preprocessor] When preprocessor option 'SingleFileParseMode' is enabled, parse all directive blocks if the condition uses undefined macros

2017-06-19 Thread Argyrios Kyrtzidis via Phabricator via cfe-commits
akyrtzi updated this revision to Diff 103066.
akyrtzi added a comment.

Provide doc-comments for `struct DirectiveEvalResult`.


https://reviews.llvm.org/D34263

Files:
  include/clang/Lex/Preprocessor.h
  include/clang/Lex/PreprocessorOptions.h
  lib/Lex/PPDirectives.cpp
  lib/Lex/PPExpressions.cpp
  test/Index/singe-file-parse.m

Index: test/Index/singe-file-parse.m
===
--- test/Index/singe-file-parse.m
+++ test/Index/singe-file-parse.m
@@ -9,3 +9,103 @@
 // CHECK: [[@LINE+1]]:8: ObjCInstanceMethodDecl=some_meth
 -(void)some_meth;
 @end
+
+#if 1
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test1
+@interface Test1 @end
+#else
+// CHECK-NOT: [[@LINE+1]]:12:
+@interface Test2 @end
+#endif
+
+#if 0
+// CHECK-NOT: [[@LINE+1]]:12:
+@interface Test3 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test4
+@interface Test4 @end
+#endif
+
+#if SOMETHING_NOT_DEFINED
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test5
+@interface Test5 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test6
+@interface Test6 @end
+#endif
+
+#define SOMETHING_DEFINED 1
+#if SOMETHING_DEFINED
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test7
+@interface Test7 @end
+#else
+// CHECK-NOT: [[@LINE+1]]:12:
+@interface Test8 @end
+#endif
+
+#if defined(SOMETHING_NOT_DEFINED)
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test9
+@interface Test9 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test10
+@interface Test10 @end
+#endif
+
+#if defined(SOMETHING_DEFINED)
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test11
+@interface Test11 @end
+#else
+// CHECK-NOT: [[@LINE+1]]:12:
+@interface Test12 @end
+#endif
+
+#if SOMETHING_NOT_DEFINED1
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test13
+@interface Test13 @end
+#elif SOMETHING_NOT_DEFINED2
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test14
+@interface Test14 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test15
+@interface Test15 @end
+#endif
+
+#ifdef SOMETHING_NOT_DEFINED
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test19
+@interface Test19 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test20
+@interface Test20 @end
+#endif
+
+#ifdef SOMETHING_DEFINED
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test21
+@interface Test21 @end
+#else
+// CHECK-NOT: [[@LINE+1]]:12:
+@interface Test22 @end
+#endif
+
+#ifndef SOMETHING_NOT_DEFINED
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test23
+@interface Test23 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test24
+@interface Test24 @end
+#endif
+
+#ifndef SOMETHING_DEFINED
+// CHECK-NOT: [[@LINE+1]]:12:
+@interface Test25 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test26
+@interface Test26 @end
+#endif
+
+#if 1 < SOMETHING_NOT_DEFINED
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test27
+@interface Test27 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test28
+@interface Test28 @end
+#endif
Index: lib/Lex/PPExpressions.cpp
===
--- lib/Lex/PPExpressions.cpp
+++ lib/Lex/PPExpressions.cpp
@@ -73,6 +73,7 @@
 
 static bool EvaluateDirectiveSubExpr(PPValue , unsigned MinPrec,
  Token , bool ValueLive,
+ bool ,
  Preprocessor );
 
 /// DefinedTracker - This struct is used while parsing expressions to keep track
@@ -93,6 +94,7 @@
   /// TheMacro - When the state is DefinedMacro or NotDefinedMacro, this
   /// indicates the macro that was checked.
   IdentifierInfo *TheMacro;
+  bool IncludedUndefinedIds = false;
 };
 
 /// EvaluateDefined - Process a 'defined(sym)' expression.
@@ -128,6 +130,7 @@
   MacroDefinition Macro = PP.getMacroDefinition(II);
   Result.Val = !!Macro;
   Result.Val.setIsUnsigned(false); // Result is signed intmax_t.
+  DT.IncludedUndefinedIds = !Macro;
 
   // If there is a macro, mark it used.
   if (Result.Val != 0 && ValueLive)
@@ -255,6 +258,8 @@
 Result.Val.setIsUnsigned(false);  // "0" is signed intmax_t 0.
 Result.setIdentifier(II);
 Result.setRange(PeekTok.getLocation());
+DT.IncludedUndefinedIds = (II->getTokenID() != tok::kw_true &&
+   II->getTokenID() != tok::kw_false);
 PP.LexNonComment(PeekTok);
 return false;
   }
@@ -400,7 +405,8 @@
   // Just use DT unmodified as our result.
 } else {
   // Otherwise, we have something like (x+y), and we consumed '(x'.
-  if (EvaluateDirectiveSubExpr(Result, 1, PeekTok, ValueLive, PP))
+  if (EvaluateDirectiveSubExpr(Result, 1, PeekTok, ValueLive,
+   DT.IncludedUndefinedIds, PP))
 return true;
 
   if (PeekTok.isNot(tok::r_paren)) {
@@ -532,6 +538,7 @@
 /// evaluation, such as division by zero warnings.
 static bool EvaluateDirectiveSubExpr(PPValue , unsigned MinPrec,
  Token , bool ValueLive,
+

[PATCH] D34263: [preprocessor] When preprocessor option 'SingleFileParseMode' is enabled, parse all directive blocks if the condition uses undefined macros

2017-06-19 Thread Argyrios Kyrtzidis via Phabricator via cfe-commits
akyrtzi added a comment.

In https://reviews.llvm.org/D34263#783770, @voskresensky.vladimir wrote:

> What I find problematic in this patch is PPOpts->SingleFileParseMode checks.
>  Let's suppose we implement what I mentioned above => how is it going to 
> co-exist nicely? I think code will be less understandable with both: check of 
> flag and call to PPCallbacks.
>  What I propose is to move the logic from the PPOpts single flag into 
> PPCallbacks. And from check of flag to query of PPCallbacks.
>  Of course when you create PPCallbacks you can consult global 
> SingleFileParseMode to create default implementation to answer "any symbol is 
> defined", so you get your use-case easily handled, but it also gives others 
> more flexibility.


There is a bit of misunderstanding on what this patch is doing, the patch is 
not about answering "any symbol is defined". See my cfe-dev email 
(http://lists.llvm.org/pipermail/cfe-dev/2017-June/054254.html) that provides 
some more context.
The patch is doing these 2 things:

- Keep track of whether a preprocessor directive condition used a symbol that 
was not resolved at all
- If above is true then make the preprocessor parse all directive blocks, not 
arbitrary choose one of them.

Here's an example to clarify the difference:

Say that you have this code:

  #if TARGET_IOS
  @interface A @end
  #else
  @interface B @end
  #endif



1. Without any changes this will happen:
  - TARGET_IOS is unresolved so it will be treated as `0`
  - `#if` block will be skipped, `#else` will be parsed
  - AST will contain `@interface B`

2. With adding a PPCallback that answers "any symbol is defined" (what you are 
proposing):
  - TARGET_IOS is undefined but the PPCallback sets it to `1`
  - `#if` block will be parsed, `#else` will be skipped
  - AST will contain `@interface A`

3. With this patch and enabling `SingleFileParseMode`
  - TARGET_IOS is unresolved
  - Both `#if` and `#else` blocks will be parsed
  - AST will contain both `@interface A` and `@interface B`

As you can see 2. and 3. above are not overlapping so they can "co-exist 
nicely" like this:

- TARGET_IOS is undefined, ask the PPCallback if it has a value for it or not
  - If the callback provides a value then parse as 1. or 2. depending on the 
value
  - If the callback cannot provide a specific value then parse as 3.


https://reviews.llvm.org/D34263



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D34263: [preprocessor] When preprocessor option 'SingleFileParseMode' is enabled, parse all directive blocks if the condition uses undefined macros

2017-06-19 Thread Argyrios Kyrtzidis via Phabricator via cfe-commits
akyrtzi added a comment.

In https://reviews.llvm.org/D34263#783694, @klimek wrote:

> how many patches for single file mode are coming down the road, though? I'm 
> somewhat concerned about the overall complexity it'll add to clang.


There is no other patch for using this preprocessor option. Any related 
improvements down the road will be about general improvements for error 
recovery, for example things like this:

- Introduce an `UnresolvedTypename` type instead of changing unresolved types 
to `int`.
- For `@interace A : B`, don't completely drop `B` from the super-class list of 
`A` if it is unresolved.

These kind of improvements are not conditional.


https://reviews.llvm.org/D34263



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D34263: [preprocessor] When preprocessor option 'SingleFileParseMode' is enabled, parse all directive blocks if the condition uses undefined macros

2017-06-19 Thread Vladimir Voskresensky via Phabricator via cfe-commits
voskresensky.vladimir added a comment.

In https://reviews.llvm.org/D34263#782391, @akyrtzi wrote:

> Hey Vladimir, what you are proposing is orthogonal to this patch. You are 
> proposing for "the client to provide the value for an undefined identifier", 
> and the patch is about the client not knowing what the value should be so it 
> fallbacks to parsing all tokens to get the max amount of info. Note that both 
> of the techniques can be combined well, if the client provides the value, the 
> preprocessor will take it into account, otherwise if it is stays unresolved 
> it will fallback to lexing all tokens.
>  But what you are proposing is not a replacement for what the patch is doing.


I'm not sure :-)

What I find problematic in this patch is PPOpts->SingleFileParseMode checks.
Let's suppose we implement what I mentioned above => how is it going to 
co-exist nicely? I think code will be less understandable with both: check of 
flag and call to PPCallbacks.
What I propose is to move the logic from the PPOpts single flag into 
PPCallbacks. And from check of flag to query of PPCallbacks.
Of course when you create PPCallbacks you can consult global 
SingleFileParseMode to create default implementation to answer "any symbol is 
defined", so you get your use-case easily handled, but it also gives others 
more flexibility.

Thanks,
Vladimir.


https://reviews.llvm.org/D34263



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D34263: [preprocessor] When preprocessor option 'SingleFileParseMode' is enabled, parse all directive blocks if the condition uses undefined macros

2017-06-19 Thread Manuel Klimek via Phabricator via cfe-commits
klimek added a comment.

Generally this patch lg from my side - how many patches for single file mode 
are coming down the road, though? I'm somewhat concerned about the overall 
complexity it'll add to clang.
When I saw your first patch my reaction was "wow, this works with this little 
change - cool".
With this patch it's "well, that doesn't seem to add too much complexity, so 
looks good".
I don't want to realize 5 patches down the line that we're sprinkling all of 
clang with single file conditional code without some discussion about the 
strategy with Richard.




Comment at: include/clang/Lex/Preprocessor.h:1838-1841
+  struct DirectiveEvalResult {
+bool Conditional;
+bool IncludedUndefinedIds;
+  };

A short comment on the struct what the semantics are would be helpful.


https://reviews.llvm.org/D34263



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D34263: [preprocessor] When preprocessor option 'SingleFileParseMode' is enabled, parse all directive blocks if the condition uses undefined macros

2017-06-16 Thread Argyrios Kyrtzidis via Phabricator via cfe-commits
akyrtzi updated this revision to Diff 102885.
akyrtzi added a comment.

Improving doc comment.


https://reviews.llvm.org/D34263

Files:
  include/clang/Lex/Preprocessor.h
  include/clang/Lex/PreprocessorOptions.h
  lib/Lex/PPDirectives.cpp
  lib/Lex/PPExpressions.cpp
  test/Index/singe-file-parse.m

Index: test/Index/singe-file-parse.m
===
--- test/Index/singe-file-parse.m
+++ test/Index/singe-file-parse.m
@@ -9,3 +9,103 @@
 // CHECK: [[@LINE+1]]:8: ObjCInstanceMethodDecl=some_meth
 -(void)some_meth;
 @end
+
+#if 1
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test1
+@interface Test1 @end
+#else
+// CHECK-NOT: [[@LINE+1]]:12:
+@interface Test2 @end
+#endif
+
+#if 0
+// CHECK-NOT: [[@LINE+1]]:12:
+@interface Test3 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test4
+@interface Test4 @end
+#endif
+
+#if SOMETHING_NOT_DEFINED
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test5
+@interface Test5 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test6
+@interface Test6 @end
+#endif
+
+#define SOMETHING_DEFINED 1
+#if SOMETHING_DEFINED
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test7
+@interface Test7 @end
+#else
+// CHECK-NOT: [[@LINE+1]]:12:
+@interface Test8 @end
+#endif
+
+#if defined(SOMETHING_NOT_DEFINED)
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test9
+@interface Test9 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test10
+@interface Test10 @end
+#endif
+
+#if defined(SOMETHING_DEFINED)
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test11
+@interface Test11 @end
+#else
+// CHECK-NOT: [[@LINE+1]]:12:
+@interface Test12 @end
+#endif
+
+#if SOMETHING_NOT_DEFINED1
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test13
+@interface Test13 @end
+#elif SOMETHING_NOT_DEFINED2
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test14
+@interface Test14 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test15
+@interface Test15 @end
+#endif
+
+#ifdef SOMETHING_NOT_DEFINED
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test19
+@interface Test19 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test20
+@interface Test20 @end
+#endif
+
+#ifdef SOMETHING_DEFINED
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test21
+@interface Test21 @end
+#else
+// CHECK-NOT: [[@LINE+1]]:12:
+@interface Test22 @end
+#endif
+
+#ifndef SOMETHING_NOT_DEFINED
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test23
+@interface Test23 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test24
+@interface Test24 @end
+#endif
+
+#ifndef SOMETHING_DEFINED
+// CHECK-NOT: [[@LINE+1]]:12:
+@interface Test25 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test26
+@interface Test26 @end
+#endif
+
+#if 1 < SOMETHING_NOT_DEFINED
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test27
+@interface Test27 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test28
+@interface Test28 @end
+#endif
Index: lib/Lex/PPExpressions.cpp
===
--- lib/Lex/PPExpressions.cpp
+++ lib/Lex/PPExpressions.cpp
@@ -73,6 +73,7 @@
 
 static bool EvaluateDirectiveSubExpr(PPValue , unsigned MinPrec,
  Token , bool ValueLive,
+ bool ,
  Preprocessor );
 
 /// DefinedTracker - This struct is used while parsing expressions to keep track
@@ -93,6 +94,7 @@
   /// TheMacro - When the state is DefinedMacro or NotDefinedMacro, this
   /// indicates the macro that was checked.
   IdentifierInfo *TheMacro;
+  bool IncludedUndefinedIds = false;
 };
 
 /// EvaluateDefined - Process a 'defined(sym)' expression.
@@ -128,6 +130,7 @@
   MacroDefinition Macro = PP.getMacroDefinition(II);
   Result.Val = !!Macro;
   Result.Val.setIsUnsigned(false); // Result is signed intmax_t.
+  DT.IncludedUndefinedIds = !Macro;
 
   // If there is a macro, mark it used.
   if (Result.Val != 0 && ValueLive)
@@ -255,6 +258,8 @@
 Result.Val.setIsUnsigned(false);  // "0" is signed intmax_t 0.
 Result.setIdentifier(II);
 Result.setRange(PeekTok.getLocation());
+DT.IncludedUndefinedIds = (II->getTokenID() != tok::kw_true &&
+   II->getTokenID() != tok::kw_false);
 PP.LexNonComment(PeekTok);
 return false;
   }
@@ -400,7 +405,8 @@
   // Just use DT unmodified as our result.
 } else {
   // Otherwise, we have something like (x+y), and we consumed '(x'.
-  if (EvaluateDirectiveSubExpr(Result, 1, PeekTok, ValueLive, PP))
+  if (EvaluateDirectiveSubExpr(Result, 1, PeekTok, ValueLive,
+   DT.IncludedUndefinedIds, PP))
 return true;
 
   if (PeekTok.isNot(tok::r_paren)) {
@@ -532,6 +538,7 @@
 /// evaluation, such as division by zero warnings.
 static bool EvaluateDirectiveSubExpr(PPValue , unsigned MinPrec,
  Token , bool ValueLive,
+ bool ,

[PATCH] D34263: [preprocessor] When preprocessor option 'SingleFileParseMode' is enabled, parse all directive blocks if the condition uses undefined macros

2017-06-16 Thread Ben Langmuir via Phabricator via cfe-commits
benlangmuir added a comment.

Thanks, this looks good to me.  I'd appreciate if @klimek could take a quick 
look though.




Comment at: include/clang/Lex/PreprocessorOptions.h:102
+  /// in preprocessor directive conditions it causes all blocks to be parsed so
+  /// that the client can get the max amount of info from the parser.
   bool SingleFileParseMode = false;

nitpick: should use the full words "maximum" and probably also "information" 
here


https://reviews.llvm.org/D34263



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D34263: [preprocessor] When preprocessor option 'SingleFileParseMode' is enabled, parse all directive blocks if the condition uses undefined macros

2017-06-16 Thread Argyrios Kyrtzidis via Phabricator via cfe-commits
akyrtzi updated this revision to Diff 102859.
akyrtzi added a comment.

Enhanced doc-comment for the preprocessor option, and fixed indentation on a 
couple of calls.


https://reviews.llvm.org/D34263

Files:
  include/clang/Lex/Preprocessor.h
  include/clang/Lex/PreprocessorOptions.h
  lib/Lex/PPDirectives.cpp
  lib/Lex/PPExpressions.cpp
  test/Index/singe-file-parse.m

Index: test/Index/singe-file-parse.m
===
--- test/Index/singe-file-parse.m
+++ test/Index/singe-file-parse.m
@@ -9,3 +9,103 @@
 // CHECK: [[@LINE+1]]:8: ObjCInstanceMethodDecl=some_meth
 -(void)some_meth;
 @end
+
+#if 1
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test1
+@interface Test1 @end
+#else
+// CHECK-NOT: [[@LINE+1]]:12:
+@interface Test2 @end
+#endif
+
+#if 0
+// CHECK-NOT: [[@LINE+1]]:12:
+@interface Test3 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test4
+@interface Test4 @end
+#endif
+
+#if SOMETHING_NOT_DEFINED
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test5
+@interface Test5 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test6
+@interface Test6 @end
+#endif
+
+#define SOMETHING_DEFINED 1
+#if SOMETHING_DEFINED
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test7
+@interface Test7 @end
+#else
+// CHECK-NOT: [[@LINE+1]]:12:
+@interface Test8 @end
+#endif
+
+#if defined(SOMETHING_NOT_DEFINED)
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test9
+@interface Test9 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test10
+@interface Test10 @end
+#endif
+
+#if defined(SOMETHING_DEFINED)
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test11
+@interface Test11 @end
+#else
+// CHECK-NOT: [[@LINE+1]]:12:
+@interface Test12 @end
+#endif
+
+#if SOMETHING_NOT_DEFINED1
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test13
+@interface Test13 @end
+#elif SOMETHING_NOT_DEFINED2
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test14
+@interface Test14 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test15
+@interface Test15 @end
+#endif
+
+#ifdef SOMETHING_NOT_DEFINED
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test19
+@interface Test19 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test20
+@interface Test20 @end
+#endif
+
+#ifdef SOMETHING_DEFINED
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test21
+@interface Test21 @end
+#else
+// CHECK-NOT: [[@LINE+1]]:12:
+@interface Test22 @end
+#endif
+
+#ifndef SOMETHING_NOT_DEFINED
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test23
+@interface Test23 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test24
+@interface Test24 @end
+#endif
+
+#ifndef SOMETHING_DEFINED
+// CHECK-NOT: [[@LINE+1]]:12:
+@interface Test25 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test26
+@interface Test26 @end
+#endif
+
+#if 1 < SOMETHING_NOT_DEFINED
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test27
+@interface Test27 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test28
+@interface Test28 @end
+#endif
Index: lib/Lex/PPExpressions.cpp
===
--- lib/Lex/PPExpressions.cpp
+++ lib/Lex/PPExpressions.cpp
@@ -73,6 +73,7 @@
 
 static bool EvaluateDirectiveSubExpr(PPValue , unsigned MinPrec,
  Token , bool ValueLive,
+ bool ,
  Preprocessor );
 
 /// DefinedTracker - This struct is used while parsing expressions to keep track
@@ -93,6 +94,7 @@
   /// TheMacro - When the state is DefinedMacro or NotDefinedMacro, this
   /// indicates the macro that was checked.
   IdentifierInfo *TheMacro;
+  bool IncludedUndefinedIds = false;
 };
 
 /// EvaluateDefined - Process a 'defined(sym)' expression.
@@ -128,6 +130,7 @@
   MacroDefinition Macro = PP.getMacroDefinition(II);
   Result.Val = !!Macro;
   Result.Val.setIsUnsigned(false); // Result is signed intmax_t.
+  DT.IncludedUndefinedIds = !Macro;
 
   // If there is a macro, mark it used.
   if (Result.Val != 0 && ValueLive)
@@ -255,6 +258,8 @@
 Result.Val.setIsUnsigned(false);  // "0" is signed intmax_t 0.
 Result.setIdentifier(II);
 Result.setRange(PeekTok.getLocation());
+DT.IncludedUndefinedIds = (II->getTokenID() != tok::kw_true &&
+   II->getTokenID() != tok::kw_false);
 PP.LexNonComment(PeekTok);
 return false;
   }
@@ -400,7 +405,8 @@
   // Just use DT unmodified as our result.
 } else {
   // Otherwise, we have something like (x+y), and we consumed '(x'.
-  if (EvaluateDirectiveSubExpr(Result, 1, PeekTok, ValueLive, PP))
+  if (EvaluateDirectiveSubExpr(Result, 1, PeekTok, ValueLive,
+   DT.IncludedUndefinedIds, PP))
 return true;
 
   if (PeekTok.isNot(tok::r_paren)) {
@@ -532,6 +538,7 @@
 /// evaluation, such as division by zero warnings.
 static bool EvaluateDirectiveSubExpr(PPValue , unsigned MinPrec,
  Token , bool 

[PATCH] D34263: [preprocessor] When preprocessor option 'SingleFileParseMode' is enabled, parse all directive blocks if the condition uses undefined macros

2017-06-16 Thread Ben Langmuir via Phabricator via cfe-commits
benlangmuir added inline comments.



Comment at: lib/Lex/PPDirectives.cpp:2774
+// the directive blocks.
+CurPPLexer->pushConditionalLevel(CI.IfLoc, /*wasskip*/false,
+   /*foundnonskip*/true, /*foundelse*/true);

akyrtzi wrote:
> benlangmuir wrote:
> > Why is wasSkipping false here?
> For `#if` it sets `wasskip` to `true` to indicate later for 
> `HandleElseDirective` that the block should not be skipped.
> But here (inside `HandleElseDirective`) setting `wasskip` doesn't really 
> affect anything, the `HandleEndifDirective` doesn't check it. I chose to set 
> it to `false` as indication that the `#else` block does get parsed.
Thanks for explaining. That makes sense to me.


https://reviews.llvm.org/D34263



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D34263: [preprocessor] When preprocessor option 'SingleFileParseMode' is enabled, parse all directive blocks if the condition uses undefined macros

2017-06-16 Thread Argyrios Kyrtzidis via Phabricator via cfe-commits
akyrtzi added inline comments.



Comment at: lib/Lex/PPDirectives.cpp:2774
+// the directive blocks.
+CurPPLexer->pushConditionalLevel(CI.IfLoc, /*wasskip*/false,
+   /*foundnonskip*/true, /*foundelse*/true);

benlangmuir wrote:
> Why is wasSkipping false here?
For `#if` it sets `wasskip` to `true` to indicate later for 
`HandleElseDirective` that the block should not be skipped.
But here (inside `HandleElseDirective`) setting `wasskip` doesn't really affect 
anything, the `HandleEndifDirective` doesn't check it. I chose to set it to 
`false` as indication that the `#else` block does get parsed.


https://reviews.llvm.org/D34263



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D34263: [preprocessor] When preprocessor option 'SingleFileParseMode' is enabled, parse all directive blocks if the condition uses undefined macros

2017-06-16 Thread Ben Langmuir via Phabricator via cfe-commits
benlangmuir added a comment.

It would be nice if the doc comment for the single file parse mode flag was 
updated to include this new functionality.




Comment at: lib/Lex/PPDirectives.cpp:2709
+CurPPLexer->pushConditionalLevel(IfToken.getLocation(), /*wasskip*/true,
+   /*foundnonskip*/false, /*foundelse*/false);
+  } else if (ConditionalTrue) {

Nitpick: this is misaligned.  Same with many other calls to 
pushConditionalLevel in this patch.



Comment at: lib/Lex/PPDirectives.cpp:2774
+// the directive blocks.
+CurPPLexer->pushConditionalLevel(CI.IfLoc, /*wasskip*/false,
+   /*foundnonskip*/true, /*foundelse*/true);

Why is wasSkipping false here?


https://reviews.llvm.org/D34263



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D34263: [preprocessor] When preprocessor option 'SingleFileParseMode' is enabled, parse all directive blocks if the condition uses undefined macros

2017-06-16 Thread Argyrios Kyrtzidis via Phabricator via cfe-commits
akyrtzi added a comment.

Hey Vladimir, what you are proposing is orthogonal to this patch. You are 
proposing for "the client to provide the value for an undefined identifier", 
and the patch is about the client not knowing what the value should be so it 
fallbacks to parsing all tokens to get the max amount of info. Note that both 
of the techniques can be combined well, if the client provides the value, the 
preprocessor will take it into account, otherwise if it is stays unresolved it 
will fallback to lexing all tokens.
But what you are proposing is not a replacement for what the patch is doing.


https://reviews.llvm.org/D34263



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D34263: [preprocessor] When preprocessor option 'SingleFileParseMode' is enabled, parse all directive blocks if the condition uses undefined macros

2017-06-16 Thread Vladimir Voskresensky via Phabricator via cfe-commits
voskresensky.vladimir added a comment.

Hello Argyrios,
This is a good addition to simplify reuse of preprocessor in IDEs. Thanks for 
doing this.

From our experience of integrating clang PP into NetBeans, the following change 
gives more flexibility:

- introduce method in PPCallbacks and consult it what is the preferred value 
for undefined symbol

It will be similar to approach used for unresolved includes and FileNotFound 
method.
It also gives dynamic behavior for clients:  client might still prefer to keep 
skipping some blocks like unix, mac, win, solaris, LP64, cplusplus, ...

Thanks,
Vladimir.


https://reviews.llvm.org/D34263



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D34263: [preprocessor] When preprocessor option 'SingleFileParseMode' is enabled, parse all directive blocks if the condition uses undefined macros

2017-06-15 Thread Argyrios Kyrtzidis via Phabricator via cfe-commits
akyrtzi created this revision.

This is useful for being able to parse the preprocessor directive blocks even 
the header that defined the macro that they check for hasn't been included.


https://reviews.llvm.org/D34263

Files:
  include/clang/Lex/Preprocessor.h
  lib/Lex/PPDirectives.cpp
  lib/Lex/PPExpressions.cpp
  test/Index/singe-file-parse.m

Index: test/Index/singe-file-parse.m
===
--- test/Index/singe-file-parse.m
+++ test/Index/singe-file-parse.m
@@ -9,3 +9,103 @@
 // CHECK: [[@LINE+1]]:8: ObjCInstanceMethodDecl=some_meth
 -(void)some_meth;
 @end
+
+#if 1
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test1
+@interface Test1 @end
+#else
+// CHECK-NOT: [[@LINE+1]]:12:
+@interface Test2 @end
+#endif
+
+#if 0
+// CHECK-NOT: [[@LINE+1]]:12:
+@interface Test3 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test4
+@interface Test4 @end
+#endif
+
+#if SOMETHING_NOT_DEFINED
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test5
+@interface Test5 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test6
+@interface Test6 @end
+#endif
+
+#define SOMETHING_DEFINED 1
+#if SOMETHING_DEFINED
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test7
+@interface Test7 @end
+#else
+// CHECK-NOT: [[@LINE+1]]:12:
+@interface Test8 @end
+#endif
+
+#if defined(SOMETHING_NOT_DEFINED)
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test9
+@interface Test9 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test10
+@interface Test10 @end
+#endif
+
+#if defined(SOMETHING_DEFINED)
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test11
+@interface Test11 @end
+#else
+// CHECK-NOT: [[@LINE+1]]:12:
+@interface Test12 @end
+#endif
+
+#if SOMETHING_NOT_DEFINED1
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test13
+@interface Test13 @end
+#elif SOMETHING_NOT_DEFINED2
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test14
+@interface Test14 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test15
+@interface Test15 @end
+#endif
+
+#ifdef SOMETHING_NOT_DEFINED
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test19
+@interface Test19 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test20
+@interface Test20 @end
+#endif
+
+#ifdef SOMETHING_DEFINED
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test21
+@interface Test21 @end
+#else
+// CHECK-NOT: [[@LINE+1]]:12:
+@interface Test22 @end
+#endif
+
+#ifndef SOMETHING_NOT_DEFINED
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test23
+@interface Test23 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test24
+@interface Test24 @end
+#endif
+
+#ifndef SOMETHING_DEFINED
+// CHECK-NOT: [[@LINE+1]]:12:
+@interface Test25 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test26
+@interface Test26 @end
+#endif
+
+#if 1 < SOMETHING_NOT_DEFINED
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test27
+@interface Test27 @end
+#else
+// CHECK: [[@LINE+1]]:12: ObjCInterfaceDecl=Test28
+@interface Test28 @end
+#endif
Index: lib/Lex/PPExpressions.cpp
===
--- lib/Lex/PPExpressions.cpp
+++ lib/Lex/PPExpressions.cpp
@@ -73,6 +73,7 @@
 
 static bool EvaluateDirectiveSubExpr(PPValue , unsigned MinPrec,
  Token , bool ValueLive,
+ bool ,
  Preprocessor );
 
 /// DefinedTracker - This struct is used while parsing expressions to keep track
@@ -93,6 +94,7 @@
   /// TheMacro - When the state is DefinedMacro or NotDefinedMacro, this
   /// indicates the macro that was checked.
   IdentifierInfo *TheMacro;
+  bool IncludedUndefinedIds = false;
 };
 
 /// EvaluateDefined - Process a 'defined(sym)' expression.
@@ -128,6 +130,7 @@
   MacroDefinition Macro = PP.getMacroDefinition(II);
   Result.Val = !!Macro;
   Result.Val.setIsUnsigned(false); // Result is signed intmax_t.
+  DT.IncludedUndefinedIds = !Macro;
 
   // If there is a macro, mark it used.
   if (Result.Val != 0 && ValueLive)
@@ -255,6 +258,8 @@
 Result.Val.setIsUnsigned(false);  // "0" is signed intmax_t 0.
 Result.setIdentifier(II);
 Result.setRange(PeekTok.getLocation());
+DT.IncludedUndefinedIds = (II->getTokenID() != tok::kw_true &&
+   II->getTokenID() != tok::kw_false);
 PP.LexNonComment(PeekTok);
 return false;
   }
@@ -400,7 +405,8 @@
   // Just use DT unmodified as our result.
 } else {
   // Otherwise, we have something like (x+y), and we consumed '(x'.
-  if (EvaluateDirectiveSubExpr(Result, 1, PeekTok, ValueLive, PP))
+  if (EvaluateDirectiveSubExpr(Result, 1, PeekTok, ValueLive,
+   DT.IncludedUndefinedIds, PP))
 return true;
 
   if (PeekTok.isNot(tok::r_paren)) {
@@ -532,6 +538,7 @@
 /// evaluation, such as division by zero warnings.
 static bool EvaluateDirectiveSubExpr(PPValue , unsigned MinPrec,
  Token , bool ValueLive,
+