mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-27 05:26:07 +00:00
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:
parent
cefc768f5b
commit
6e0d42c6f8
@ -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.
|
||||
|
@ -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];
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user