Add identifiers for macro arguments to MacroInfo, check for duplicates,

enhance macro equality testing to verify argument lists match.

llvm-svn: 38682
This commit is contained in:
Chris Lattner 2006-07-08 20:32:52 +00:00
parent cefc768f5b
commit 6e0d42c6f8
6 changed files with 73 additions and 16 deletions

View File

@ -199,6 +199,7 @@ IdentifierInfo &IdentifierTable::get(const char *NameStart,
Identifier->TokInfo.TokenID = tok::identifier;
Identifier->TokInfo.IsExtension = false;
Identifier->TokInfo.IsPoisoned = false;
Identifier->TokInfo.IsMacroArg = false;
Identifier->TokInfo.FETokenInfo = 0;
// Copy the string information.

View File

@ -26,20 +26,30 @@ MacroInfo::MacroInfo(SourceLocation DefLoc) : Location(DefLoc) {
IsUsed = true;
}
/// SetIdentifierIsMacroArgFlags - Set or clear the "isMacroArg" flags on the
/// identifiers that make up the argument list for this macro.
void MacroInfo::SetIdentifierIsMacroArgFlags(bool Val) const {
for (arg_iterator I = arg_begin(), E = arg_end(); I != E; ++I)
(*I)->setIsMacroArg(Val);
}
/// 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.
// Check # tokens in replacement match.
// Check # tokens in replacement, number of args, and various flags all match.
if (ReplacementTokens.size() != Other.ReplacementTokens.size() ||
Arguments.size() != Other.Arguments.size() ||
isFunctionLike() != Other.isFunctionLike() ||
isC99Varargs() != Other.isC99Varargs() ||
isGNUVarargs() != Other.isGNUVarargs())
return false;
// Check arguments.
for (arg_iterator I = arg_begin(), OI = Other.arg_begin(), E = arg_end();
I != E; ++I, ++OI)
if (*I != *OI) return false;
// Check all the tokens.
for (unsigned i = 0, e = ReplacementTokens.size(); i != e; ++i) {
const LexerToken &A = ReplacementTokens[i];

View File

@ -1347,13 +1347,12 @@ void Preprocessor::HandleImportDirective(LexerToken &ImportTok) {
/// 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()
if (MI->arg_begin() == MI->arg_end()) return false; // #define FOO()
// Otherwise we have #define FOO(A,)
Diag(Tok, diag::err_pp_expected_ident_in_arg_list);
return true;
@ -1376,13 +1375,19 @@ bool Preprocessor::ReadMacroDefinitionArgList(MacroInfo *MI) {
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");
IdentifierInfo *II = Tok.getIdentifierInfo();
// If this is already used as an argument, it is used multiple times (e.g.
// #define X(A,A.
if (II->isMacroArg()) { // C99 6.10.3p6
Diag(Tok, diag::err_pp_duplicate_name_in_arg_list, II->getName());
return true;
}
// Add the argument to the macro info.
MI->addArgument(II);
// Remember it is an argument now.
II->setIsMacroArg(true);
// Lex the token after the identifier.
LexUnexpandedToken(Tok);
@ -1431,13 +1436,20 @@ void Preprocessor::HandleDefineDirective(LexerToken &DefineTok) {
LexerToken Tok;
LexUnexpandedToken(Tok);
// If this is a function-like macro definition, parse the argument list,
// marking each of the identifiers as being used as macro arguments. Also,
// check other constraints on the first token of the macro body.
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. Read the argument list.
MI->setIsFunctionLike();
if (ReadMacroDefinitionArgList(MI)) {
// Clear the "isMacroArg" flags from all the macro arguments parsed.
MI->SetIdentifierIsMacroArgFlags(false);
// Forget about MI.
delete MI;
// Throw away the rest of the line.
if (CurLexer->ParsingPreprocessorDirective)
DiscardUntilEndOfDirective();
return;
@ -1476,11 +1488,15 @@ void Preprocessor::HandleDefineDirective(LexerToken &DefineTok) {
if (NumTokens != 0) {
if (MI->getReplacementToken(0).getKind() == tok::hashhash) {
SourceLocation Loc = MI->getReplacementToken(0).getLocation();
// Clear the "isMacroArg" flags from all the macro arguments.
MI->SetIdentifierIsMacroArgFlags(false);
delete MI;
return Diag(Loc, diag::err_paste_at_start);
}
if (MI->getReplacementToken(NumTokens-1).getKind() == tok::hashhash) {
SourceLocation Loc = MI->getReplacementToken(NumTokens-1).getLocation();
// Clear the "isMacroArg" flags from all the macro arguments.
MI->SetIdentifierIsMacroArgFlags(false);
delete MI;
return Diag(Loc, diag::err_paste_at_end);
}
@ -1509,6 +1525,9 @@ void Preprocessor::HandleDefineDirective(LexerToken &DefineTok) {
}
MacroNameTok.getIdentifierInfo()->setMacroInfo(MI);
// Clear the "isMacroArg" flags from all the macro arguments.
MI->SetIdentifierIsMacroArgFlags(false);
}

View File

@ -155,6 +155,8 @@ 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_duplicate_name_in_arg_list, ERROR,
"duplicate macro parameter name \"%s\"")
DIAG(err_pp_malformed_ident, ERROR,
"invalid #ident directive")
DIAG(err_pp_unterminated_conditional, ERROR,

View File

@ -34,6 +34,7 @@ class IdentifierInfo {
tok::TokenKind TokenID:8; // Front-end token ID or tok::identifier.
bool IsExtension : 1; // True if this identifier is a language extension.
bool IsPoisoned : 1; // True if this identifier is poisoned.
bool IsMacroArg : 1; // True if currently used as a macro argument.
void *FETokenInfo; // Managed by the language front-end.
friend class IdentifierTable;
public:
@ -76,6 +77,12 @@ public:
/// isPoisoned - Return true if this token has been poisoned.
bool isPoisoned() const { return IsPoisoned; }
/// IsMacroArg accessors - These indicate if the identifier is currently in
/// use as a macro argument identifier. This is a transient property only
/// used during macro definition and expansion.
bool isMacroArg() const { return IsMacroArg; }
void setIsMacroArg(bool Val) { IsMacroArg = Val; }
/// getFETokenInfo/setFETokenInfo - The language front-end is allowed to
/// associate arbitrary metadata with this token.
template<typename T>

View File

@ -14,7 +14,7 @@
#ifndef LLVM_CLANG_MACROINFO_H
#define LLVM_CLANG_MACROINFO_H
#include "clang/Lex/Lexer.h"
#include "clang/Lex/LexerToken.h"
#include <vector>
namespace llvm {
@ -30,8 +30,9 @@ class MacroInfo {
/// Location - This is the place the macro is defined.
SourceLocation Location;
// TODO: Parameter list
// TODO: # parameters
/// Arguments - The list of arguments for a function-like macro. This can be
/// empty, for, e.g. "#define X()".
std::vector<IdentifierInfo*> Arguments;
/// ReplacementTokens - This is the list of tokens that the macro is defined
/// to.
@ -91,6 +92,19 @@ public:
void setIsUsed(bool Val) {
IsUsed = Val;
}
/// addArgument - Add an argument to the list of formal arguments for this
/// function-like macro.
void addArgument(IdentifierInfo *Arg) {
Arguments.push_back(Arg);
}
/// Arguments - The list of arguments for a function-like macro. This can be
/// empty, for, e.g. "#define X()".
typedef std::vector<IdentifierInfo*>::const_iterator arg_iterator;
arg_iterator arg_begin() const { return Arguments.begin(); }
arg_iterator arg_end() const { return Arguments.end(); }
/// Function/Object-likeness. Keep track of whether this macro has formal
/// parameters.
@ -142,6 +156,10 @@ public:
assert(!IsDisabled && "Cannot disable an already-disabled macro!");
IsDisabled = true;
}
/// SetIdentifierIsMacroArgFlags - Set or clear the "isMacroArg" flags on the
/// identifiers that make up the argument list for this macro.
void SetIdentifierIsMacroArgFlags(bool Val) const;
};
} // end namespace llvm