Improve diagnostic for the case when a non-defined function-like macro is used

in a preprocessor constant expression.

llvm-svn: 266495
This commit is contained in:
Richard Smith 2016-04-16 00:07:09 +00:00
parent 60469e2ac0
commit 4d247e7012
4 changed files with 45 additions and 8 deletions

View File

@ -409,6 +409,8 @@ def err_pp_remainder_by_zero : Error<
"remainder by zero in preprocessor expression">;
def err_pp_expr_bad_token_binop : Error<
"token is not a valid binary operator in a preprocessor subexpression">;
def err_pp_expr_bad_token_lparen : Error<
"function-like macro %0 is not defined">;
def err_pp_expr_bad_token_start_expr : Error<
"invalid token at start of a preprocessor expression">;
def err_pp_invalid_poison : Error<"can only poison identifier tokens">;

View File

@ -33,12 +33,18 @@ namespace {
/// conditional and the source range covered by it.
class PPValue {
SourceRange Range;
IdentifierInfo *II;
public:
llvm::APSInt Val;
// Default ctor - Construct an 'invalid' PPValue.
PPValue(unsigned BitWidth) : Val(BitWidth) {}
// If this value was produced by directly evaluating an identifier, produce
// that identifier.
IdentifierInfo *getIdentifier() const { return II; }
void setIdentifier(IdentifierInfo *II) { this->II = II; }
unsigned getBitWidth() const { return Val.getBitWidth(); }
bool isUnsigned() const { return Val.isUnsigned(); }
@ -209,6 +215,8 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
bool ValueLive, Preprocessor &PP) {
DT.State = DefinedTracker::Unknown;
Result.setIdentifier(nullptr);
if (PeekTok.is(tok::code_completion)) {
if (PP.getCodeCompletionHandler())
PP.getCodeCompletionHandler()->CodeCompletePreprocessorExpression();
@ -234,6 +242,7 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
PP.Diag(PeekTok, diag::warn_pp_undef_identifier) << II;
Result.Val = II->getTokenID() == tok::kw_true;
Result.Val.setIsUnsigned(false); // "0" is signed intmax_t 0.
Result.setIdentifier(II);
Result.setRange(PeekTok.getLocation());
PP.LexNonComment(PeekTok);
return false;
@ -392,6 +401,7 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
DT.State = DefinedTracker::Unknown;
}
Result.setRange(Start, PeekTok.getLocation());
Result.setIdentifier(nullptr);
PP.LexNonComment(PeekTok); // Eat the ).
return false;
}
@ -401,6 +411,7 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
PP.LexNonComment(PeekTok);
if (EvaluateValue(Result, PeekTok, DT, ValueLive, PP)) return true;
Result.setBegin(Start);
Result.setIdentifier(nullptr);
return false;
}
case tok::minus: {
@ -408,6 +419,7 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
PP.LexNonComment(PeekTok);
if (EvaluateValue(Result, PeekTok, DT, ValueLive, PP)) return true;
Result.setBegin(Loc);
Result.setIdentifier(nullptr);
// C99 6.5.3.3p3: The sign of the result matches the sign of the operand.
Result.Val = -Result.Val;
@ -428,6 +440,7 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
PP.LexNonComment(PeekTok);
if (EvaluateValue(Result, PeekTok, DT, ValueLive, PP)) return true;
Result.setBegin(Start);
Result.setIdentifier(nullptr);
// C99 6.5.3.3p4: The sign of the result matches the sign of the operand.
Result.Val = ~Result.Val;
@ -443,6 +456,7 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
Result.Val = !Result.Val;
// C99 6.5.3.3p5: The sign of the result is 'int', aka it is signed.
Result.Val.setIsUnsigned(false);
Result.setIdentifier(nullptr);
if (DT.State == DefinedTracker::DefinedMacro)
DT.State = DefinedTracker::NotDefinedMacro;
@ -491,6 +505,15 @@ static unsigned getPrecedence(tok::TokenKind Kind) {
}
}
static void diagnoseUnexpectedOperator(Preprocessor &PP, PPValue &LHS,
Token &Tok) {
if (Tok.is(tok::l_paren) && LHS.getIdentifier())
PP.Diag(LHS.getRange().getBegin(), diag::err_pp_expr_bad_token_lparen)
<< LHS.getIdentifier();
else
PP.Diag(Tok.getLocation(), diag::err_pp_expr_bad_token_binop)
<< LHS.getRange();
}
/// EvaluateDirectiveSubExpr - Evaluate the subexpression whose first token is
/// PeekTok, and whose precedence is PeekPrec. This returns the result in LHS.
@ -504,8 +527,7 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec,
unsigned PeekPrec = getPrecedence(PeekTok.getKind());
// If this token isn't valid, report the error.
if (PeekPrec == ~0U) {
PP.Diag(PeekTok.getLocation(), diag::err_pp_expr_bad_token_binop)
<< LHS.getRange();
diagnoseUnexpectedOperator(PP, LHS, PeekTok);
return true;
}
@ -548,8 +570,7 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec,
// If this token isn't valid, report the error.
if (PeekPrec == ~0U) {
PP.Diag(PeekTok.getLocation(), diag::err_pp_expr_bad_token_binop)
<< RHS.getRange();
diagnoseUnexpectedOperator(PP, RHS, PeekTok);
return true;
}
@ -769,6 +790,7 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec,
// Put the result back into 'LHS' for our next iteration.
LHS.Val = Res;
LHS.setEnd(RHS.getRange().getEnd());
RHS.setIdentifier(nullptr);
}
}

View File

@ -1,15 +1,28 @@
// RUN: not %clang_cc1 -E %s 2>&1 | grep 'invalid token at start of a preprocessor expression'
// RUN: not %clang_cc1 -E %s 2>&1 | grep 'token is not a valid binary operator in a preprocessor subexpression'
// RUN: not %clang_cc1 -E %s 2>&1 | grep ':14: error: expected end of line in preprocessor expression'
// RUN: not %clang_cc1 -E %s 2>&1 | FileCheck %s
// PR2220
// CHECK: invalid token at start of a preprocessor expression
#if 1 * * 2
#endif
// CHECK: token is not a valid binary operator in a preprocessor subexpression
#if 4 [ 2
#endif
// PR2284 - The constant-expr production does not including comma.
// CHECK: [[@LINE+1]]:14: error: expected end of line in preprocessor expression
#if 1 ? 2 : 0, 1
#endif
// CHECK: [[@LINE+1]]:5: error: function-like macro 'FOO' is not defined
#if FOO(1, 2, 3)
#endif
// CHECK: [[@LINE+1]]:9: error: function-like macro 'BAR' is not defined
#if 1 + BAR(1, 2, 3)
#endif
// CHECK: [[@LINE+1]]:10: error: token is not a valid binary operator
#if (FOO)(1, 2, 3)
#endif

View File

@ -54,5 +54,5 @@ int has_no_volatile_attribute();
int does_not_have_uuid
#endif
#if __has_cpp_attribute(selectany) // expected-error {{token is not a valid binary operator in a preprocessor subexpression}}
#if __has_cpp_attribute(selectany) // expected-error {{function-like macro '__has_cpp_attribute' is not defined}}
#endif