]> granicus.if.org Git - clang/commitdiff
parse and enforce required constraints on #line directives. Right now
authorChris Lattner <sabre@nondot.org>
Mon, 26 Jan 2009 05:29:08 +0000 (05:29 +0000)
committerChris Lattner <sabre@nondot.org>
Mon, 26 Jan 2009 05:29:08 +0000 (05:29 +0000)
we just discard them.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@62999 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticKinds.def
include/clang/Lex/Preprocessor.h
lib/Lex/PPDirectives.cpp
test/Preprocessor/line-directive.c [new file with mode: 0644]

index e9dbad94b676e5681a91f9e2530d709a3e4d5d64..09b24ad818419fc6baaadefb456664226691f5e5 100644 (file)
@@ -200,6 +200,13 @@ DIAG(err_pp_duplicate_name_in_arg_list, ERROR,
      "duplicate macro parameter name %0")
 DIAG(err_pp_stringize_not_parameter, ERROR,
      "'#' is not followed by a macro parameter")
+DIAG(err_pp_line_requires_integer, ERROR,
+     "#line directive requires a positive integer argument")
+DIAG(err_pp_line_invalid_filename, ERROR,
+     "invalid filename for #line directive")
+DIAG(ext_pp_line_too_big, EXTENSION,
+     "C requires #line number to be less than %0, allowed as extension")
+     
 DIAG(err_pp_malformed_ident, ERROR,
      "invalid #ident directive")
 DIAG(err_pp_unterminated_conditional, ERROR,
index 2954c676e8db67f317d3e42112b05ad1954580cf..8081759e9655733d3a6e02bf619867d58ce068db 100644 (file)
@@ -691,6 +691,7 @@ private:
   /// should side-effect the current preprocessor object so that the next call
   /// to Lex() will return the appropriate token next.
   
+  void HandleLineDirective(Token &Tok);
   void HandleUserDiagnosticDirective(Token &Tok, bool isWarning);
   void HandleIdentSCCSDirective(Token &Tok);
   
index ec5b67fb788e49bc58e9914788a904402dc2cdc1..4ab293b9b72469f22d9c6adb7947425d74076ec7 100644 (file)
 //===----------------------------------------------------------------------===//
 
 #include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/LiteralSupport.h"
 #include "clang/Lex/HeaderSearch.h"
 #include "clang/Lex/MacroInfo.h"
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/APInt.h"
 using namespace clang;
 
 //===----------------------------------------------------------------------===//
@@ -478,8 +480,7 @@ TryAgain:
 
   case tok::numeric_constant:
     // FIXME: implement # 7 line numbers!
-    DiscardUntilEndOfDirective();
-    return;
+    return DiscardUntilEndOfDirective();
   default:
     IdentifierInfo *II = Result.getIdentifierInfo();
     if (II == 0) break;  // Not an identifier.
@@ -513,9 +514,7 @@ TryAgain:
 
     // C99 6.10.4 - Line Control.
     case tok::pp_line:
-      // FIXME: implement #line
-      DiscardUntilEndOfDirective();
-      return;
+      return HandleLineDirective(Result);
       
     // C99 6.10.5 - Error Directive.
     case tok::pp_error:
@@ -557,22 +556,95 @@ TryAgain:
   // Okay, we're done parsing the directive.
 }
 
+/// HandleLineDirective - Handle #line directive: C99 6.10.4.  The two 
+/// acceptable forms are:
+///   # line digit-sequence
+///   # line digit-sequence "s-char-sequence"
+void Preprocessor::HandleLineDirective(Token &Tok) {
+  // Read the line # and string argument.  Per C99 6.10.4p5, these tokens are
+  // expanded.
+  Token DigitTok;
+  Lex(DigitTok);
+
+  // Verify that we get a number.
+  if (DigitTok.isNot(tok::numeric_constant)) {
+    Diag(DigitTok, diag::err_pp_line_requires_integer);
+    if (DigitTok.isNot(tok::eom))
+      DiscardUntilEndOfDirective();
+    return;
+  }
+  
+  // Validate the number and convert it to an unsigned.
+  llvm::SmallString<64> IntegerBuffer;
+  IntegerBuffer.resize(DigitTok.getLength());
+  const char *DigitTokBegin = &IntegerBuffer[0];
+  unsigned ActualLength = getSpelling(DigitTok, DigitTokBegin);
+  NumericLiteralParser Literal(DigitTokBegin, DigitTokBegin+ActualLength, 
+                               DigitTok.getLocation(), *this);
+  if (Literal.hadError)
+    return DiscardUntilEndOfDirective();  // a diagnostic was already reported.
+  
+  if (Literal.isFloatingLiteral() || Literal.isImaginary) {
+    Diag(DigitTok, diag::err_pp_line_requires_integer);
+    return;
+  }
+  
+  // Parse the integer literal into Result.
+  llvm::APInt Val(32, 0);
+  if (Literal.GetIntegerValue(Val)) {
+    // Overflow parsing integer literal.
+    Diag(DigitTok, diag::err_pp_line_requires_integer);
+    return DiscardUntilEndOfDirective();
+  }
+
+  // Enforce C99 6.10.4p3: The digit sequence shall not specify zero, nor a
+  // number greater than 2147483647. 
+  unsigned LineNo = Val.getZExtValue();
+  if (LineNo == 0) {
+    Diag(DigitTok, diag::err_pp_line_requires_integer);
+    return DiscardUntilEndOfDirective();
+  }
+  
+  // C90 requires that the line # be less than 32767, and C99 ups the limit.
+  unsigned LineLimit = Features.C99 ? 2147483648U : 32768U;
+  if (LineNo >= LineLimit)
+    Diag(DigitTok, diag::ext_pp_line_too_big) << LineLimit;
+  
+  Token StrTok;
+  Lex(StrTok);
+
+  // If the StrTok is "eom", then it wasn't present.  Otherwise, it must be a
+  // string followed by eom.
+  if (StrTok.is(tok::eom)) 
+    ; // ok
+  else if (StrTok.isNot(tok::string_literal)) {
+    Diag(StrTok, diag::err_pp_line_invalid_filename);
+    DiscardUntilEndOfDirective();
+    return;
+  } else {
+    // Verify that there is nothing after the string, other than EOM.
+    CheckEndOfDirective("#line");
+  }
+  
+  // FIXME: do something with the #line info.
+}
+
+
 void Preprocessor::HandleUserDiagnosticDirective(Token &Tok, 
                                                  bool isWarning) {
+  if (!CurLexer)
+    return CurPTHLexer->DiscardToEndOfLine();
+
   // Read the rest of the line raw.  We do this because we don't want macros
   // to be expanded and we don't require that the tokens be valid preprocessing
   // tokens.  For example, this is allowed: "#warning `   'foo".  GCC does
   // collapse multiple consequtive white space between tokens, but this isn't
   // specified by the standard.
-  
-  if (CurLexer) {
-    std::string Message = CurLexer->ReadToEndOfLine();
-    unsigned DiagID = isWarning ? diag::pp_hash_warning : diag::err_pp_hash_error;
-    Diag(Tok, DiagID) << Message;
-  }
-  else {
-    CurPTHLexer->DiscardToEndOfLine();
-  }    
+  std::string Message = CurLexer->ReadToEndOfLine();
+  if (isWarning)
+    Diag(Tok, diag::pp_hash_warning) << Message;
+  else
+    Diag(Tok, diag::err_pp_hash_error) << Message;
 }
 
 /// HandleIdentSCCSDirective - Handle a #ident/#sccs directive.
diff --git a/test/Preprocessor/line-directive.c b/test/Preprocessor/line-directive.c
new file mode 100644 (file)
index 0000000..9b79506
--- /dev/null
@@ -0,0 +1,10 @@
+// RUN: clang -fsyntax-only -verify -pedantic %s
+
+#line 'a'            // expected-error {{#line directive requires a positive integer argument}}
+#line 0              // expected-error {{#line directive requires a positive integer argument}}
+#line 2147483648     // expected-warning {{C requires #line number to be less than 2147483648, allowed as extension}}
+#line 42             // ok
+#line 42 'a'         // expected-error {{nvalid filename for #line directive}}
+#line 42 "foo/bar/baz.h"  // ok
+
+