///
class NullStmt : public Stmt {
SourceLocation SemiLoc;
+
+ /// \brief Whether the null statement was preceded by an empty macro, e.g:
+ /// @code
+ /// #define CALL(x)
+ /// CALL(0);
+ /// @endcode
+ bool LeadingEmptyMacro;
public:
- NullStmt(SourceLocation L) : Stmt(NullStmtClass), SemiLoc(L) {}
+ NullStmt(SourceLocation L, bool LeadingEmptyMacro = false)
+ : Stmt(NullStmtClass), SemiLoc(L), LeadingEmptyMacro(LeadingEmptyMacro) {}
/// \brief Build an empty null statement.
explicit NullStmt(EmptyShell Empty) : Stmt(NullStmtClass, Empty) { }
SourceLocation getSemiLoc() const { return SemiLoc; }
void setSemiLoc(SourceLocation L) { SemiLoc = L; }
+ bool hasLeadingEmptyMacro() const { return LeadingEmptyMacro; }
+
virtual SourceRange getSourceRange() const { return SourceRange(SemiLoc); }
static bool classof(const Stmt *T) {
// Iterators
virtual child_iterator child_begin();
virtual child_iterator child_end();
+
+ friend class ASTStmtReader;
+ friend class ASTStmtWriter;
};
/// CompoundStmt - This represents a group of statements like { stmt 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,
- bool macroExpandedInThenStmt = false);
+ Stmt *then, SourceLocation EL = SourceLocation(), Stmt *elsev = 0);
/// \brief Build an empty if/then/else statement
explicit IfStmt(EmptyShell Empty) : Stmt(IfStmtClass, Empty) { }
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());
// 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.
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
/// 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;
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
StartOfLine = 0x01, // At start of line or only after whitespace.
LeadingSpace = 0x02, // Whitespace exists before this token.
DisableExpand = 0x04, // This identifier may never be macro expanded.
- NeedsCleaning = 0x08 // Contained an escaped newline or trigraph.
+ NeedsCleaning = 0x08, // Contained an escaped newline or trigraph.
+ LeadingEmptyMacro = 0x10 // Empty macro exists before this token.
};
tok::TokenKind getKind() const { return (tok::TokenKind)Kind; }
/// newlines in it.
///
bool needsCleaning() const { return (Flags & NeedsCleaning) ? true : false; }
-
+
+ /// \brief Return true if this token has an empty macro before it.
+ ///
+ bool hasLeadingEmptyMacro() const {
+ return (Flags & LeadingEmptyMacro) ? true : false;
+ }
+
};
/// PPConditionalInfo - Information about the conditional stack (#if directives)
bool ParseParenExprOrCondition(ExprResult &ExprResult,
Decl *&DeclResult,
SourceLocation Loc,
- bool ConvertToBoolean,
- bool *MacroExpandedAfterRParen = 0);
+ bool ConvertToBoolean);
StmtResult ParseIfStatement(AttributeList *Attr);
StmtResult ParseSwitchStatement(AttributeList *Attr);
StmtResult ParseWhileStatement(AttributeList *Attr);
StmtResult ActOnExprStmt(FullExprArg Expr);
- StmtResult ActOnNullStmt(SourceLocation SemiLoc);
+ StmtResult ActOnNullStmt(SourceLocation SemiLoc,
+ bool LeadingEmptyMacro = false);
StmtResult ActOnCompoundStmt(SourceLocation L, SourceLocation R,
MultiStmtArg Elts,
bool isStmtExpr);
bool HasUnusedAttr);
StmtResult ActOnIfStmt(SourceLocation IfLoc,
FullExprArg CondVal, Decl *CondVar,
- Stmt *ThenVal, bool MacroExpandedInThenStmt,
+ Stmt *ThenVal,
SourceLocation ElseLoc, Stmt *ElseVal);
StmtResult ActOnStartOfSwitchStmt(SourceLocation SwitchLoc,
Expr *Cond,
}
IfStmt::IfStmt(ASTContext &C, SourceLocation IL, VarDecl *var, Expr *cond,
- Stmt *then, SourceLocation EL, Stmt *elsev,
- bool macroExpandedInThenStmt)
- : Stmt(IfStmtClass), IfLoc(IL), ElseLoc(EL),
- MacroExpandedInThenStmt(macroExpandedInThenStmt)
+ Stmt *then, SourceLocation EL, Stmt *elsev)
+ : Stmt(IfStmtClass), IfLoc(IL), ElseLoc(EL)
{
setConditionVariable(C, var);
SubExprs[COND] = reinterpret_cast<Stmt*>(cond);
/// 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,
if (IsAtStartOfLine) Identifier.setFlag(Token::StartOfLine);
if (HadLeadingSpace) Identifier.setFlag(Token::LeadingSpace);
}
+ Identifier.setFlag(Token::LeadingEmptyMacro);
++NumFastMacroExpanded;
return false;
case tok::l_brace: // C99 6.8.2: compound-statement
return ParseCompoundStatement(AttrList);
- case tok::semi: // C99 6.8.3p3: expression[opt] ';'
- return Actions.ActOnNullStmt(ConsumeToken());
+ case tok::semi: { // C99 6.8.3p3: expression[opt] ';'
+ bool LeadingEmptyMacro = Tok.hasLeadingEmptyMacro();
+ return Actions.ActOnNullStmt(ConsumeToken(), LeadingEmptyMacro);
+ }
case tok::kw_if: // C99 6.8.4.1: if-statement
return ParseIfStatement(AttrList);
bool Parser::ParseParenExprOrCondition(ExprResult &ExprResult,
Decl *&DeclResult,
SourceLocation Loc,
- bool ConvertToBoolean,
- bool *MacroExpandedAfterRParen) {
+ bool ConvertToBoolean) {
bool ParseError = false;
SourceLocation LParenLoc = ConsumeParen();
}
// 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;
}
// Parse the condition.
ExprResult CondExp;
Decl *CondVar = 0;
- bool MacroExpandedInThenStmt;
- if (ParseParenExprOrCondition(CondExp, CondVar, IfLoc, true,
- &MacroExpandedInThenStmt))
+ if (ParseParenExprOrCondition(CondExp, CondVar, IfLoc, true))
return StmtError();
FullExprArg FullCondExp(Actions.MakeFullExpr(CondExp.get()));
ElseStmt = Actions.ActOnNullStmt(ElseStmtLoc);
return Actions.ActOnIfStmt(IfLoc, FullCondExp, CondVar, ThenStmt.get(),
- MacroExpandedInThenStmt, ElseLoc, ElseStmt.get());
+ ElseLoc, ElseStmt.get());
}
/// ParseSwitchStatement
}
-StmtResult Sema::ActOnNullStmt(SourceLocation SemiLoc) {
- return Owned(new (Context) NullStmt(SemiLoc));
+StmtResult Sema::ActOnNullStmt(SourceLocation SemiLoc, bool LeadingEmptyMacro) {
+ return Owned(new (Context) NullStmt(SemiLoc, LeadingEmptyMacro));
}
StmtResult Sema::ActOnDeclStmt(DeclGroupPtrTy dg,
StmtResult
Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, Decl *CondVar,
- Stmt *thenStmt, bool MacroExpandedInThenStmt,
- SourceLocation ElseLoc, Stmt *elseStmt) {
+ Stmt *thenStmt, SourceLocation ElseLoc,
+ Stmt *elseStmt) {
ExprResult CondResult(CondVal.release());
VarDecl *ConditionVar = 0;
// if (condition)
// CALL(0);
//
- if (!MacroExpandedInThenStmt)
+ if (!stmt->hasLeadingEmptyMacro())
Diag(stmt->getSemiLoc(), diag::warn_empty_if_body);
}
DiagnoseUnusedExprResult(elseStmt);
return Owned(new (Context) IfStmt(Context, IfLoc, ConditionVar, ConditionExpr,
- thenStmt, ElseLoc, elseStmt,
- MacroExpandedInThenStmt));
+ thenStmt, ElseLoc, elseStmt));
}
/// ConvertIntegerToTypeWarnOnOverflow - Convert the specified APInt to have
/// 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,
- bool MacroExpandedInThenStmt,
+ VarDecl *CondVar, Stmt *Then,
SourceLocation ElseLoc, Stmt *Else) {
- return getSema().ActOnIfStmt(IfLoc, Cond, CondVar, Then,
- MacroExpandedInThenStmt, ElseLoc, Else);
+ return getSema().ActOnIfStmt(IfLoc, Cond, CondVar, Then, ElseLoc, Else);
}
/// \brief Start building a new switch statement.
return SemaRef.Owned(S);
return getDerived().RebuildIfStmt(S->getIfLoc(), FullCond, ConditionVar,
- Then.get(), S->hasMacroExpandedInThenStmt(),
+ Then.get(),
S->getElseLoc(), Else.get());
}
void ASTStmtReader::VisitNullStmt(NullStmt *S) {
VisitStmt(S);
S->setSemiLoc(ReadSourceLocation(Record, Idx));
+ S->LeadingEmptyMacro = Record[Idx++];
}
void ASTStmtReader::VisitCompoundStmt(CompoundStmt *S) {
S->setElse(Reader.ReadSubStmt());
S->setIfLoc(ReadSourceLocation(Record, Idx));
S->setElseLoc(ReadSourceLocation(Record, Idx));
- S->MacroExpandedInThenStmt = Record[Idx++];
}
void ASTStmtReader::VisitSwitchStmt(SwitchStmt *S) {
void ASTStmtWriter::VisitNullStmt(NullStmt *S) {
VisitStmt(S);
Writer.AddSourceLocation(S->getSemiLoc(), Record);
+ Record.push_back(S->LeadingEmptyMacro);
Code = serialization::STMT_NULL;
}
Writer.AddStmt(S->getElse());
Writer.AddSourceLocation(S->getIfLoc(), Record);
Writer.AddSourceLocation(S->getElseLoc(), Record);
- Record.push_back(S->MacroExpandedInThenStmt);
Code = serialization::STMT_IF;
}