arphaman updated this revision to Diff 95349.
arphaman added a comment.

Check if `IdentifierInfo` is nil in `ActOnIdExpression` to prevent crash.


Repository:
  rL LLVM

https://reviews.llvm.org/D32081

Files:
  include/clang/Basic/DiagnosticLexKinds.td
  include/clang/Basic/IdentifierTable.h
  include/clang/Basic/LangOptions.def
  include/clang/Driver/Options.td
  include/clang/Lex/Lexer.h
  include/clang/Lex/Token.h
  lib/Driver/ToolChains/Clang.cpp
  lib/Frontend/CompilerInvocation.cpp
  lib/Lex/Lexer.cpp
  lib/Parse/Parser.cpp
  lib/Sema/SemaCXXScopeSpec.cpp
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaExpr.cpp
  test/Driver/clang_f_opts.c
  test/Parser/editor-placeholder-recovery.cpp
  test/Parser/placeholder-recovery.m

Index: test/Parser/placeholder-recovery.m
===================================================================
--- test/Parser/placeholder-recovery.m
+++ test/Parser/placeholder-recovery.m
@@ -1,11 +1,14 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
 
+@protocol NSObject
+@end
+
+@protocol <#protocol name#> <NSObject> // expected-error {{editor placeholder in source file}}
+// expected-note@-1 {{protocol started here}}
+
 // FIXME: We could do much better with this, if we recognized
 // placeholders somehow. However, we're content with not generating
 // bogus 'archaic' warnings with bad location info.
-@protocol <#protocol name#> <NSObject> // expected-error {{expected identifier or '('}} \
-// expected-error 2{{expected identifier}} \
-// expected-warning{{protocol has no object type specified; defaults to qualified 'id'}}
-<#methods#>
+<#methods#> // expected-error {{editor placeholder in source file}}
 
-@end
+@end // expected-error {{prefix attribute must be followed by an interface or protocol}} expected-error {{missing '@end'}}
Index: test/Parser/editor-placeholder-recovery.cpp
===================================================================
--- /dev/null
+++ test/Parser/editor-placeholder-recovery.cpp
@@ -0,0 +1,71 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -fallow-editor-placeholders -DSUPPRESS -verify %s
+
+struct Struct {
+public:
+    void method(Struct &x);
+};
+
+struct <#struct name#> {
+  int <#field-name#>;
+#ifndef SUPPRESS
+  // expected-error@-3 {{editor placeholder in source file}}
+  // expected-error@-3 {{editor placeholder in source file}}
+#endif
+};
+
+typename <#typename#>::<#name#>;
+decltype(<#expression#>) foobar;
+typedef <#type#> <#name#>;
+#ifndef SUPPRESS
+  // expected-error@-4 2 {{editor placeholder in source file}}
+  // expected-error@-4 {{editor placeholder in source file}}
+  // expected-error@-4 2 {{editor placeholder in source file}}
+#endif
+
+namespace <#identifier#> {
+  <#declarations#>
+#ifndef SUPPRESS
+  // expected-error@-3 {{editor placeholder in source file}}
+  // expected-error@-3 {{editor placeholder in source file}}
+#endif
+
+}
+
+using <#qualifier#>::<#name#>;
+#ifndef SUPPRESS
+  // expected-error@-2 2 {{editor placeholder in source file}}
+#endif
+
+void avoidPlaceholderErrors(Struct &obj) {
+    static_cast< <#type#> >(<#expression#>);
+    while (<#condition#>) {
+        <#statements#>
+    }
+    obj.method(<#Struct &x#>);
+#ifndef SUPPRESS
+  // expected-error@-6 2 {{editor placeholder in source file}}
+  // expected-error@-6 {{editor placeholder in source file}}
+  // expected-error@-6 {{editor placeholder in source file}}
+  // expected-error@-5 {{editor placeholder in source file}}
+#endif
+    switch (<#expression#>) {
+        case <#constant#>:
+            <#statements#>
+#ifndef SUPPRESS
+  // expected-error@-4 {{editor placeholder in source file}}
+  // expected-error@-4 {{editor placeholder in source file}}
+  // expected-error@-4 {{editor placeholder in source file}}
+#endif
+            break;
+
+        default:
+            break;
+    }
+}
+
+void Struct::method(<#Struct &x#>, noSupressionHere) { // expected-error {{unknown type name 'noSupressionHere'}} expected-error {{C++ requires a type specifier for all declarations}}
+#ifndef SUPPRESS
+  // expected-error@-2 {{editor placeholder in source file}}
+#endif
+}
Index: test/Driver/clang_f_opts.c
===================================================================
--- test/Driver/clang_f_opts.c
+++ test/Driver/clang_f_opts.c
@@ -494,3 +494,8 @@
 // RUN: %clang -### -S -fdebug-info-for-profiling -fno-debug-info-for-profiling %s 2>&1 | FileCheck -check-prefix=CHECK-NO-PROFILE-DEBUG %s
 // CHECK-PROFILE-DEBUG: -fdebug-info-for-profiling
 // CHECK-NO-PROFILE-DEBUG-NOT: -fdebug-info-for-profiling
+
+// RUN: %clang -### -S -fallow-editor-placeholders %s 2>&1 | FileCheck -check-prefix=CHECK-ALLOW-PLACEHOLDERS %s
+// RUN: %clang -### -S -fno-allow-editor-placeholders %s 2>&1 | FileCheck -check-prefix=CHECK-NO-ALLOW-PLACEHOLDERS %s
+// CHECK-ALLOW-PLACEHOLDERS: -fallow-editor-placeholders
+// CHECK-NO-ALLOW-PLACEHOLDERS-NOT: -fallow-editor-placeholders
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -2126,6 +2126,12 @@
   IdentifierInfo *II = Name.getAsIdentifierInfo();
   SourceLocation NameLoc = NameInfo.getLoc();
 
+  if (II && II->isEditorPlaceholder()) {
+    // FIXME: When typed placeholders are supported we can create a typed
+    // placeholder expression node.
+    return ExprError();
+  }
+
   // C++ [temp.dep.expr]p3:
   //   An id-expression is type-dependent if it contains:
   //     -- an identifier that was declared with a dependent type,
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -628,6 +628,9 @@
                                    CXXScopeSpec *SS,
                                    ParsedType &SuggestedType,
                                    bool AllowClassTemplates) {
+  // Don't report typename errors for editor placeholders.
+  if (II->isEditorPlaceholder())
+    return;
   // We don't have anything to suggest (yet).
   SuggestedType = nullptr;
 
Index: lib/Sema/SemaCXXScopeSpec.cpp
===================================================================
--- lib/Sema/SemaCXXScopeSpec.cpp
+++ lib/Sema/SemaCXXScopeSpec.cpp
@@ -480,6 +480,8 @@
                                        bool ErrorRecoveryLookup,
                                        bool *IsCorrectedToColon,
                                        bool OnlyNamespace) {
+  if (IdInfo.Identifier->isEditorPlaceholder())
+    return true;
   LookupResult Found(*this, IdInfo.Identifier, IdInfo.IdentifierLoc,
                      OnlyNamespace ? LookupNamespaceName
                                    : LookupNestedNameSpecifierName);
Index: lib/Parse/Parser.cpp
===================================================================
--- lib/Parse/Parser.cpp
+++ lib/Parse/Parser.cpp
@@ -847,6 +847,10 @@
 
   default:
   dont_know:
+    if (Tok.isEditorPlaceholder()) {
+      ConsumeToken();
+      return nullptr;
+    }
     // We can't tell whether this is a function-definition or declaration yet.
     return ParseDeclarationOrFunctionDefinition(attrs, DS);
   }
@@ -1675,6 +1679,8 @@
           return false;
         }
       }
+      if (Tok.isEditorPlaceholder())
+        return true;
 
       Diag(Tok.getLocation(), diag::err_expected_qualified_after_typename);
       return true;
Index: lib/Lex/Lexer.cpp
===================================================================
--- lib/Lex/Lexer.cpp
+++ lib/Lex/Lexer.cpp
@@ -2722,6 +2722,37 @@
   return false;
 }
 
+static const char *findPlaceholderEnd(const char *CurPtr,
+                                      const char *BufferEnd) {
+  if (CurPtr == BufferEnd)
+    return nullptr;
+  BufferEnd -= 1; // Scan until the second last character.
+  for (; CurPtr != BufferEnd; ++CurPtr) {
+    if (CurPtr[0] == '#' && CurPtr[1] == '>')
+      return CurPtr + 2;
+  }
+  return nullptr;
+}
+
+bool Lexer::lexEditorPlaceholder(Token &Result, const char *CurPtr) {
+  assert(CurPtr[-1] == '<' && CurPtr[0] == '#' && "Not a placeholder!");
+  if (!PP || LexingRawMode)
+    return false;
+  const char *End = findPlaceholderEnd(CurPtr + 1, BufferEnd);
+  if (!End)
+    return false;
+  const char *Start = CurPtr - 1;
+  if (!LangOpts.AllowEditorPlaceholders)
+    Diag(Start, diag::err_placeholder_in_source);
+  Result.startToken();
+  FormTokenWithChars(Result, End, tok::raw_identifier);
+  Result.setRawIdentifierData(Start);
+  PP->LookUpIdentifierInfo(Result);
+  Result.setFlag(Token::IsEditorPlaceholder);
+  BufferPtr = End;
+  return true;
+}
+
 bool Lexer::isCodeCompletionPoint(const char *CurPtr) const {
   if (PP && PP->isCodeCompletionEnabled()) {
     SourceLocation Loc = FileLoc.getLocWithOffset(CurPtr-BufferStart);
@@ -3479,6 +3510,8 @@
     } else if (LangOpts.Digraphs && Char == '%') {     // '<%' -> '{'
       CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
       Kind = tok::l_brace;
+    } else if (Char == '#' && lexEditorPlaceholder(Result, CurPtr)) {
+      return true;
     } else {
       Kind = tok::less;
     }
Index: lib/Frontend/CompilerInvocation.cpp
===================================================================
--- lib/Frontend/CompilerInvocation.cpp
+++ lib/Frontend/CompilerInvocation.cpp
@@ -2329,6 +2329,9 @@
       Args.getAllArgValues(OPT_fxray_always_instrument);
   Opts.XRayNeverInstrumentFiles =
       Args.getAllArgValues(OPT_fxray_never_instrument);
+
+  // -fallow-editor-placeholders
+  Opts.AllowEditorPlaceholders = Args.hasArg(OPT_fallow_editor_placeholders);
 }
 
 static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
Index: lib/Driver/ToolChains/Clang.cpp
===================================================================
--- lib/Driver/ToolChains/Clang.cpp
+++ lib/Driver/ToolChains/Clang.cpp
@@ -2290,6 +2290,9 @@
   if (!Args.hasFlag(options::OPT_fstrict_return, options::OPT_fno_strict_return,
                     true))
     CmdArgs.push_back("-fno-strict-return");
+  if (Args.hasFlag(options::OPT_fallow_editor_placeholders,
+                   options::OPT_fno_allow_editor_placeholders, false))
+    CmdArgs.push_back("-fallow-editor-placeholders");
   if (Args.hasFlag(options::OPT_fstrict_vtable_pointers,
                    options::OPT_fno_strict_vtable_pointers,
                    false))
Index: include/clang/Lex/Token.h
===================================================================
--- include/clang/Lex/Token.h
+++ include/clang/Lex/Token.h
@@ -84,6 +84,7 @@
     StringifiedInMacro = 0x100, // This string or character literal is formed by
                                 // macro stringizing or charizing operator.
     CommaAfterElided = 0x200, // The comma following this token was elided (MS).
+    IsEditorPlaceholder = 0x400, // This identifier is a placeholder.
   };
 
   tok::TokenKind getKind() const { return Kind; }
@@ -298,6 +299,9 @@
 
   /// Returns true if the comma after this token was elided.
   bool commaAfterElided() const { return getFlag(CommaAfterElided); }
+
+  /// Returns true if this identifier token is an editor placeholder.
+  bool isEditorPlaceholder() const { return getFlag(IsEditorPlaceholder); }
 };
 
 /// \brief Information about the conditional stack (\#if directives)
Index: include/clang/Lex/Lexer.h
===================================================================
--- include/clang/Lex/Lexer.h
+++ include/clang/Lex/Lexer.h
@@ -638,6 +638,8 @@
   bool IsStartOfConflictMarker(const char *CurPtr);
   bool HandleEndOfConflictMarker(const char *CurPtr);
 
+  bool lexEditorPlaceholder(Token &Result, const char *CurPtr);
+
   bool isCodeCompletionPoint(const char *CurPtr) const;
   void cutOffLexing() { BufferPtr = BufferEnd; }
 
Index: include/clang/Driver/Options.td
===================================================================
--- include/clang/Driver/Options.td
+++ include/clang/Driver/Options.td
@@ -1470,6 +1470,13 @@
 def fno_strict_return : Flag<["-"], "fno-strict-return">, Group<f_Group>,
   Flags<[CC1Option]>;
 
+def fallow_editor_placeholders : Flag<["-"], "fallow-editor-placeholders">,
+  Group<f_Group>, Flags<[CC1Option]>,
+  HelpText<"Treat editor placeholders as valid source code">;
+def fno_allow_editor_placeholders : Flag<["-"],
+  "fno-allow-editor-placeholders">, Group<f_Group>,
+  Flags<[CC1Option]>;
+
 def fdebug_types_section: Flag <["-"], "fdebug-types-section">, Group<f_Group>,
   Flags<[CC1Option]>, HelpText<"Place debug types in their own section (ELF Only)">;
 def fno_debug_types_section: Flag<["-"], "fno-debug-types-section">, Group<f_Group>,
Index: include/clang/Basic/LangOptions.def
===================================================================
--- include/clang/Basic/LangOptions.def
+++ include/clang/Basic/LangOptions.def
@@ -265,6 +265,8 @@
 
 LANGOPT(XRayInstrument, 1, 0, "controls whether to do XRay instrumentation")
 
+LANGOPT(AllowEditorPlaceholders, 1, 0, "allow editor placeholders in source")
+
 #undef LANGOPT
 #undef COMPATIBLE_LANGOPT
 #undef BENIGN_LANGOPT
Index: include/clang/Basic/IdentifierTable.h
===================================================================
--- include/clang/Basic/IdentifierTable.h
+++ include/clang/Basic/IdentifierTable.h
@@ -355,6 +355,11 @@
       RecomputeNeedsHandleIdentifier();
   }
 
+  /// Return true if this identifier is an editor placeholder.
+  bool isEditorPlaceholder() const {
+    return getName().startswith("<#") && getName().endswith("#>");
+  }
+
   /// \brief Provide less than operator for lexicographical sorting.
   bool operator<(const IdentifierInfo &RHS) const {
     return getName() < RHS.getName();
Index: include/clang/Basic/DiagnosticLexKinds.td
===================================================================
--- include/clang/Basic/DiagnosticLexKinds.td
+++ include/clang/Basic/DiagnosticLexKinds.td
@@ -242,6 +242,7 @@
   "illegal character encoding in character literal">,
   InGroup<InvalidSourceEncoding>;
 def err_lexing_string : Error<"failure when lexing a string">;
+def err_placeholder_in_source : Error<"editor placeholder in source file">;
 
 
 //===----------------------------------------------------------------------===//
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to