From: Richard Smith Date: Sat, 16 Apr 2016 00:07:09 +0000 (+0000) Subject: Improve diagnostic for the case when a non-defined function-like macro is used X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=acd477f5a48c2bb5181574d4c4ea753587f91c42;p=clang Improve diagnostic for the case when a non-defined function-like macro is used in a preprocessor constant expression. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@266495 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td index a8f899b762..dab8cf279c 100644 --- a/include/clang/Basic/DiagnosticLexKinds.td +++ b/include/clang/Basic/DiagnosticLexKinds.td @@ -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">; diff --git a/lib/Lex/PPExpressions.cpp b/lib/Lex/PPExpressions.cpp index 058e2741d7..94075ece35 100644 --- a/lib/Lex/PPExpressions.cpp +++ b/lib/Lex/PPExpressions.cpp @@ -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); } } diff --git a/test/Preprocessor/expr_invalid_tok.c b/test/Preprocessor/expr_invalid_tok.c index 5defcc5bfb..0b97b255f1 100644 --- a/test/Preprocessor/expr_invalid_tok.c +++ b/test/Preprocessor/expr_invalid_tok.c @@ -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 diff --git a/test/Preprocessor/has_attribute.c b/test/Preprocessor/has_attribute.c index 1a3c2a0e18..4970dc5904 100644 --- a/test/Preprocessor/has_attribute.c +++ b/test/Preprocessor/has_attribute.c @@ -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