зеркало из https://github.com/microsoft/clang-1.git
When instantiating statements that involve conditions (if, while, do,
for, and switch), be careful to construct the full expressions as soon as we perform template instantation, so we don't either forget to call temporary destructors or destroy temporaries at the wrong time. This is the template-instantiation analogue to r103187, during which I hadn't realized that the issue would affect the handling of these constructs differently inside and outside of templates. Fixes a regression in Boost.Function. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@103357 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
20fba8ad3f
Коммит
eaa18e449b
|
@ -758,21 +758,10 @@ public:
|
||||||
///
|
///
|
||||||
/// By default, performs semantic analysis to build the new statement.
|
/// By default, performs semantic analysis to build the new statement.
|
||||||
/// Subclasses may override this routine to provide different behavior.
|
/// Subclasses may override this routine to provide different behavior.
|
||||||
OwningStmtResult RebuildIfStmt(SourceLocation IfLoc, Sema::ExprArg Cond,
|
OwningStmtResult RebuildIfStmt(SourceLocation IfLoc, Sema::FullExprArg Cond,
|
||||||
VarDecl *CondVar, StmtArg Then,
|
VarDecl *CondVar, StmtArg Then,
|
||||||
SourceLocation ElseLoc, StmtArg Else) {
|
SourceLocation ElseLoc, StmtArg Else) {
|
||||||
if (Cond.get()) {
|
return getSema().ActOnIfStmt(IfLoc, Cond, DeclPtrTy::make(CondVar),
|
||||||
// Convert the condition to a boolean value.
|
|
||||||
OwningExprResult CondE = getSema().ActOnBooleanCondition(0, IfLoc,
|
|
||||||
move(Cond));
|
|
||||||
if (CondE.isInvalid())
|
|
||||||
return getSema().StmtError();
|
|
||||||
|
|
||||||
Cond = move(CondE);
|
|
||||||
}
|
|
||||||
|
|
||||||
Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond));
|
|
||||||
return getSema().ActOnIfStmt(IfLoc, FullCond, DeclPtrTy::make(CondVar),
|
|
||||||
move(Then), ElseLoc, move(Else));
|
move(Then), ElseLoc, move(Else));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -802,20 +791,10 @@ public:
|
||||||
/// By default, performs semantic analysis to build the new statement.
|
/// By default, performs semantic analysis to build the new statement.
|
||||||
/// Subclasses may override this routine to provide different behavior.
|
/// Subclasses may override this routine to provide different behavior.
|
||||||
OwningStmtResult RebuildWhileStmt(SourceLocation WhileLoc,
|
OwningStmtResult RebuildWhileStmt(SourceLocation WhileLoc,
|
||||||
Sema::ExprArg Cond,
|
Sema::FullExprArg Cond,
|
||||||
VarDecl *CondVar,
|
VarDecl *CondVar,
|
||||||
StmtArg Body) {
|
StmtArg Body) {
|
||||||
if (Cond.get()) {
|
return getSema().ActOnWhileStmt(WhileLoc, Cond,
|
||||||
// Convert the condition to a boolean value.
|
|
||||||
OwningExprResult CondE = getSema().ActOnBooleanCondition(0, WhileLoc,
|
|
||||||
move(Cond));
|
|
||||||
if (CondE.isInvalid())
|
|
||||||
return getSema().StmtError();
|
|
||||||
Cond = move(CondE);
|
|
||||||
}
|
|
||||||
|
|
||||||
Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond));
|
|
||||||
return getSema().ActOnWhileStmt(WhileLoc, FullCond,
|
|
||||||
DeclPtrTy::make(CondVar), move(Body));
|
DeclPtrTy::make(CondVar), move(Body));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -838,21 +817,10 @@ public:
|
||||||
/// Subclasses may override this routine to provide different behavior.
|
/// Subclasses may override this routine to provide different behavior.
|
||||||
OwningStmtResult RebuildForStmt(SourceLocation ForLoc,
|
OwningStmtResult RebuildForStmt(SourceLocation ForLoc,
|
||||||
SourceLocation LParenLoc,
|
SourceLocation LParenLoc,
|
||||||
StmtArg Init, Sema::ExprArg Cond,
|
StmtArg Init, Sema::FullExprArg Cond,
|
||||||
VarDecl *CondVar, Sema::FullExprArg Inc,
|
VarDecl *CondVar, Sema::FullExprArg Inc,
|
||||||
SourceLocation RParenLoc, StmtArg Body) {
|
SourceLocation RParenLoc, StmtArg Body) {
|
||||||
if (Cond.get()) {
|
return getSema().ActOnForStmt(ForLoc, LParenLoc, move(Init), Cond,
|
||||||
// Convert the condition to a boolean value.
|
|
||||||
OwningExprResult CondE = getSema().ActOnBooleanCondition(0, ForLoc,
|
|
||||||
move(Cond));
|
|
||||||
if (CondE.isInvalid())
|
|
||||||
return getSema().StmtError();
|
|
||||||
|
|
||||||
Cond = move(CondE);
|
|
||||||
}
|
|
||||||
|
|
||||||
Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond));
|
|
||||||
return getSema().ActOnForStmt(ForLoc, LParenLoc, move(Init), FullCond,
|
|
||||||
DeclPtrTy::make(CondVar),
|
DeclPtrTy::make(CondVar),
|
||||||
Inc, RParenLoc, move(Body));
|
Inc, RParenLoc, move(Body));
|
||||||
}
|
}
|
||||||
|
@ -3523,8 +3491,20 @@ TreeTransform<Derived>::TransformIfStmt(IfStmt *S) {
|
||||||
|
|
||||||
if (Cond.isInvalid())
|
if (Cond.isInvalid())
|
||||||
return SemaRef.StmtError();
|
return SemaRef.StmtError();
|
||||||
|
|
||||||
|
// Convert the condition to a boolean value.
|
||||||
|
OwningExprResult CondE = getSema().ActOnBooleanCondition(0, S->getIfLoc(),
|
||||||
|
move(Cond));
|
||||||
|
if (CondE.isInvalid())
|
||||||
|
return getSema().StmtError();
|
||||||
|
|
||||||
|
Cond = move(CondE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond));
|
||||||
|
if (!S->getConditionVariable() && S->getCond() && !FullCond->get())
|
||||||
|
return SemaRef.StmtError();
|
||||||
|
|
||||||
// Transform the "then" branch.
|
// Transform the "then" branch.
|
||||||
OwningStmtResult Then = getDerived().TransformStmt(S->getThen());
|
OwningStmtResult Then = getDerived().TransformStmt(S->getThen());
|
||||||
if (Then.isInvalid())
|
if (Then.isInvalid())
|
||||||
|
@ -3536,13 +3516,13 @@ TreeTransform<Derived>::TransformIfStmt(IfStmt *S) {
|
||||||
return SemaRef.StmtError();
|
return SemaRef.StmtError();
|
||||||
|
|
||||||
if (!getDerived().AlwaysRebuild() &&
|
if (!getDerived().AlwaysRebuild() &&
|
||||||
Cond.get() == S->getCond() &&
|
FullCond->get() == S->getCond() &&
|
||||||
ConditionVar == S->getConditionVariable() &&
|
ConditionVar == S->getConditionVariable() &&
|
||||||
Then.get() == S->getThen() &&
|
Then.get() == S->getThen() &&
|
||||||
Else.get() == S->getElse())
|
Else.get() == S->getElse())
|
||||||
return SemaRef.Owned(S->Retain());
|
return SemaRef.Owned(S->Retain());
|
||||||
|
|
||||||
return getDerived().RebuildIfStmt(S->getIfLoc(), move(Cond), ConditionVar,
|
return getDerived().RebuildIfStmt(S->getIfLoc(), FullCond, ConditionVar,
|
||||||
move(Then),
|
move(Then),
|
||||||
S->getElseLoc(), move(Else));
|
S->getElseLoc(), move(Else));
|
||||||
}
|
}
|
||||||
|
@ -3604,36 +3584,48 @@ TreeTransform<Derived>::TransformWhileStmt(WhileStmt *S) {
|
||||||
|
|
||||||
if (Cond.isInvalid())
|
if (Cond.isInvalid())
|
||||||
return SemaRef.StmtError();
|
return SemaRef.StmtError();
|
||||||
|
|
||||||
|
// Convert the condition to a boolean value.
|
||||||
|
OwningExprResult CondE = getSema().ActOnBooleanCondition(0,
|
||||||
|
S->getWhileLoc(),
|
||||||
|
move(Cond));
|
||||||
|
if (CondE.isInvalid())
|
||||||
|
return getSema().StmtError();
|
||||||
|
Cond = move(CondE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond));
|
||||||
|
if (!S->getConditionVariable() && S->getCond() && !FullCond->get())
|
||||||
|
return SemaRef.StmtError();
|
||||||
|
|
||||||
// Transform the body
|
// Transform the body
|
||||||
OwningStmtResult Body = getDerived().TransformStmt(S->getBody());
|
OwningStmtResult Body = getDerived().TransformStmt(S->getBody());
|
||||||
if (Body.isInvalid())
|
if (Body.isInvalid())
|
||||||
return SemaRef.StmtError();
|
return SemaRef.StmtError();
|
||||||
|
|
||||||
if (!getDerived().AlwaysRebuild() &&
|
if (!getDerived().AlwaysRebuild() &&
|
||||||
Cond.get() == S->getCond() &&
|
FullCond->get() == S->getCond() &&
|
||||||
ConditionVar == S->getConditionVariable() &&
|
ConditionVar == S->getConditionVariable() &&
|
||||||
Body.get() == S->getBody())
|
Body.get() == S->getBody())
|
||||||
return SemaRef.Owned(S->Retain());
|
return SemaRef.Owned(S->Retain());
|
||||||
|
|
||||||
return getDerived().RebuildWhileStmt(S->getWhileLoc(), move(Cond),
|
return getDerived().RebuildWhileStmt(S->getWhileLoc(), FullCond,
|
||||||
ConditionVar, move(Body));
|
ConditionVar, move(Body));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Derived>
|
template<typename Derived>
|
||||||
Sema::OwningStmtResult
|
Sema::OwningStmtResult
|
||||||
TreeTransform<Derived>::TransformDoStmt(DoStmt *S) {
|
TreeTransform<Derived>::TransformDoStmt(DoStmt *S) {
|
||||||
// Transform the condition
|
|
||||||
OwningExprResult Cond = getDerived().TransformExpr(S->getCond());
|
|
||||||
if (Cond.isInvalid())
|
|
||||||
return SemaRef.StmtError();
|
|
||||||
|
|
||||||
// Transform the body
|
// Transform the body
|
||||||
OwningStmtResult Body = getDerived().TransformStmt(S->getBody());
|
OwningStmtResult Body = getDerived().TransformStmt(S->getBody());
|
||||||
if (Body.isInvalid())
|
if (Body.isInvalid())
|
||||||
return SemaRef.StmtError();
|
return SemaRef.StmtError();
|
||||||
|
|
||||||
|
// Transform the condition
|
||||||
|
OwningExprResult Cond = getDerived().TransformExpr(S->getCond());
|
||||||
|
if (Cond.isInvalid())
|
||||||
|
return SemaRef.StmtError();
|
||||||
|
|
||||||
if (!getDerived().AlwaysRebuild() &&
|
if (!getDerived().AlwaysRebuild() &&
|
||||||
Cond.get() == S->getCond() &&
|
Cond.get() == S->getCond() &&
|
||||||
Body.get() == S->getBody())
|
Body.get() == S->getBody())
|
||||||
|
@ -3668,13 +3660,29 @@ TreeTransform<Derived>::TransformForStmt(ForStmt *S) {
|
||||||
|
|
||||||
if (Cond.isInvalid())
|
if (Cond.isInvalid())
|
||||||
return SemaRef.StmtError();
|
return SemaRef.StmtError();
|
||||||
|
|
||||||
|
// Convert the condition to a boolean value.
|
||||||
|
OwningExprResult CondE = getSema().ActOnBooleanCondition(0, S->getForLoc(),
|
||||||
|
move(Cond));
|
||||||
|
if (CondE.isInvalid())
|
||||||
|
return getSema().StmtError();
|
||||||
|
|
||||||
|
Cond = move(CondE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond));
|
||||||
|
if (!S->getConditionVariable() && S->getCond() && !FullCond->get())
|
||||||
|
return SemaRef.StmtError();
|
||||||
|
|
||||||
// Transform the increment
|
// Transform the increment
|
||||||
OwningExprResult Inc = getDerived().TransformExpr(S->getInc());
|
OwningExprResult Inc = getDerived().TransformExpr(S->getInc());
|
||||||
if (Inc.isInvalid())
|
if (Inc.isInvalid())
|
||||||
return SemaRef.StmtError();
|
return SemaRef.StmtError();
|
||||||
|
|
||||||
|
Sema::FullExprArg FullInc(getSema().MakeFullExpr(Inc));
|
||||||
|
if (S->getInc() && !FullInc->get())
|
||||||
|
return SemaRef.StmtError();
|
||||||
|
|
||||||
// Transform the body
|
// Transform the body
|
||||||
OwningStmtResult Body = getDerived().TransformStmt(S->getBody());
|
OwningStmtResult Body = getDerived().TransformStmt(S->getBody());
|
||||||
if (Body.isInvalid())
|
if (Body.isInvalid())
|
||||||
|
@ -3682,15 +3690,14 @@ TreeTransform<Derived>::TransformForStmt(ForStmt *S) {
|
||||||
|
|
||||||
if (!getDerived().AlwaysRebuild() &&
|
if (!getDerived().AlwaysRebuild() &&
|
||||||
Init.get() == S->getInit() &&
|
Init.get() == S->getInit() &&
|
||||||
Cond.get() == S->getCond() &&
|
FullCond->get() == S->getCond() &&
|
||||||
Inc.get() == S->getInc() &&
|
Inc.get() == S->getInc() &&
|
||||||
Body.get() == S->getBody())
|
Body.get() == S->getBody())
|
||||||
return SemaRef.Owned(S->Retain());
|
return SemaRef.Owned(S->Retain());
|
||||||
|
|
||||||
return getDerived().RebuildForStmt(S->getForLoc(), S->getLParenLoc(),
|
return getDerived().RebuildForStmt(S->getForLoc(), S->getLParenLoc(),
|
||||||
move(Init), move(Cond), ConditionVar,
|
move(Init), FullCond, ConditionVar,
|
||||||
getSema().MakeFullExpr(Inc),
|
FullInc, S->getRParenLoc(), move(Body));
|
||||||
S->getRParenLoc(), move(Body));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Derived>
|
template<typename Derived>
|
||||||
|
|
|
@ -14,6 +14,7 @@ void h() {
|
||||||
|
|
||||||
struct X {
|
struct X {
|
||||||
X();
|
X();
|
||||||
|
X(const X&);
|
||||||
~X();
|
~X();
|
||||||
operator bool();
|
operator bool();
|
||||||
};
|
};
|
||||||
|
@ -171,3 +172,81 @@ void do_destruct(int z) {
|
||||||
z = 99;
|
z = 99;
|
||||||
// CHECK: ret
|
// CHECK: ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int f(X);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
int instantiated(T x) {
|
||||||
|
int result;
|
||||||
|
|
||||||
|
// CHECK: call void @_ZN1XC1ERKS_
|
||||||
|
// CHECK: call i32 @_Z1f1X
|
||||||
|
// CHECK: call void @_ZN1XD1Ev
|
||||||
|
// CHECK: br
|
||||||
|
// CHECK: store i32 2
|
||||||
|
// CHECK: br
|
||||||
|
// CHECK: store i32 3
|
||||||
|
if (f(x)) { result = 2; } else { result = 3; }
|
||||||
|
|
||||||
|
// CHECK: call void @_ZN1XC1ERKS_
|
||||||
|
// CHECK: call i32 @_Z1f1X
|
||||||
|
// CHECK: call void @_ZN1XD1Ev
|
||||||
|
// CHECK: br
|
||||||
|
// CHECK: store i32 4
|
||||||
|
// CHECK: br
|
||||||
|
while (f(x)) { result = 4; }
|
||||||
|
|
||||||
|
// CHECK: call void @_ZN1XC1ERKS_
|
||||||
|
// CHECK: call i32 @_Z1f1X
|
||||||
|
// CHECK: call void @_ZN1XD1Ev
|
||||||
|
// CHECK: br
|
||||||
|
// CHECK: store i32 6
|
||||||
|
// CHECK: br
|
||||||
|
// CHECK: call void @_ZN1XC1ERKS_
|
||||||
|
// CHECK: call i32 @_Z1f1X
|
||||||
|
// CHECK: store i32 5
|
||||||
|
// CHECK: call void @_ZN1XD1Ev
|
||||||
|
// CHECK: br
|
||||||
|
for (; f(x); f(x), result = 5) {
|
||||||
|
result = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: call void @_ZN1XC1ERKS_
|
||||||
|
// CHECK: call i32 @_Z1f1X
|
||||||
|
// CHECK: call void @_ZN1XD1Ev
|
||||||
|
// CHECK: switch i32
|
||||||
|
// CHECK: store i32 7
|
||||||
|
// CHECK: store i32 8
|
||||||
|
switch (f(x)) {
|
||||||
|
case 0:
|
||||||
|
result = 7;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
result = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: store i32 9
|
||||||
|
// CHECK: br
|
||||||
|
// CHECK: call void @_ZN1XC1ERKS_
|
||||||
|
// CHECK: call i32 @_Z1f1X
|
||||||
|
// CHECK: call void @_ZN1XD1Ev
|
||||||
|
// CHECK: br
|
||||||
|
do {
|
||||||
|
result = 9;
|
||||||
|
} while (f(x));
|
||||||
|
|
||||||
|
// CHECK: store i32 10
|
||||||
|
// CHECK: call void @_ZN1XC1ERKS_
|
||||||
|
// CHECK: call zeroext i1 @_ZN1XcvbEv
|
||||||
|
// CHECK: call void @_ZN1XD1Ev
|
||||||
|
// CHECK: br
|
||||||
|
do {
|
||||||
|
result = 10;
|
||||||
|
} while (X(x));
|
||||||
|
|
||||||
|
// CHECK: ret i32
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template int instantiated(X);
|
||||||
|
|
|
@ -63,7 +63,7 @@ template struct Conditional0<int, int, int>;
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct StatementExpr0 {
|
struct StatementExpr0 {
|
||||||
void f(T t) {
|
void f(T t) {
|
||||||
(void)({ if (t) t = t + 17; t + 12;}); // expected-error{{invalid}}
|
(void)({ if (t) t = t + 17; t + 12;}); // expected-error{{contextually convertible}}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче