[cfe-commits] r38681 - in /cfe/cfe/trunk: Lex/Lexer.cpp Lex/MacroInfo.cpp Lex/Pragma.cpp Lex/Preprocessor.cpp include/clang/Basic/DiagnosticKinds.def include/clang/Lex/MacroInfo.h include/clang/Lex/Preprocessor.h

sabre at cs.uiuc.edu sabre at cs.uiuc.edu
Wed Jul 11 09:23:46 PDT 2007


Author: sabre
Date: Wed Jul 11 11:23:46 2007
New Revision: 38681

URL: http://llvm.org/viewvc/llvm-project?rev=38681&view=rev
Log:
Start reading/validating the argument list for a function-like macro.

Modified:
    cfe/cfe/trunk/Lex/Lexer.cpp
    cfe/cfe/trunk/Lex/MacroInfo.cpp
    cfe/cfe/trunk/Lex/Pragma.cpp
    cfe/cfe/trunk/Lex/Preprocessor.cpp
    cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def
    cfe/cfe/trunk/include/clang/Lex/MacroInfo.h
    cfe/cfe/trunk/include/clang/Lex/Preprocessor.h

Modified: cfe/cfe/trunk/Lex/Lexer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Lex/Lexer.cpp?rev=38681&r1=38680&r2=38681&view=diff

==============================================================================
--- cfe/cfe/trunk/Lex/Lexer.cpp (original)
+++ cfe/cfe/trunk/Lex/Lexer.cpp Wed Jul 11 11:23:46 2007
@@ -349,22 +349,13 @@
   // FIXME: UCNs.
   if (C != '\\' && C != '?' && (C != '$' || !Features.DollarIdents)) {
 FinishIdentifier:
-    const char *IdStart = BufferPtr, *IdEnd = CurPtr;
+    const char *IdStart = BufferPtr;
     FormTokenWithChars(Result, CurPtr);
     Result.SetKind(tok::identifier);
     
-    // Look up this token, see if it is a macro, or if it is a language keyword.
-    IdentifierInfo *II;
-    if (!Result.needsCleaning()) {
-      // No cleaning needed, just use the characters from the lexed buffer.
-      II = PP.getIdentifierInfo(IdStart, IdEnd);
-    } else {
-      // Cleaning needed, alloca a buffer, clean into it, then use the buffer.
-      const char *TmpBuf = (char*)alloca(Result.getLength());
-      unsigned Size = PP.getSpelling(Result, TmpBuf);
-      II = PP.getIdentifierInfo(TmpBuf, TmpBuf+Size);
-    }
-    Result.SetIdentifierInfo(II);
+    // Fill in Result.IdentifierInfo, looking up the identifier in the
+    // identifier table.
+    PP.LookUpIdentifierInfo(Result, IdStart);
     
     // Finally, now that we know we have an identifier, pass this off to the
     // preprocessor, which may macro expand it or something.

Modified: cfe/cfe/trunk/Lex/MacroInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Lex/MacroInfo.cpp?rev=38681&r1=38680&r2=38681&view=diff

==============================================================================
--- cfe/cfe/trunk/Lex/MacroInfo.cpp (original)
+++ cfe/cfe/trunk/Lex/MacroInfo.cpp Wed Jul 11 11:23:46 2007
@@ -17,14 +17,27 @@
 using namespace llvm;
 using namespace clang;
 
+MacroInfo::MacroInfo(SourceLocation DefLoc) : Location(DefLoc) {
+  IsFunctionLike = false;
+  IsC99Varargs = false;
+  IsGNUVarargs = false;
+  IsBuiltinMacro = false;
+  IsDisabled = false;
+  IsUsed = true;
+}
+
+
 /// isIdenticalTo - Return true if the specified macro definition is equal to
 /// this macro in spelling, arguments, and whitespace.  This is used to emit
 /// duplicate definition warnings.  This implements the rules in C99 6.10.3.
 bool MacroInfo::isIdenticalTo(const MacroInfo &Other, Preprocessor &PP) const {
-  // TODO: Check param count, variadic, function likeness.
+  // TODO: Check param count.
   
   // Check # tokens in replacement match.
-  if (ReplacementTokens.size() != Other.ReplacementTokens.size())
+  if (ReplacementTokens.size() != Other.ReplacementTokens.size() ||
+      isFunctionLike() != Other.isFunctionLike() ||
+      isC99Varargs() != Other.isC99Varargs() ||
+      isGNUVarargs() != Other.isGNUVarargs())
     return false;
   
   // Check all the tokens.

Modified: cfe/cfe/trunk/Lex/Pragma.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Lex/Pragma.cpp?rev=38681&r1=38680&r2=38681&view=diff

==============================================================================
--- cfe/cfe/trunk/Lex/Pragma.cpp (original)
+++ cfe/cfe/trunk/Lex/Pragma.cpp Wed Jul 11 11:23:46 2007
@@ -204,10 +204,9 @@
       return;
     }
     
-    // Look up the identifier info for the token.  Note that this can't use
-    // Tok.getIdentifierInfo() directly because we disabled identifier lookup.
-    std::string TokStr = getSpelling(Tok);
-    IdentifierInfo *II =getIdentifierInfo(&TokStr[0], &TokStr[0]+TokStr.size());
+    // Look up the identifier info for the token.  We disabled identifier lookup
+    // by saying we're skipping contents, so we need to do this manually.
+    IdentifierInfo *II = LookUpIdentifierInfo(Tok);
     
     // Already poisoned.
     if (II->isPoisoned()) continue;

Modified: cfe/cfe/trunk/Lex/Preprocessor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Lex/Preprocessor.cpp?rev=38681&r1=38680&r2=38681&view=diff

==============================================================================
--- cfe/cfe/trunk/Lex/Preprocessor.cpp (original)
+++ cfe/cfe/trunk/Lex/Preprocessor.cpp Wed Jul 11 11:23:46 2007
@@ -706,6 +706,29 @@
 // Lexer Event Handling.
 //===----------------------------------------------------------------------===//
 
+/// LookUpIdentifierInfo - Given a tok::identifier token, look up the
+/// identifier information for the token and install it into the token.
+IdentifierInfo *Preprocessor::LookUpIdentifierInfo(LexerToken &Identifier,
+                                                   const char *BufPtr) {
+  assert(Identifier.getKind() == tok::identifier && "Not an identifier!");
+  assert(Identifier.getIdentifierInfo() == 0 && "Identinfo already exists!");
+  
+  // Look up this token, see if it is a macro, or if it is a language keyword.
+  IdentifierInfo *II;
+  if (BufPtr && !Identifier.needsCleaning()) {
+    // No cleaning needed, just use the characters from the lexed buffer.
+    II = getIdentifierInfo(BufPtr, BufPtr+Identifier.getLength());
+  } else {
+    // Cleaning needed, alloca a buffer, clean into it, then use the buffer.
+    const char *TmpBuf = (char*)alloca(Identifier.getLength());
+    unsigned Size = getSpelling(Identifier, TmpBuf);
+    II = getIdentifierInfo(TmpBuf, TmpBuf+Size);
+  }
+  Identifier.SetIdentifierInfo(II);
+  return II;
+}
+
+
 /// HandleIdentifier - This callback is invoked when the lexer reads an
 /// identifier.  This callback looks up the identifier in the map and/or
 /// potentially macro expands it or turns it into a named token (like 'for').
@@ -1318,6 +1341,78 @@
 // Preprocessor Macro Directive Handling.
 //===----------------------------------------------------------------------===//
 
+/// ReadMacroDefinitionArgList - The ( starting an argument list of a macro
+/// definition has just been read.  Lex the rest of the arguments and the
+/// closing ), updating MI with what we learn.  Return true if an error occurs
+/// parsing the arg list.
+bool Preprocessor::ReadMacroDefinitionArgList(MacroInfo *MI) {
+  LexerToken Tok;
+  bool isFirst = true;
+  while (1) {
+    LexUnexpandedToken(Tok);
+    switch (Tok.getKind()) {
+    case tok::r_paren:
+      // Found the end of the argument list.
+      if (isFirst) return false;  // #define FOO()
+      // Otherwise we have #define FOO(A,)
+      Diag(Tok, diag::err_pp_expected_ident_in_arg_list);
+      return true;
+    case tok::ellipsis:  // #define X(... -> C99 varargs
+      // Warn if use of C99 feature in non-C99 mode.
+      if (!Features.C99) Diag(Tok, diag::ext_variadic_macro);
+
+      // Lex the token after the identifier.
+      LexUnexpandedToken(Tok);
+      if (Tok.getKind() != tok::r_paren) {
+        Diag(Tok, diag::err_pp_missing_rparen_in_macro_def);
+        return true;
+      }
+      MI->setIsC99Varargs();
+      return false;
+    case tok::eom:  // #define X(
+      Diag(Tok, diag::err_pp_missing_rparen_in_macro_def);
+      return true;
+    default:        // #define X(1
+      Diag(Tok, diag::err_pp_invalid_tok_in_arg_list);
+      return true;
+    case tok::identifier:
+      isFirst = false;
+      
+      // Fill in Result.IdentifierInfo, looking up the identifier in the
+      // identifier table.
+      IdentifierInfo *II = LookUpIdentifierInfo(Tok);
+      
+      assert(0 && "FIXME: lookup/add identifier, check for conflicts");
+      
+      // Lex the token after the identifier.
+      LexUnexpandedToken(Tok);
+      
+      switch (Tok.getKind()) {
+      default:          // #define X(A B
+        Diag(Tok, diag::err_pp_expected_comma_in_arg_list);
+        return true;
+      case tok::r_paren: // #define X(A)
+        return false;
+      case tok::comma:  // #define X(A,
+        break;
+      case tok::ellipsis:  // #define X(A... -> GCC extension
+        // Diagnose extension.
+        Diag(Tok, diag::ext_named_variadic_macro);
+        
+        // Lex the token after the identifier.
+        LexUnexpandedToken(Tok);
+        if (Tok.getKind() != tok::r_paren) {
+          Diag(Tok, diag::err_pp_missing_rparen_in_macro_def);
+          return true;
+        }
+          
+        MI->setIsGNUVarargs();
+        return false;
+      }
+    }
+  }
+}
+
 /// HandleDefineDirective - Implements #define.  This consumes the entire macro
 /// line then lets the caller lex the next real token.
 ///
@@ -1339,10 +1434,14 @@
   if (Tok.getKind() == tok::eom) {
     // If there is no body to this macro, we have no special handling here.
   } else if (Tok.getKind() == tok::l_paren && !Tok.hasLeadingSpace()) {
-    // This is a function-like macro definition.
-    //assert(0 && "Function-like macros not implemented!");
-    delete MI;
-    return DiscardUntilEndOfDirective();
+    // This is a function-like macro definition.  Read the argument list.
+    MI->setIsFunctionLike();
+    if (ReadMacroDefinitionArgList(MI)) {
+      delete MI;
+      if (CurLexer->ParsingPreprocessorDirective)
+        DiscardUntilEndOfDirective();
+      return;
+    }
 
   } else if (!Tok.hasLeadingSpace()) {
     // C99 requires whitespace between the macro definition and the body.  Emit

Modified: cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=38681&r1=38680&r2=38681&view=diff

==============================================================================
--- cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def Wed Jul 11 11:23:46 2007
@@ -119,6 +119,10 @@
      "\"%s\" macro redefined")
 DIAG(ext_pp_macro_redef2, EXTENSION,
      "this is previous definition")
+DIAG(ext_variadic_macro, EXTENSION,
+     "variadic macros were introduced in C99")
+DIAG(ext_named_variadic_macro, EXTENSION,
+     "named variadic macros are a GNU extension")
 
 DIAG(ext_pp_base_file, EXTENSION,
      "__BASE_FILE__ is a language extension")
@@ -143,6 +147,14 @@
      "macro names must be identifiers")
 DIAG(err_pp_missing_macro_name, ERROR,
      "macro name missing")
+DIAG(err_pp_missing_rparen_in_macro_def, ERROR,
+     "missing ')' in macro parameter list")
+DIAG(err_pp_invalid_tok_in_arg_list, ERROR,
+     "invalid token in macro parameter list")
+DIAG(err_pp_expected_ident_in_arg_list, ERROR,
+     "expected identifier in macro parameter list")
+DIAG(err_pp_expected_comma_in_arg_list, ERROR,
+     "expected comma in macro parameter list")
 DIAG(err_pp_malformed_ident, ERROR,
      "invalid #ident directive")
 DIAG(err_pp_unterminated_conditional, ERROR,

Modified: cfe/cfe/trunk/include/clang/Lex/MacroInfo.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/Lex/MacroInfo.h?rev=38681&r1=38680&r2=38681&view=diff

==============================================================================
--- cfe/cfe/trunk/include/clang/Lex/MacroInfo.h (original)
+++ cfe/cfe/trunk/include/clang/Lex/MacroInfo.h Wed Jul 11 11:23:46 2007
@@ -24,6 +24,9 @@
 /// MacroInfo - Each identifier that is #define'd has an instance of this class
 /// associated with it, used to implement macro expansion.
 class MacroInfo {
+  //===--------------------------------------------------------------------===//
+  // State set when the macro is defined.
+
   /// Location - This is the place the macro is defined.
   SourceLocation Location;
 
@@ -33,26 +36,40 @@
   /// ReplacementTokens - This is the list of tokens that the macro is defined
   /// to.
   std::vector<LexerToken> ReplacementTokens;
+
+  /// IsFunctionLike - True if this macro is a function-like macro, false if it
+  /// is an object-like macro.
+  bool IsFunctionLike : 1;
+  
+  /// IsC99Varargs - True if this macro is of the form "#define X(...)" or
+  /// "#define X(Y,Z,...)".  The __VA_ARGS__ token should be replaced with the
+  /// contents of "..." in an invocation.
+  bool IsC99Varargs : 1;
+  
+  /// IsGNUVarargs -  True if this macro is of the form "#define X(a...)".  The
+  /// "a" identifier in th replacement list will be replaced with all arguments
+  /// of the macro starting with the specified one.
+  bool IsGNUVarargs : 1;
   
+  /// IsBuiltinMacro - True if this is a builtin macro, such as __LINE__, and if
+  /// it has not yet been redefined or undefined.
+  bool IsBuiltinMacro : 1;
+  
+private:
+  //===--------------------------------------------------------------------===//
+  // State that changes as the macro is used.
+
   /// IsDisabled - True if we have started an expansion of this macro already.
   /// This disbles recursive expansion, which would be quite bad for things like
   /// #define A A.
   bool IsDisabled : 1;
   
-  /// IsBuiltinMacro - True if this is a builtin macro, such as __LINE__, and if
-  /// it has not yet been redefined or undefined.
-  bool IsBuiltinMacro : 1;
-  
   /// IsUsed - True if this macro is either defined in the main file and has
   /// been used, or if it is not defined in the main file.  This is used to 
   /// emit -Wunused-macros diagnostics.
   bool IsUsed : 1;
 public:
-  MacroInfo(SourceLocation DefLoc) : Location(DefLoc) {
-    IsDisabled = false;
-    IsBuiltinMacro = false;
-    IsUsed = true;
-  }
+  MacroInfo(SourceLocation DefLoc);
   
   /// getDefinitionLoc - Return the location that the macro was defined at.
   ///
@@ -75,6 +92,18 @@
     IsUsed = Val;
   }
   
+  /// Function/Object-likeness.  Keep track of whether this macro has formal
+  /// parameters.
+  void setIsFunctionLike() { IsFunctionLike = true; }
+  bool isFunctionLike() const { return IsFunctionLike; }
+  bool isObjectLike() const { return !IsFunctionLike; }
+  
+  /// Varargs querying methods.  This can only be set for function-like macros.
+  void setIsC99Varargs() { IsC99Varargs = true; }
+  void setIsGNUVarargs() { IsGNUVarargs = true; }
+  bool isC99Varargs() const { return IsC99Varargs; }
+  bool isGNUVarargs() const { return IsGNUVarargs; }
+  
   /// isBuiltinMacro - Return true if this macro is a builtin macro, such as
   /// __LINE__, which requires processing before expansion.
   bool isBuiltinMacro() const { return IsBuiltinMacro; }

Modified: cfe/cfe/trunk/include/clang/Lex/Preprocessor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/Lex/Preprocessor.h?rev=38681&r1=38680&r2=38681&view=diff

==============================================================================
--- cfe/cfe/trunk/include/clang/Lex/Preprocessor.h (original)
+++ cfe/cfe/trunk/include/clang/Lex/Preprocessor.h Wed Jul 11 11:23:46 2007
@@ -384,6 +384,11 @@
   // Preprocessor callback methods.  These are invoked by a lexer as various
   // directives and events are found.
 
+  /// LookUpIdentifierInfo - Given a tok::identifier token, look up the
+  /// identifier information for the token and install it into the token.
+  IdentifierInfo *LookUpIdentifierInfo(LexerToken &Identifier,
+                                       const char *BufPtr = 0);
+  
   /// HandleIdentifier - This callback is invoked when the lexer reads an
   /// identifier and has filled in the tokens IdentifierInfo member.  This
   /// callback potentially macro expands it or turns it into a named token (like
@@ -423,6 +428,12 @@
   /// and discards the rest of the macro line if the macro name is invalid.
   void ReadMacroName(LexerToken &MacroNameTok, char isDefineUndef = 0);
   
+  /// ReadMacroDefinitionArgList - The ( starting an argument list of a macro
+  /// definition has just been read.  Lex the rest of the arguments and the
+  /// closing ), updating MI with what we learn.  Return true if an error occurs
+  /// parsing the arg list.
+  bool ReadMacroDefinitionArgList(MacroInfo *MI);
+  
   /// SkipExcludedConditionalBlock - We just read a #if or related directive and
   /// decided that the subsequent tokens are in the #if'd out portion of the
   /// file.  Lex the rest of the file, until we see an #endif.  If





More information about the cfe-commits mailing list