From 4d247e7012ae6355c9b63b6a6549adadd0a16fd1 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Sat, 16 Apr 2016 00:07:09 +0000 Subject: [PATCH] Improve diagnostic for the case when a non-defined function-like macro is used in a preprocessor constant expression. llvm-svn: 266495 --- clang/include/clang/Basic/DiagnosticLexKinds.td | 2 ++ clang/lib/Lex/PPExpressions.cpp | 30 +++++++++++++++++++++---- clang/test/Preprocessor/expr_invalid_tok.c | 19 +++++++++++++--- clang/test/Preprocessor/has_attribute.c | 2 +- 4 files changed, 45 insertions(+), 8 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td index a8f899b..dab8cf2 100644 --- a/clang/include/clang/Basic/DiagnosticLexKinds.td +++ b/clang/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/clang/lib/Lex/PPExpressions.cpp b/clang/lib/Lex/PPExpressions.cpp index 058e274..94075ec 100644 --- a/clang/lib/Lex/PPExpressions.cpp +++ b/clang/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/clang/test/Preprocessor/expr_invalid_tok.c b/clang/test/Preprocessor/expr_invalid_tok.c index 5defcc5b..0b97b25 100644 --- a/clang/test/Preprocessor/expr_invalid_tok.c +++ b/clang/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/clang/test/Preprocessor/has_attribute.c b/clang/test/Preprocessor/has_attribute.c index 1a3c2a0..4970dc5 100644 --- a/clang/test/Preprocessor/has_attribute.c +++ b/clang/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 -- 2.7.4