diff options
| -rw-r--r-- | clang/include/clang/AST/Stmt.h | 18 | ||||
| -rw-r--r-- | clang/include/clang/Lex/Preprocessor.h | 17 | ||||
| -rw-r--r-- | clang/include/clang/Parse/Parser.h | 3 | ||||
| -rw-r--r-- | clang/include/clang/Sema/Sema.h | 2 | ||||
| -rw-r--r-- | clang/lib/AST/Stmt.cpp | 6 | ||||
| -rw-r--r-- | clang/lib/Lex/PPMacroExpansion.cpp | 1 | ||||
| -rw-r--r-- | clang/lib/Parse/ParseStmt.cpp | 16 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaStmt.cpp | 16 | ||||
| -rw-r--r-- | clang/lib/Sema/TreeTransform.h | 8 | ||||
| -rw-r--r-- | clang/lib/Serialization/ASTReaderStmt.cpp | 1 | ||||
| -rw-r--r-- | clang/lib/Serialization/ASTWriterStmt.cpp | 1 | ||||
| -rw-r--r-- | clang/test/SemaCXX/if-empty-body.cpp (renamed from clang/test/Sema/if-empty-body.c) | 15 | 
12 files changed, 85 insertions, 19 deletions
diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h index 67871258632..8726bfb417d 100644 --- a/clang/include/clang/AST/Stmt.h +++ b/clang/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/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h index 261daed75bc..2194d6fe620 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/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/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index e94225813e2..325b47d1cc6 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/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/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index e6cbc329bf5..8294ffd784a 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/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/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp index acd77beaca4..85e640701bf 100644 --- a/clang/lib/AST/Stmt.cpp +++ b/clang/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/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index 2428f9af450..6d2c387d528 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/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/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index 12444e87bbd..e3c15680c23 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/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/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index a4f1d34aec3..c6194edac3a 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/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/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 807346c4c57..3ae4e5c5f49 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/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/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index 6d578f616ed..a7b42cd3fcf 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/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/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index 495c3d05ffe..a59b772da4e 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/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/clang/test/Sema/if-empty-body.c b/clang/test/SemaCXX/if-empty-body.cpp index b28c1cdce96..ec7f89d68e7 100644 --- a/clang/test/Sema/if-empty-body.c +++ b/clang/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>(); +}  | 

