diff options
author | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2010-11-19 20:54:25 +0000 |
---|---|---|
committer | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2010-11-19 20:54:25 +0000 |
commit | a25b6a4b43e8b9611f7506e5fe1b448833b10a46 (patch) | |
tree | 1c8c6e68f978b9b156704e77c31beb8bf573b845 | |
parent | b95cfe4bb01f18a112bcb7eea3b82bc8d6dfe20b (diff) |
Don't warn for empty 'if' body if there is a macro that expands to nothing, e.g:
if (condition)
CALL(0); // empty macro but don't warn for empty body.
Fixes rdar://8436021.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@119838 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/AST/Stmt.h | 18 | ||||
-rw-r--r-- | include/clang/Lex/Preprocessor.h | 17 | ||||
-rw-r--r-- | include/clang/Parse/Parser.h | 3 | ||||
-rw-r--r-- | include/clang/Sema/Sema.h | 2 | ||||
-rw-r--r-- | lib/AST/Stmt.cpp | 6 | ||||
-rw-r--r-- | lib/Lex/PPMacroExpansion.cpp | 1 | ||||
-rw-r--r-- | lib/Parse/ParseStmt.cpp | 16 | ||||
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 16 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 8 | ||||
-rw-r--r-- | lib/Serialization/ASTReaderStmt.cpp | 1 | ||||
-rw-r--r-- | lib/Serialization/ASTWriterStmt.cpp | 1 | ||||
-rw-r--r-- | test/SemaCXX/if-empty-body.cpp (renamed from test/Sema/if-empty-body.c) | 15 |
12 files changed, 85 insertions, 19 deletions
diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h index 6787125863..8726bfb417 100644 --- a/include/clang/AST/Stmt.h +++ b/include/clang/AST/Stmt.h @@ -651,10 +651,19 @@ class IfStmt : public Stmt { SourceLocation IfLoc; SourceLocation ElseLoc; - + + /// \brief True if we have code like: + /// @code + /// #define CALL(x) + /// if (condition) + /// CALL(0); + /// @endcode + bool MacroExpandedInThenStmt; + public: IfStmt(ASTContext &C, SourceLocation IL, VarDecl *var, Expr *cond, - Stmt *then, SourceLocation EL = SourceLocation(), Stmt *elsev = 0); + Stmt *then, SourceLocation EL = SourceLocation(), Stmt *elsev = 0, + bool macroExpandedInThenStmt = false); /// \brief Build an empty if/then/else statement explicit IfStmt(EmptyShell Empty) : Stmt(IfStmtClass, Empty) { } @@ -686,6 +695,8 @@ public: SourceLocation getElseLoc() const { return ElseLoc; } void setElseLoc(SourceLocation L) { ElseLoc = L; } + bool hasMacroExpandedInThenStmt() const { return MacroExpandedInThenStmt; } + virtual SourceRange getSourceRange() const { if (SubExprs[ELSE]) return SourceRange(IfLoc, SubExprs[ELSE]->getLocEnd()); @@ -702,6 +713,9 @@ public: // over the initialization expression referenced by the condition variable. virtual child_iterator child_begin(); virtual child_iterator child_end(); + + friend class ASTStmtReader; + friend class ASTStmtWriter; }; /// SwitchStmt - This represents a 'switch' stmt. diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h index 261daed75b..2194d6fe62 100644 --- a/include/clang/Lex/Preprocessor.h +++ b/include/clang/Lex/Preprocessor.h @@ -47,6 +47,7 @@ class PPCallbacks; class CodeCompletionHandler; class DirectoryLookup; class PreprocessingRecord; +class PPMacroExpansionTrap; /// Preprocessor - This object engages in a tight little dance with the lexer to /// efficiently preprocess tokens. Lexers know only about tokens within a @@ -110,6 +111,11 @@ class Preprocessor { /// DisableMacroExpansion - True if macro expansion is disabled. bool DisableMacroExpansion : 1; + /// \brief This is set to true when a macro is expanded. + /// Used by PPMacroExpansionTrap. + bool MacroExpansionFlag : 1; + friend class PPMacroExpansionTrap; + /// \brief Whether we have already loaded macros from the external source. mutable bool ReadMacrosFromExternalSource : 1; @@ -1029,6 +1035,17 @@ public: virtual bool HandleComment(Preprocessor &PP, SourceRange Comment) = 0; }; +/// \brief RAII class that determines when any macro expansion has occurred +/// between the time the instance was created and the time it was +/// queried. +class PPMacroExpansionTrap { + Preprocessor &PP; +public: + PPMacroExpansionTrap(Preprocessor &PP) : PP(PP) { reset(); } + bool hasMacroExpansionOccured() const { return PP.MacroExpansionFlag; } + void reset() { PP.MacroExpansionFlag = false; } +}; + } // end namespace clang #endif diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index e94225813e..325b47d1cc 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -1199,7 +1199,8 @@ private: bool ParseParenExprOrCondition(ExprResult &ExprResult, Decl *&DeclResult, SourceLocation Loc, - bool ConvertToBoolean); + bool ConvertToBoolean, + bool *MacroExpandedAfterRParen = 0); StmtResult ParseIfStatement(AttributeList *Attr); StmtResult ParseSwitchStatement(AttributeList *Attr); StmtResult ParseWhileStatement(AttributeList *Attr); diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index e6cbc329bf..8294ffd784 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -1590,7 +1590,7 @@ public: bool HasUnusedAttr); StmtResult ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, Decl *CondVar, - Stmt *ThenVal, + Stmt *ThenVal, bool MacroExpandedInThenStmt, SourceLocation ElseLoc, Stmt *ElseVal); StmtResult ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Expr *Cond, diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index acd77beaca..85e640701b 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -470,8 +470,10 @@ CXXTryStmt::CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock, } IfStmt::IfStmt(ASTContext &C, SourceLocation IL, VarDecl *var, Expr *cond, - Stmt *then, SourceLocation EL, Stmt *elsev) - : Stmt(IfStmtClass), IfLoc(IL), ElseLoc(EL) + Stmt *then, SourceLocation EL, Stmt *elsev, + bool macroExpandedInThenStmt) + : Stmt(IfStmtClass), IfLoc(IL), ElseLoc(EL), + MacroExpandedInThenStmt(macroExpandedInThenStmt) { setConditionVariable(C, var); SubExprs[COND] = reinterpret_cast<Stmt*>(cond); diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index 2428f9af45..6d2c387d52 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -176,6 +176,7 @@ bool Preprocessor::isNextPPTokenLParen() { /// expanded as a macro, handle it and return the next token as 'Identifier'. bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier, MacroInfo *MI) { + MacroExpansionFlag = true; if (Callbacks) Callbacks->MacroExpands(Identifier, MI); // If this is a macro expansion in the "#if !defined(x)" line for the file, diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 12444e87bb..e3c15680c2 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -538,7 +538,8 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { bool Parser::ParseParenExprOrCondition(ExprResult &ExprResult, Decl *&DeclResult, SourceLocation Loc, - bool ConvertToBoolean) { + bool ConvertToBoolean, + bool *MacroExpandedAfterRParen) { bool ParseError = false; SourceLocation LParenLoc = ConsumeParen(); @@ -567,7 +568,14 @@ bool Parser::ParseParenExprOrCondition(ExprResult &ExprResult, } // Otherwise the condition is valid or the rparen is present. + + // Catch a macro expansion after ')'. This is used to know that there is a + // macro for 'if' body and not warn for empty body if the macro is empty. + PPMacroExpansionTrap MacroExpansionTrap(PP); MatchRHSPunctuation(tok::r_paren, LParenLoc); + if (MacroExpandedAfterRParen) + *MacroExpandedAfterRParen = MacroExpansionTrap.hasMacroExpansionOccured(); + return false; } @@ -610,7 +618,9 @@ StmtResult Parser::ParseIfStatement(AttributeList *Attr) { // Parse the condition. ExprResult CondExp; Decl *CondVar = 0; - if (ParseParenExprOrCondition(CondExp, CondVar, IfLoc, true)) + bool MacroExpandedInThenStmt; + if (ParseParenExprOrCondition(CondExp, CondVar, IfLoc, true, + &MacroExpandedInThenStmt)) return StmtError(); FullExprArg FullCondExp(Actions.MakeFullExpr(CondExp.get())); @@ -694,7 +704,7 @@ StmtResult Parser::ParseIfStatement(AttributeList *Attr) { ElseStmt = Actions.ActOnNullStmt(ElseStmtLoc); return Actions.ActOnIfStmt(IfLoc, FullCondExp, CondVar, ThenStmt.get(), - ElseLoc, ElseStmt.get()); + MacroExpandedInThenStmt, ElseLoc, ElseStmt.get()); } /// ParseSwitchStatement diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index a4f1d34aec..c6194edac3 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -282,8 +282,8 @@ Sema::ActOnLabelStmt(SourceLocation IdentLoc, IdentifierInfo *II, StmtResult Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, Decl *CondVar, - Stmt *thenStmt, SourceLocation ElseLoc, - Stmt *elseStmt) { + Stmt *thenStmt, bool MacroExpandedInThenStmt, + SourceLocation ElseLoc, Stmt *elseStmt) { ExprResult CondResult(CondVal.release()); VarDecl *ConditionVar = 0; @@ -304,17 +304,23 @@ Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, Decl *CondVar, // if (condition); // do_stuff(); // - // NOTE: Do not emit this warning if the body is expanded from a macro. if (!elseStmt) { if (NullStmt* stmt = dyn_cast<NullStmt>(thenStmt)) - if (!stmt->getLocStart().isMacroID()) + // But do not warn if the body is a macro that expands to nothing, e.g: + // + // #define CALL(x) + // if (condition) + // CALL(0); + // + if (!MacroExpandedInThenStmt) Diag(stmt->getSemiLoc(), diag::warn_empty_if_body); } DiagnoseUnusedExprResult(elseStmt); return Owned(new (Context) IfStmt(Context, IfLoc, ConditionVar, ConditionExpr, - thenStmt, ElseLoc, elseStmt)); + thenStmt, ElseLoc, elseStmt, + MacroExpandedInThenStmt)); } /// ConvertIntegerToTypeWarnOnOverflow - Convert the specified APInt to have diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 807346c4c5..3ae4e5c5f4 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -772,9 +772,11 @@ public: /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildIfStmt(SourceLocation IfLoc, Sema::FullExprArg Cond, - VarDecl *CondVar, Stmt *Then, + VarDecl *CondVar, Stmt *Then, + bool MacroExpandedInThenStmt, SourceLocation ElseLoc, Stmt *Else) { - return getSema().ActOnIfStmt(IfLoc, Cond, CondVar, Then, ElseLoc, Else); + return getSema().ActOnIfStmt(IfLoc, Cond, CondVar, Then, + MacroExpandedInThenStmt, ElseLoc, Else); } /// \brief Start building a new switch statement. @@ -3692,7 +3694,7 @@ TreeTransform<Derived>::TransformIfStmt(IfStmt *S) { return SemaRef.Owned(S); return getDerived().RebuildIfStmt(S->getIfLoc(), FullCond, ConditionVar, - Then.get(), + Then.get(), S->hasMacroExpandedInThenStmt(), S->getElseLoc(), Else.get()); } diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp index 6d578f616e..a7b42cd3fc 100644 --- a/lib/Serialization/ASTReaderStmt.cpp +++ b/lib/Serialization/ASTReaderStmt.cpp @@ -256,6 +256,7 @@ void ASTStmtReader::VisitIfStmt(IfStmt *S) { S->setElse(Reader.ReadSubStmt()); S->setIfLoc(ReadSourceLocation(Record, Idx)); S->setElseLoc(ReadSourceLocation(Record, Idx)); + S->MacroExpandedInThenStmt = Record[Idx++]; } void ASTStmtReader::VisitSwitchStmt(SwitchStmt *S) { diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp index 495c3d05ff..a59b772da4 100644 --- a/lib/Serialization/ASTWriterStmt.cpp +++ b/lib/Serialization/ASTWriterStmt.cpp @@ -228,6 +228,7 @@ void ASTStmtWriter::VisitIfStmt(IfStmt *S) { Writer.AddStmt(S->getElse()); Writer.AddSourceLocation(S->getIfLoc(), Record); Writer.AddSourceLocation(S->getElseLoc(), Record); + Record.push_back(S->MacroExpandedInThenStmt); Code = serialization::STMT_IF; } diff --git a/test/Sema/if-empty-body.c b/test/SemaCXX/if-empty-body.cpp index b28c1cdce9..ec7f89d68e 100644 --- a/test/Sema/if-empty-body.c +++ b/test/SemaCXX/if-empty-body.cpp @@ -16,9 +16,20 @@ void f3() { // Don't warn about an empty body if is expanded from a macro. void f4(int i) { - #define BODY ; + #define BODY(x) if (i == i) // expected-warning{{self-comparison always evaluates to true}} - BODY + BODY(0); #undef BODY } +template <typename T> +void tf() { + #define BODY(x) + if (0) + BODY(0); + #undef BODY +} + +void f5() { + tf<int>(); +} |