forked from OSchip/llvm-project
P0305R0: Semantic analysis and code generation for C++17 init-statement for 'if' and 'switch':
if (stmt; condition) { ... } Patch by Anton Bikineev! Some minor formatting and comment tweets by me. llvm-svn: 275350
This commit is contained in:
parent
d5bbd856e2
commit
a547eb27fa
|
@ -879,7 +879,7 @@ public:
|
|||
/// IfStmt - This represents an if/then/else.
|
||||
///
|
||||
class IfStmt : public Stmt {
|
||||
enum { VAR, COND, THEN, ELSE, END_EXPR };
|
||||
enum { INIT, VAR, COND, THEN, ELSE, END_EXPR };
|
||||
Stmt* SubExprs[END_EXPR];
|
||||
|
||||
SourceLocation IfLoc;
|
||||
|
@ -887,7 +887,7 @@ class IfStmt : public Stmt {
|
|||
|
||||
public:
|
||||
IfStmt(const ASTContext &C, SourceLocation IL,
|
||||
bool IsConstexpr, VarDecl *var, Expr *cond,
|
||||
bool IsConstexpr, Stmt *init, VarDecl *var, Expr *cond,
|
||||
Stmt *then, SourceLocation EL = SourceLocation(),
|
||||
Stmt *elsev = nullptr);
|
||||
|
||||
|
@ -911,6 +911,9 @@ public:
|
|||
return reinterpret_cast<DeclStmt*>(SubExprs[VAR]);
|
||||
}
|
||||
|
||||
Stmt *getInit() { return SubExprs[INIT]; }
|
||||
const Stmt *getInit() const { return SubExprs[INIT]; }
|
||||
void setInit(Stmt *S) { SubExprs[INIT] = S; }
|
||||
const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);}
|
||||
void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt *>(E); }
|
||||
const Stmt *getThen() const { return SubExprs[THEN]; }
|
||||
|
@ -953,7 +956,7 @@ public:
|
|||
///
|
||||
class SwitchStmt : public Stmt {
|
||||
SourceLocation SwitchLoc;
|
||||
enum { VAR, COND, BODY, END_EXPR };
|
||||
enum { INIT, VAR, COND, BODY, END_EXPR };
|
||||
Stmt* SubExprs[END_EXPR];
|
||||
// This points to a linked list of case and default statements and, if the
|
||||
// SwitchStmt is a switch on an enum value, records whether all the enum
|
||||
|
@ -962,7 +965,7 @@ class SwitchStmt : public Stmt {
|
|||
llvm::PointerIntPair<SwitchCase *, 1, bool> FirstCase;
|
||||
|
||||
public:
|
||||
SwitchStmt(const ASTContext &C, VarDecl *Var, Expr *cond);
|
||||
SwitchStmt(const ASTContext &C, Stmt *Init, VarDecl *Var, Expr *cond);
|
||||
|
||||
/// \brief Build a empty switch statement.
|
||||
explicit SwitchStmt(EmptyShell Empty) : Stmt(SwitchStmtClass, Empty) { }
|
||||
|
@ -985,6 +988,9 @@ public:
|
|||
return reinterpret_cast<DeclStmt*>(SubExprs[VAR]);
|
||||
}
|
||||
|
||||
Stmt *getInit() { return SubExprs[INIT]; }
|
||||
const Stmt *getInit() const { return SubExprs[INIT]; }
|
||||
void setInit(Stmt *S) { SubExprs[INIT] = S; }
|
||||
const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);}
|
||||
const Stmt *getBody() const { return SubExprs[BODY]; }
|
||||
const SwitchCase *getSwitchCaseList() const { return FirstCase.getPointer(); }
|
||||
|
|
|
@ -7503,9 +7503,6 @@ def warn_empty_switch_body : Warning<
|
|||
def note_empty_body_on_separate_line : Note<
|
||||
"put the semicolon on a separate line to silence this warning">;
|
||||
|
||||
def err_init_stmt_not_supported : Error<
|
||||
"C++1z init-statement not yet supported">;
|
||||
|
||||
def err_va_start_used_in_non_variadic_function : Error<
|
||||
"'va_start' used in function with fixed args">;
|
||||
def err_va_start_used_in_wrong_abi_function : Error<
|
||||
|
|
|
@ -3401,6 +3401,7 @@ public:
|
|||
ConditionResult Cond, Stmt *ThenVal,
|
||||
SourceLocation ElseLoc, Stmt *ElseVal);
|
||||
StmtResult BuildIfStmt(SourceLocation IfLoc, bool IsConstexpr,
|
||||
Stmt *InitStmt,
|
||||
ConditionResult Cond, Stmt *ThenVal,
|
||||
SourceLocation ElseLoc, Stmt *ElseVal);
|
||||
StmtResult ActOnStartOfSwitchStmt(SourceLocation SwitchLoc,
|
||||
|
|
|
@ -4961,6 +4961,9 @@ Stmt *ASTNodeImporter::VisitAttributedStmt(AttributedStmt *S) {
|
|||
|
||||
Stmt *ASTNodeImporter::VisitIfStmt(IfStmt *S) {
|
||||
SourceLocation ToIfLoc = Importer.Import(S->getIfLoc());
|
||||
Stmt *ToInit = Importer.Import(S->getInit());
|
||||
if (!ToInit && S->getInit())
|
||||
return nullptr;
|
||||
VarDecl *ToConditionVariable = nullptr;
|
||||
if (VarDecl *FromConditionVariable = S->getConditionVariable()) {
|
||||
ToConditionVariable =
|
||||
|
@ -4980,12 +4983,16 @@ Stmt *ASTNodeImporter::VisitIfStmt(IfStmt *S) {
|
|||
return nullptr;
|
||||
return new (Importer.getToContext()) IfStmt(Importer.getToContext(),
|
||||
ToIfLoc, S->isConstexpr(),
|
||||
ToInit,
|
||||
ToConditionVariable,
|
||||
ToCondition, ToThenStmt,
|
||||
ToElseLoc, ToElseStmt);
|
||||
}
|
||||
|
||||
Stmt *ASTNodeImporter::VisitSwitchStmt(SwitchStmt *S) {
|
||||
Stmt *ToInit = Importer.Import(S->getInit());
|
||||
if (!ToInit && S->getInit())
|
||||
return nullptr;
|
||||
VarDecl *ToConditionVariable = nullptr;
|
||||
if (VarDecl *FromConditionVariable = S->getConditionVariable()) {
|
||||
ToConditionVariable =
|
||||
|
@ -4997,8 +5004,8 @@ Stmt *ASTNodeImporter::VisitSwitchStmt(SwitchStmt *S) {
|
|||
if (!ToCondition && S->getCond())
|
||||
return nullptr;
|
||||
SwitchStmt *ToStmt = new (Importer.getToContext()) SwitchStmt(
|
||||
Importer.getToContext(), ToConditionVariable,
|
||||
ToCondition);
|
||||
Importer.getToContext(), ToInit,
|
||||
ToConditionVariable, ToCondition);
|
||||
Stmt *ToBody = Importer.Import(S->getBody());
|
||||
if (!ToBody && S->getBody())
|
||||
return nullptr;
|
||||
|
|
|
@ -3485,6 +3485,11 @@ static EvalStmtResult EvaluateSwitch(StmtResult &Result, EvalInfo &Info,
|
|||
APSInt Value;
|
||||
{
|
||||
FullExpressionRAII Scope(Info);
|
||||
if (const Stmt *Init = SS->getInit()) {
|
||||
EvalStmtResult ESR = EvaluateStmt(Result, Info, Init);
|
||||
if (ESR != ESR_Succeeded)
|
||||
return ESR;
|
||||
}
|
||||
if (SS->getConditionVariable() &&
|
||||
!EvaluateDecl(Info, SS->getConditionVariable()))
|
||||
return ESR_Failed;
|
||||
|
@ -3667,6 +3672,11 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
|
|||
|
||||
// Evaluate the condition, as either a var decl or as an expression.
|
||||
BlockScopeRAII Scope(Info);
|
||||
if (const Stmt *Init = IS->getInit()) {
|
||||
EvalStmtResult ESR = EvaluateStmt(Result, Info, Init);
|
||||
if (ESR != ESR_Succeeded)
|
||||
return ESR;
|
||||
}
|
||||
bool Cond;
|
||||
if (!EvaluateCond(Info, IS->getConditionVariable(), IS->getCond(), Cond))
|
||||
return ESR_Failed;
|
||||
|
|
|
@ -764,11 +764,12 @@ void MSAsmStmt::initialize(const ASTContext &C, StringRef asmstr,
|
|||
}
|
||||
|
||||
IfStmt::IfStmt(const ASTContext &C, SourceLocation IL, bool IsConstexpr,
|
||||
VarDecl *var, Expr *cond, Stmt *then, SourceLocation EL,
|
||||
Stmt *elsev)
|
||||
Stmt *init, VarDecl *var, Expr *cond, Stmt *then,
|
||||
SourceLocation EL, Stmt *elsev)
|
||||
: Stmt(IfStmtClass), IfLoc(IL), ElseLoc(EL) {
|
||||
setConstexpr(IsConstexpr);
|
||||
setConditionVariable(C, var);
|
||||
SubExprs[INIT] = init;
|
||||
SubExprs[COND] = cond;
|
||||
SubExprs[THEN] = then;
|
||||
SubExprs[ELSE] = elsev;
|
||||
|
@ -824,9 +825,11 @@ void ForStmt::setConditionVariable(const ASTContext &C, VarDecl *V) {
|
|||
VarRange.getEnd());
|
||||
}
|
||||
|
||||
SwitchStmt::SwitchStmt(const ASTContext &C, VarDecl *Var, Expr *cond)
|
||||
SwitchStmt::SwitchStmt(const ASTContext &C, Stmt *init, VarDecl *Var,
|
||||
Expr *cond)
|
||||
: Stmt(SwitchStmtClass), FirstCase(nullptr, false) {
|
||||
setConditionVariable(C, Var);
|
||||
SubExprs[INIT] = init;
|
||||
SubExprs[COND] = cond;
|
||||
SubExprs[BODY] = nullptr;
|
||||
}
|
||||
|
|
|
@ -239,7 +239,8 @@ static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) {
|
|||
SourceLocation());
|
||||
|
||||
// (5) Create the 'if' statement.
|
||||
IfStmt *If = new (C) IfStmt(C, SourceLocation(), false, nullptr, UO, CS);
|
||||
IfStmt *If = new (C) IfStmt(C, SourceLocation(), false, nullptr, nullptr,
|
||||
UO, CS);
|
||||
return If;
|
||||
}
|
||||
|
||||
|
@ -342,9 +343,8 @@ static Stmt *create_OSAtomicCompareAndSwap(ASTContext &C, const FunctionDecl *D)
|
|||
Stmt *Else = M.makeReturn(RetVal);
|
||||
|
||||
/// Construct the If.
|
||||
Stmt *If =
|
||||
new (C) IfStmt(C, SourceLocation(), false, nullptr, Comparison, Body,
|
||||
SourceLocation(), Else);
|
||||
Stmt *If = new (C) IfStmt(C, SourceLocation(), false, nullptr, nullptr,
|
||||
Comparison, Body, SourceLocation(), Else);
|
||||
|
||||
return If;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//===--- CFG.cpp - Classes for representing and building CFGs----*- C++ -*-===//
|
||||
//===--- CFG.cpp - Classes for representing and building CFGs----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
|
@ -1945,7 +1945,8 @@ CFGBlock *CFGBuilder::VisitCompoundStmt(CompoundStmt *C) {
|
|||
addLocalScopeForStmt(C);
|
||||
}
|
||||
if (!C->body_empty() && !isa<ReturnStmt>(*C->body_rbegin())) {
|
||||
// If the body ends with a ReturnStmt, the dtors will be added in VisitReturnStmt
|
||||
// If the body ends with a ReturnStmt, the dtors will be added in
|
||||
// VisitReturnStmt.
|
||||
addAutomaticObjDtors(ScopePos, scopeBeginPos, C);
|
||||
}
|
||||
|
||||
|
@ -2168,6 +2169,13 @@ CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) {
|
|||
// won't be restored when traversing AST.
|
||||
SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos);
|
||||
|
||||
// Create local scope for C++17 if init-stmt if one exists.
|
||||
if (Stmt *Init = I->getInit()) {
|
||||
LocalScope::const_iterator BeginScopePos = ScopePos;
|
||||
addLocalScopeForStmt(Init);
|
||||
addAutomaticObjDtors(ScopePos, BeginScopePos, I);
|
||||
}
|
||||
|
||||
// Create local scope for possible condition variable.
|
||||
// Store scope position. Add implicit destructor.
|
||||
if (VarDecl *VD = I->getConditionVariable()) {
|
||||
|
@ -2268,13 +2276,19 @@ CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) {
|
|||
// blocks will be pointed to be "Block".
|
||||
CFGBlock *LastBlock = addStmt(I->getCond());
|
||||
|
||||
// Finally, if the IfStmt contains a condition variable, add it and its
|
||||
// If the IfStmt contains a condition variable, add it and its
|
||||
// initializer to the CFG.
|
||||
if (const DeclStmt* DS = I->getConditionVariableDeclStmt()) {
|
||||
autoCreateBlock();
|
||||
LastBlock = addStmt(const_cast<DeclStmt *>(DS));
|
||||
}
|
||||
|
||||
// Finally, if the IfStmt contains a C++17 init-stmt, add it to the CFG.
|
||||
if (Stmt *Init = I->getInit()) {
|
||||
autoCreateBlock();
|
||||
LastBlock = addStmt(Init);
|
||||
}
|
||||
|
||||
return LastBlock;
|
||||
}
|
||||
|
||||
|
@ -3059,6 +3073,13 @@ CFGBlock *CFGBuilder::VisitSwitchStmt(SwitchStmt *Terminator) {
|
|||
// won't be restored when traversing AST.
|
||||
SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos);
|
||||
|
||||
// Create local scope for C++17 switch init-stmt if one exists.
|
||||
if (Stmt *Init = Terminator->getInit()) {
|
||||
LocalScope::const_iterator BeginScopePos = ScopePos;
|
||||
addLocalScopeForStmt(Init);
|
||||
addAutomaticObjDtors(ScopePos, BeginScopePos, Terminator);
|
||||
}
|
||||
|
||||
// Create local scope for possible condition variable.
|
||||
// Store scope position. Add implicit destructor.
|
||||
if (VarDecl *VD = Terminator->getConditionVariable()) {
|
||||
|
@ -3138,7 +3159,7 @@ CFGBlock *CFGBuilder::VisitSwitchStmt(SwitchStmt *Terminator) {
|
|||
Block = SwitchTerminatedBlock;
|
||||
CFGBlock *LastBlock = addStmt(Terminator->getCond());
|
||||
|
||||
// Finally, if the SwitchStmt contains a condition variable, add both the
|
||||
// If the SwitchStmt contains a condition variable, add both the
|
||||
// SwitchStmt and the condition variable initialization to the CFG.
|
||||
if (VarDecl *VD = Terminator->getConditionVariable()) {
|
||||
if (Expr *Init = VD->getInit()) {
|
||||
|
@ -3148,6 +3169,12 @@ CFGBlock *CFGBuilder::VisitSwitchStmt(SwitchStmt *Terminator) {
|
|||
}
|
||||
}
|
||||
|
||||
// Finally, if the SwitchStmt contains a C++17 init-stmt, add it to the CFG.
|
||||
if (Stmt *Init = Terminator->getInit()) {
|
||||
autoCreateBlock();
|
||||
LastBlock = addStmt(Init);
|
||||
}
|
||||
|
||||
return LastBlock;
|
||||
}
|
||||
|
||||
|
|
|
@ -568,6 +568,9 @@ void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
|
|||
// unequal to 0. The condition must be a scalar type.
|
||||
LexicalScope ConditionScope(*this, S.getCond()->getSourceRange());
|
||||
|
||||
if (S.getInit())
|
||||
EmitStmt(S.getInit());
|
||||
|
||||
if (S.getConditionVariable())
|
||||
EmitAutoVarDecl(*S.getConditionVariable());
|
||||
|
||||
|
@ -1484,6 +1487,9 @@ void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) {
|
|||
incrementProfileCounter(Case);
|
||||
RunCleanupsScope ExecutedScope(*this);
|
||||
|
||||
if (S.getInit())
|
||||
EmitStmt(S.getInit());
|
||||
|
||||
// Emit the condition variable if needed inside the entire cleanup scope
|
||||
// used by this special case for constant folded switches.
|
||||
if (S.getConditionVariable())
|
||||
|
@ -1511,6 +1517,10 @@ void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) {
|
|||
JumpDest SwitchExit = getJumpDestInCurrentScope("sw.epilog");
|
||||
|
||||
RunCleanupsScope ConditionScope(*this);
|
||||
|
||||
if (S.getInit())
|
||||
EmitStmt(S.getInit());
|
||||
|
||||
if (S.getConditionVariable())
|
||||
EmitAutoVarDecl(*S.getConditionVariable());
|
||||
llvm::Value *CondV = EmitScalarExpr(S.getCond());
|
||||
|
|
|
@ -279,7 +279,7 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S,
|
|||
unsigned &ParentScope = ((isa<Expr>(S) && !isa<StmtExpr>(S))
|
||||
? origParentScope : independentParentScope);
|
||||
|
||||
bool SkipFirstSubStmt = false;
|
||||
unsigned StmtsToSkip = 0u;
|
||||
|
||||
// If we found a label, remember that it is in ParentScope scope.
|
||||
switch (S->getStmtClass()) {
|
||||
|
@ -304,11 +304,15 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S,
|
|||
break;
|
||||
|
||||
case Stmt::SwitchStmtClass:
|
||||
// Evaluate the condition variable before entering the scope of the switch
|
||||
// statement.
|
||||
// Evaluate the C++17 init stmt and condition variable
|
||||
// before entering the scope of the switch statement.
|
||||
if (Stmt *Init = cast<SwitchStmt>(S)->getInit()) {
|
||||
BuildScopeInformation(Init, ParentScope);
|
||||
++StmtsToSkip;
|
||||
}
|
||||
if (VarDecl *Var = cast<SwitchStmt>(S)->getConditionVariable()) {
|
||||
BuildScopeInformation(Var, ParentScope);
|
||||
SkipFirstSubStmt = true;
|
||||
++StmtsToSkip;
|
||||
}
|
||||
// Fall through
|
||||
|
||||
|
@ -537,13 +541,13 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S,
|
|||
}
|
||||
|
||||
for (Stmt *SubStmt : S->children()) {
|
||||
if (SkipFirstSubStmt) {
|
||||
SkipFirstSubStmt = false;
|
||||
if (!SubStmt)
|
||||
continue;
|
||||
if (StmtsToSkip) {
|
||||
--StmtsToSkip;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!SubStmt) continue;
|
||||
|
||||
// Cases, labels, and defaults aren't "scope parents". It's also
|
||||
// important to handle these iteratively instead of recursively in
|
||||
// order to avoid blowing out the stack.
|
||||
|
|
|
@ -508,9 +508,6 @@ Sema::ActOnIfStmt(SourceLocation IfLoc, bool IsConstexpr, Stmt *InitStmt,
|
|||
ConditionResult Cond,
|
||||
Stmt *thenStmt, SourceLocation ElseLoc,
|
||||
Stmt *elseStmt) {
|
||||
if (InitStmt)
|
||||
Diag(InitStmt->getLocStart(), diag::err_init_stmt_not_supported);
|
||||
|
||||
if (Cond.isInvalid())
|
||||
Cond = ConditionResult(
|
||||
*this, nullptr,
|
||||
|
@ -528,12 +525,14 @@ Sema::ActOnIfStmt(SourceLocation IfLoc, bool IsConstexpr, Stmt *InitStmt,
|
|||
DiagnoseEmptyStmtBody(CondExpr->getLocEnd(), thenStmt,
|
||||
diag::warn_empty_if_body);
|
||||
|
||||
return BuildIfStmt(IfLoc, IsConstexpr, Cond, thenStmt, ElseLoc, elseStmt);
|
||||
return BuildIfStmt(IfLoc, IsConstexpr, InitStmt, Cond, thenStmt, ElseLoc,
|
||||
elseStmt);
|
||||
}
|
||||
|
||||
StmtResult Sema::BuildIfStmt(SourceLocation IfLoc, bool IsConstexpr,
|
||||
ConditionResult Cond, Stmt *thenStmt,
|
||||
SourceLocation ElseLoc, Stmt *elseStmt) {
|
||||
Stmt *InitStmt, ConditionResult Cond,
|
||||
Stmt *thenStmt, SourceLocation ElseLoc,
|
||||
Stmt *elseStmt) {
|
||||
if (Cond.isInvalid())
|
||||
return StmtError();
|
||||
|
||||
|
@ -543,8 +542,9 @@ StmtResult Sema::BuildIfStmt(SourceLocation IfLoc, bool IsConstexpr,
|
|||
DiagnoseUnusedExprResult(thenStmt);
|
||||
DiagnoseUnusedExprResult(elseStmt);
|
||||
|
||||
return new (Context) IfStmt(Context, IfLoc, IsConstexpr, Cond.get().first,
|
||||
Cond.get().second, thenStmt, ElseLoc, elseStmt);
|
||||
return new (Context)
|
||||
IfStmt(Context, IfLoc, IsConstexpr, InitStmt, Cond.get().first,
|
||||
Cond.get().second, thenStmt, ElseLoc, elseStmt);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -668,13 +668,10 @@ StmtResult Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc,
|
|||
if (Cond.isInvalid())
|
||||
return StmtError();
|
||||
|
||||
if (InitStmt)
|
||||
Diag(InitStmt->getLocStart(), diag::err_init_stmt_not_supported);
|
||||
|
||||
getCurFunction()->setHasBranchIntoScope();
|
||||
|
||||
SwitchStmt *SS =
|
||||
new (Context) SwitchStmt(Context, Cond.get().first, Cond.get().second);
|
||||
SwitchStmt *SS = new (Context)
|
||||
SwitchStmt(Context, InitStmt, Cond.get().first, Cond.get().second);
|
||||
getCurFunction()->SwitchStack.push_back(SS);
|
||||
return SS;
|
||||
}
|
||||
|
|
|
@ -1174,9 +1174,9 @@ public:
|
|||
/// By default, performs semantic analysis to build the new statement.
|
||||
/// Subclasses may override this routine to provide different behavior.
|
||||
StmtResult RebuildIfStmt(SourceLocation IfLoc, bool IsConstexpr,
|
||||
Sema::ConditionResult Cond, Stmt *Then,
|
||||
Sema::ConditionResult Cond, Stmt *Init, Stmt *Then,
|
||||
SourceLocation ElseLoc, Stmt *Else) {
|
||||
return getSema().ActOnIfStmt(IfLoc, IsConstexpr, nullptr, Cond, Then,
|
||||
return getSema().ActOnIfStmt(IfLoc, IsConstexpr, Init, Cond, Then,
|
||||
ElseLoc, Else);
|
||||
}
|
||||
|
||||
|
@ -1184,9 +1184,9 @@ public:
|
|||
///
|
||||
/// By default, performs semantic analysis to build the new statement.
|
||||
/// Subclasses may override this routine to provide different behavior.
|
||||
StmtResult RebuildSwitchStmtStart(SourceLocation SwitchLoc,
|
||||
StmtResult RebuildSwitchStmtStart(SourceLocation SwitchLoc, Stmt *Init,
|
||||
Sema::ConditionResult Cond) {
|
||||
return getSema().ActOnStartOfSwitchStmt(SwitchLoc, nullptr, Cond);
|
||||
return getSema().ActOnStartOfSwitchStmt(SwitchLoc, Init, Cond);
|
||||
}
|
||||
|
||||
/// \brief Attach the body to the switch statement.
|
||||
|
@ -6266,6 +6266,11 @@ StmtResult TreeTransform<Derived>::TransformAttributedStmt(AttributedStmt *S) {
|
|||
template<typename Derived>
|
||||
StmtResult
|
||||
TreeTransform<Derived>::TransformIfStmt(IfStmt *S) {
|
||||
// Transform the initialization statement
|
||||
StmtResult Init = getDerived().TransformStmt(S->getInit());
|
||||
if (Init.isInvalid())
|
||||
return StmtError();
|
||||
|
||||
// Transform the condition
|
||||
Sema::ConditionResult Cond = getDerived().TransformCondition(
|
||||
S->getIfLoc(), S->getConditionVariable(), S->getCond(),
|
||||
|
@ -6298,18 +6303,25 @@ TreeTransform<Derived>::TransformIfStmt(IfStmt *S) {
|
|||
}
|
||||
|
||||
if (!getDerived().AlwaysRebuild() &&
|
||||
Init.get() == S->getInit() &&
|
||||
Cond.get() == std::make_pair(S->getConditionVariable(), S->getCond()) &&
|
||||
Then.get() == S->getThen() &&
|
||||
Else.get() == S->getElse())
|
||||
return S;
|
||||
|
||||
return getDerived().RebuildIfStmt(S->getIfLoc(), S->isConstexpr(), Cond,
|
||||
Then.get(), S->getElseLoc(), Else.get());
|
||||
Init.get(), Then.get(), S->getElseLoc(),
|
||||
Else.get());
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
StmtResult
|
||||
TreeTransform<Derived>::TransformSwitchStmt(SwitchStmt *S) {
|
||||
// Transform the initialization statement
|
||||
StmtResult Init = getDerived().TransformStmt(S->getInit());
|
||||
if (Init.isInvalid())
|
||||
return StmtError();
|
||||
|
||||
// Transform the condition.
|
||||
Sema::ConditionResult Cond = getDerived().TransformCondition(
|
||||
S->getSwitchLoc(), S->getConditionVariable(), S->getCond(),
|
||||
|
@ -6319,7 +6331,8 @@ TreeTransform<Derived>::TransformSwitchStmt(SwitchStmt *S) {
|
|||
|
||||
// Rebuild the switch statement.
|
||||
StmtResult Switch
|
||||
= getDerived().RebuildSwitchStmtStart(S->getSwitchLoc(), Cond);
|
||||
= getDerived().RebuildSwitchStmtStart(S->getSwitchLoc(),
|
||||
S->getInit(), Cond);
|
||||
if (Switch.isInvalid())
|
||||
return StmtError();
|
||||
|
||||
|
|
|
@ -185,6 +185,7 @@ void ASTStmtReader::VisitAttributedStmt(AttributedStmt *S) {
|
|||
void ASTStmtReader::VisitIfStmt(IfStmt *S) {
|
||||
VisitStmt(S);
|
||||
S->setConstexpr(Record[Idx++]);
|
||||
S->setInit(Reader.ReadSubStmt());
|
||||
S->setConditionVariable(Reader.getContext(),
|
||||
ReadDeclAs<VarDecl>(Record, Idx));
|
||||
S->setCond(Reader.ReadSubExpr());
|
||||
|
@ -196,6 +197,7 @@ void ASTStmtReader::VisitIfStmt(IfStmt *S) {
|
|||
|
||||
void ASTStmtReader::VisitSwitchStmt(SwitchStmt *S) {
|
||||
VisitStmt(S);
|
||||
S->setInit(Reader.ReadSubStmt());
|
||||
S->setConditionVariable(Reader.getContext(),
|
||||
ReadDeclAs<VarDecl>(Record, Idx));
|
||||
S->setCond(Reader.ReadSubExpr());
|
||||
|
|
|
@ -129,6 +129,7 @@ void ASTStmtWriter::VisitAttributedStmt(AttributedStmt *S) {
|
|||
void ASTStmtWriter::VisitIfStmt(IfStmt *S) {
|
||||
VisitStmt(S);
|
||||
Record.push_back(S->isConstexpr());
|
||||
Record.AddStmt(S->getInit());
|
||||
Record.AddDeclRef(S->getConditionVariable());
|
||||
Record.AddStmt(S->getCond());
|
||||
Record.AddStmt(S->getThen());
|
||||
|
@ -140,6 +141,7 @@ void ASTStmtWriter::VisitIfStmt(IfStmt *S) {
|
|||
|
||||
void ASTStmtWriter::VisitSwitchStmt(SwitchStmt *S) {
|
||||
VisitStmt(S);
|
||||
Record.AddStmt(S->getInit());
|
||||
Record.AddDeclRef(S->getConditionVariable());
|
||||
Record.AddStmt(S->getCond());
|
||||
Record.AddStmt(S->getBody());
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
// RUN: %clang_cc1 -std=c++1z -triple x86_64-apple-macosx10.7.0 -emit-llvm -o - %s -w | FileCheck %s
|
||||
|
||||
typedef int T;
|
||||
void f() {
|
||||
// CHECK: %[[A:.*]] = alloca i32, align 4
|
||||
// CHECK-NEXT: store i32 5, i32* %[[A]], align 4
|
||||
// CHECK-NEXT: %[[B:.*]] = load i32, i32* %[[A]], align 4
|
||||
// CHECK-NEXT %[[C:.*]] = icmp slt i32 %[[B]], 8
|
||||
if (int a = 5; a < 8)
|
||||
;
|
||||
}
|
||||
|
||||
void f1() {
|
||||
// CHECK: %[[A:.*]] = alloca i32, align 4
|
||||
// CHECK-NEXT: %[[B:.*]] = alloca i32, align 4
|
||||
// CHECK-NEXT: %[[C:.*]] = alloca i32, align 4
|
||||
// CHECK-NEXT: store i32 5, i32* %[[B]], align 4
|
||||
// CHECK-NEXT: store i32 7, i32* %[[C]], align 4
|
||||
if (int a, b = 5; int c = 7)
|
||||
;
|
||||
}
|
||||
|
||||
int f2() {
|
||||
// CHECK: %[[A:.*]] = alloca i32, align 4
|
||||
// CHECK-NEXT: %[[B:.*]] = call i32 @_Z2f2v()
|
||||
// CHECK-NEXT: store i32 7, i32* %[[A]], align 4
|
||||
// CHECK-NEXT: %[[C:.*]] = load i32, i32* %[[A]], align 4
|
||||
// CHECK-NEXT: %[[D:.*]] = icmp ne i32 %[[C]], 0
|
||||
if (T{f2()}; int c = 7)
|
||||
;
|
||||
return 2;
|
||||
}
|
||||
|
||||
void g() {
|
||||
// CHECK: %[[A:.*]] = alloca i32, align 4
|
||||
// CHECK-NEXT: store i32 5, i32* %[[A]], align 4
|
||||
// CHECK-NEXT: %[[B:.*]] = load i32, i32* %[[A]], align 4
|
||||
// CHECK-NEXT: switch i32 %[[B]], label %[[C:.*]] [
|
||||
switch (int a = 5; a) {
|
||||
case 0:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void g1() {
|
||||
// CHECK: %[[A:.*]] = alloca i32, align 4
|
||||
// CHECK-NEXT: %[[B:.*]] = alloca i32, align 4
|
||||
// CHECK-NEXT: %[[C:.*]] = alloca i32, align 4
|
||||
// CHECK-NEXT: store i32 5, i32* %[[B]], align 4
|
||||
// CHECK-NEXT: store i32 7, i32* %[[C]], align 4
|
||||
// CHECK-NEXT: %[[D:.*]] = load i32, i32* %[[C]], align 4
|
||||
// CHECK-NEXT: switch i32 %[[D]], label %[[E:.*]] [
|
||||
switch (int a, b = 5; int c = 7) {
|
||||
case 0:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int g2() {
|
||||
// CHECK: %[[A:.*]] = alloca i32, align 4
|
||||
// CHECK-NEXT: %[[B:.*]] = call i32 @_Z2f2v()
|
||||
// CHECK-NEXT: store i32 7, i32* %[[A]], align 4
|
||||
// CHECK-NEXT: %[[C:.*]] = load i32, i32* %[[A]], align 4
|
||||
// CHECK-NEXT: switch i32 %[[C]], label %[[E:.*]] [
|
||||
switch (T{f2()}; int c = 7) {
|
||||
case 0:
|
||||
break;
|
||||
}
|
||||
return 2;
|
||||
}
|
|
@ -34,6 +34,7 @@ int g(int i) {
|
|||
// CHECK-NEXT: `-CompoundStmt
|
||||
// CHECK-NEXT: `-IfStmt {{.*}} <line:25:3, line:28:12>
|
||||
// CHECK-NEXT: |-<<<NULL>>>
|
||||
// CHECK-NEXT: |-<<<NULL>>>
|
||||
// CHECK-NEXT: |-OpaqueValueExpr {{.*}} <<invalid sloc>> '_Bool'
|
||||
// CHECK-NEXT: |-ReturnStmt {{.*}} <line:26:5, col:12>
|
||||
// CHECK-NEXT: | `-IntegerLiteral {{.*}} <col:12> 'int' 4
|
||||
|
@ -41,7 +42,6 @@ int g(int i) {
|
|||
// CHECK-NEXT: `-ImplicitCastExpr {{.*}} <col:12> 'int' <LValueToRValue>
|
||||
// CHECK-NEXT: `-DeclRefExpr {{.*}} <col:12> 'int' lvalue ParmVar {{.*}} 'i' 'int'
|
||||
|
||||
|
||||
namespace TestInvalidFunctionDecl {
|
||||
struct Str {
|
||||
double foo1(double, invalid_type);
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
// Test this without pch.
|
||||
// RUN: %clang_cc1 -std=c++1z -include %S/cxx1z-init-statement.h -fsyntax-only -emit-llvm -o - %s
|
||||
|
||||
// Test with pch.
|
||||
// RUN: %clang_cc1 -x c++ -std=c++1z -emit-pch -o %t %S/cxx1z-init-statement.h
|
||||
// RUN: %clang_cc1 -std=c++1z -include-pch %t -fsyntax-only -emit-llvm -o - %s
|
||||
|
||||
void g0(void) {
|
||||
static_assert(test_if(-1) == -1, "");
|
||||
static_assert(test_if(0) == 0, "");
|
||||
}
|
||||
|
||||
void g1(void) {
|
||||
static_assert(test_switch(-1) == -1, "");
|
||||
static_assert(test_switch(0) == 0, "");
|
||||
static_assert(test_switch(1) == 1, "");
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
// Header for PCH test cxx1z-init-statement.cpp
|
||||
|
||||
constexpr int test_if(int x) {
|
||||
if (int a = ++x; a == 0) {
|
||||
return -1;
|
||||
} else if (++a; a == 2) {
|
||||
return 0;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
|
||||
constexpr int test_switch(int x) {
|
||||
switch (int a = ++x; a) {
|
||||
case 0:
|
||||
return -1;
|
||||
case 1:
|
||||
return 0;
|
||||
case 2:
|
||||
return 1;
|
||||
}
|
||||
return 2;
|
||||
}
|
|
@ -4,18 +4,18 @@ int g, h;
|
|||
typedef int T;
|
||||
int f() {
|
||||
// init-statement declarations
|
||||
if (T n = 0; n != 0) {} // expected-error {{not yet supported}}
|
||||
if (T f(); f()) {} // expected-error {{not yet supported}}
|
||||
if (T(f()); f()) {} // expected-error {{not yet supported}}
|
||||
if (T(f()), g, h; f()) {} // expected-error {{not yet supported}}
|
||||
if (T f(); f()) {} // expected-error {{not yet supported}}
|
||||
if (T f(), g, h; f()) {} // expected-error {{not yet supported}}
|
||||
if (T(n) = 0; n) {} // expected-error {{not yet supported}}
|
||||
if (T n = 0; n != 0) {}
|
||||
if (T f(); f()) {}
|
||||
if (T(f()); f()) {}
|
||||
if (T(f()), g, h; f()) {}
|
||||
if (T f(); f()) {}
|
||||
if (T f(), g, h; f()) {}
|
||||
if (T(n) = 0; n) {}
|
||||
|
||||
// init-statement expressions
|
||||
if (T{f()}; f()) {} // expected-error {{not yet supported}}
|
||||
if (T{f()}, g, h; f()) {} // expected-error {{not yet supported}} expected-warning 2{{unused}}
|
||||
if (T(f()), g, h + 1; f()) {} // expected-error {{not yet supported}} expected-warning 2{{unused}}
|
||||
if (T{f()}; f()) {}
|
||||
if (T{f()}, g, h; f()) {} // expected-warning 2{{unused}}
|
||||
if (T(f()), g, h + 1; f()) {} // expected-warning 2{{unused}}
|
||||
|
||||
// condition declarations
|
||||
if (T(n){g}) {}
|
||||
|
@ -34,10 +34,10 @@ int f() {
|
|||
if (T(n)(int())) {} // expected-error {{undeclared identifier 'n'}}
|
||||
|
||||
// Likewise for 'switch'
|
||||
switch (int n; n) {} // expected-error {{not yet supported}}
|
||||
switch (g; int g = 5) {} // expected-error {{not yet supported}}
|
||||
switch (int n; n) {}
|
||||
switch (g; int g = 5) {}
|
||||
|
||||
if (int a, b; int c = a) { // expected-error {{not yet supported}} expected-note 6{{previous}}
|
||||
if (int a, b; int c = a) { // expected-note 6{{previous}}
|
||||
int a; // expected-error {{redefinition}}
|
||||
int b; // expected-error {{redefinition}}
|
||||
int c; // expected-error {{redefinition}}
|
||||
|
@ -46,4 +46,6 @@ int f() {
|
|||
int b; // expected-error {{redefinition}}
|
||||
int c; // expected-error {{redefinition}}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
// RUN: %clang_cc1 -std=c++1z -verify -Wuninitialized %s
|
||||
|
||||
void testIf() {
|
||||
if (bool b; b) // expected-warning {{uninitialized}} expected-note {{to silence}}
|
||||
;
|
||||
if (int a, b = 2; a) // expected-warning {{uninitialized}} expected-note {{to silence}}
|
||||
;
|
||||
int a;
|
||||
if (a = 0; a) {} // OK
|
||||
}
|
||||
|
||||
void testSwitch() {
|
||||
switch (bool b; b) { // expected-warning {{uninitialized}} expected-warning {{boolean value}} expected-note {{to silence}}
|
||||
case 0:
|
||||
break;
|
||||
}
|
||||
switch (int a, b = 7; a) { // expected-warning {{uninitialized}} expected-note {{to silence}}
|
||||
case 0:
|
||||
break;
|
||||
}
|
||||
int c;
|
||||
switch (c = 0; c) { // OK
|
||||
case 0:
|
||||
break;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
// RUN: %clang_cc1 -std=c++1z -verify %s
|
||||
|
||||
void testIf() {
|
||||
int x = 0;
|
||||
if (x; x) ++x;
|
||||
if (int t = 0; t) ++t; else --t;
|
||||
|
||||
if (int x, y = 0; y) // expected-note 2 {{previous definition is here}}
|
||||
int x = 0; // expected-error {{redefinition of 'x'}}
|
||||
else
|
||||
int x = 0; // expected-error {{redefinition of 'x'}}
|
||||
|
||||
if (x; int a = 0) ++a;
|
||||
if (x, +x; int a = 0) // expected-note 2 {{previous definition is here}} expected-warning {{unused}}
|
||||
int a = 0; // expected-error {{redefinition of 'a'}}
|
||||
else
|
||||
int a = 0; // expected-error {{redefinition of 'a'}}
|
||||
|
||||
if (int b = 0; b)
|
||||
;
|
||||
b = 2; // expected-error {{use of undeclared identifier}}
|
||||
}
|
||||
|
||||
void testSwitch() {
|
||||
int x = 0;
|
||||
switch (x; x) {
|
||||
case 1:
|
||||
++x;
|
||||
}
|
||||
|
||||
switch (int x, y = 0; y) {
|
||||
case 1:
|
||||
++x;
|
||||
default:
|
||||
++y;
|
||||
}
|
||||
|
||||
switch (int x, y = 0; y) { // expected-note 2 {{previous definition is here}}
|
||||
case 0:
|
||||
int x = 0; // expected-error {{redefinition of 'x'}}
|
||||
case 1:
|
||||
int y = 0; // expected-error {{redefinition of 'y'}}
|
||||
};
|
||||
|
||||
switch (x; int a = 0) {
|
||||
case 0:
|
||||
++a;
|
||||
}
|
||||
|
||||
switch (x, +x; int a = 0) { // expected-note {{previous definition is here}} expected-warning {{unused}}
|
||||
case 0:
|
||||
int a = 0; // expected-error {{redefinition of 'a'}} // expected-note {{previous definition is here}}
|
||||
case 1:
|
||||
int a = 0; // expected-error {{redefinition of 'a'}}
|
||||
}
|
||||
|
||||
switch (int b = 0; b) {
|
||||
case 0:
|
||||
break;
|
||||
}
|
||||
b = 2; // expected-error {{use of undeclared identifier}}
|
||||
}
|
||||
|
||||
constexpr bool constexpr_if_init(int n) {
|
||||
if (int a = n; ++a > 0)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
constexpr int constexpr_switch_init(int n) {
|
||||
switch (int p = n + 2; p) {
|
||||
case 0:
|
||||
return 0;
|
||||
case 1:
|
||||
return 1;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
void test_constexpr_init_stmt() {
|
||||
constexpr bool a = constexpr_if_init(-2);
|
||||
static_assert(!a, "");
|
||||
static_assert(constexpr_if_init(1), "");
|
||||
|
||||
constexpr int b = constexpr_switch_init(-1);
|
||||
static_assert(b == 1, "");
|
||||
static_assert(constexpr_switch_init(-2) == 0, "");
|
||||
static_assert(constexpr_switch_init(-5) == -1, "");
|
||||
}
|
|
@ -725,7 +725,7 @@ as the draft C++1z standard evolves.</p>
|
|||
<tr>
|
||||
<td>Separate variable and condition for <tt>if</tt> and <tt>switch</tt></td>
|
||||
<td><a href="http://wg21.link/p0305r1">P0305R1</a></td>
|
||||
<td class="none" align="center">No</td>
|
||||
<td class="svn" align="center">SVN</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
|
Loading…
Reference in New Issue