зеркало из https://github.com/microsoft/clang-1.git
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
This commit is contained in:
Родитель
b95cfe4bb0
Коммит
a25b6a4b43
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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>();
|
||||
}
|
Загрузка…
Ссылка в новой задаче