Establish the iteration variable of an ObjC for-in loop before

emitting the collection expression.  Fixes some really, really broken
code.

llvm-svn: 126193
This commit is contained in:
John McCall 2011-02-22 07:16:58 +00:00
parent 666cf56668
commit 9e2e22f5c6
4 changed files with 39 additions and 13 deletions

View File

@ -782,10 +782,12 @@ static bool isCapturedBy(const VarDecl &var, const Expr *e) {
} }
void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) { void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
assert(emission.Variable && "emission was not valid!");
// If this was emitted as a global constant, we're done. // If this was emitted as a global constant, we're done.
if (emission.wasEmittedAsGlobal()) return; if (emission.wasEmittedAsGlobal()) return;
const VarDecl &D = emission.Variable; const VarDecl &D = *emission.Variable;
QualType type = D.getType(); QualType type = D.getType();
// If this local has an initializer, emit it now. // If this local has an initializer, emit it now.
@ -940,10 +942,12 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
} }
void CodeGenFunction::EmitAutoVarCleanups(const AutoVarEmission &emission) { void CodeGenFunction::EmitAutoVarCleanups(const AutoVarEmission &emission) {
assert(emission.Variable && "emission was not valid!");
// If this was emitted as a global constant, we're done. // If this was emitted as a global constant, we're done.
if (emission.wasEmittedAsGlobal()) return; if (emission.wasEmittedAsGlobal()) return;
const VarDecl &D = emission.Variable; const VarDecl &D = *emission.Variable;
// Handle C++ destruction of variables. // Handle C++ destruction of variables.
if (getLangOptions().CPlusPlus) { if (getLangOptions().CPlusPlus) {

View File

@ -663,6 +663,11 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
return; return;
} }
// The local variable comes into scope immediately.
AutoVarEmission variable = AutoVarEmission::invalid();
if (const DeclStmt *SD = dyn_cast<DeclStmt>(S.getElement()))
variable = EmitAutoVarAlloca(*cast<VarDecl>(SD->getSingleDecl()));
CGDebugInfo *DI = getDebugInfo(); CGDebugInfo *DI = getDebugInfo();
if (DI) { if (DI) {
DI->setLocation(S.getSourceRange().getBegin()); DI->setLocation(S.getSourceRange().getBegin());
@ -799,22 +804,23 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
// Initialize the element variable. // Initialize the element variable.
RunCleanupsScope elementVariableScope(*this); RunCleanupsScope elementVariableScope(*this);
bool elementIsDecl; bool elementIsVariable;
LValue elementLValue; LValue elementLValue;
QualType elementType; QualType elementType;
if (const DeclStmt *SD = dyn_cast<DeclStmt>(S.getElement())) { if (const DeclStmt *SD = dyn_cast<DeclStmt>(S.getElement())) {
EmitStmt(SD); // Initialize the variable, in case it's a __block variable or something.
const VarDecl* D = cast<VarDecl>(SD->getSingleDecl()); EmitAutoVarInit(variable);
const VarDecl* D = cast<VarDecl>(SD->getSingleDecl());
DeclRefExpr tempDRE(const_cast<VarDecl*>(D), D->getType(), DeclRefExpr tempDRE(const_cast<VarDecl*>(D), D->getType(),
VK_LValue, SourceLocation()); VK_LValue, SourceLocation());
elementLValue = EmitLValue(&tempDRE); elementLValue = EmitLValue(&tempDRE);
elementType = D->getType(); elementType = D->getType();
elementIsDecl = true; elementIsVariable = true;
} else { } else {
elementLValue = LValue(); // suppress warning elementLValue = LValue(); // suppress warning
elementType = cast<Expr>(S.getElement())->getType(); elementType = cast<Expr>(S.getElement())->getType();
elementIsDecl = false; elementIsVariable = false;
} }
const llvm::Type *convertedElementType = ConvertType(elementType); const llvm::Type *convertedElementType = ConvertType(elementType);
@ -837,11 +843,16 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
// Make sure we have an l-value. Yes, this gets evaluated every // Make sure we have an l-value. Yes, this gets evaluated every
// time through the loop. // time through the loop.
if (!elementIsDecl) if (!elementIsVariable)
elementLValue = EmitLValue(cast<Expr>(S.getElement())); elementLValue = EmitLValue(cast<Expr>(S.getElement()));
EmitStoreThroughLValue(RValue::get(CurrentItem), elementLValue, elementType); EmitStoreThroughLValue(RValue::get(CurrentItem), elementLValue, elementType);
// If we do have an element variable, this assignment is the end of
// its initialization.
if (elementIsVariable)
EmitAutoVarCleanups(variable);
// Perform the loop body, setting up break and continue labels. // Perform the loop body, setting up break and continue labels.
BreakContinueStack.push_back(BreakContinue(LoopEnd, AfterBody)); BreakContinueStack.push_back(BreakContinue(LoopEnd, AfterBody));
{ {
@ -891,7 +902,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
// No more elements. // No more elements.
EmitBlock(EmptyBB); EmitBlock(EmptyBB);
if (!elementIsDecl) { if (!elementIsVariable) {
// If the element was not a declaration, set it to be null. // If the element was not a declaration, set it to be null.
llvm::Value *null = llvm::Constant::getNullValue(convertedElementType); llvm::Value *null = llvm::Constant::getNullValue(convertedElementType);

View File

@ -1560,7 +1560,7 @@ public:
class AutoVarEmission { class AutoVarEmission {
friend class CodeGenFunction; friend class CodeGenFunction;
const VarDecl &Variable; const VarDecl *Variable;
/// The alignment of the variable. /// The alignment of the variable.
CharUnits Alignment; CharUnits Alignment;
@ -1578,13 +1578,18 @@ public:
/// initializer. /// initializer.
bool IsConstantAggregate; bool IsConstantAggregate;
struct Invalid {};
AutoVarEmission(Invalid) : Variable(0) {}
AutoVarEmission(const VarDecl &variable) AutoVarEmission(const VarDecl &variable)
: Variable(variable), Address(0), NRVOFlag(0), : Variable(&variable), Address(0), NRVOFlag(0),
IsByRef(false), IsConstantAggregate(false) {} IsByRef(false), IsConstantAggregate(false) {}
bool wasEmittedAsGlobal() const { return Address == 0; } bool wasEmittedAsGlobal() const { return Address == 0; }
public: public:
static AutoVarEmission invalid() { return AutoVarEmission(Invalid()); }
/// Returns the address of the object within this declaration. /// Returns the address of the object within this declaration.
/// Note that this does not chase the forwarding pointer for /// Note that this does not chase the forwarding pointer for
/// __block decls. /// __block decls.
@ -1592,8 +1597,8 @@ public:
if (!IsByRef) return Address; if (!IsByRef) return Address;
return CGF.Builder.CreateStructGEP(Address, return CGF.Builder.CreateStructGEP(Address,
CGF.getByRefValueLLVMField(&Variable), CGF.getByRefValueLLVMField(Variable),
Variable.getNameAsString()); Variable->getNameAsString());
} }
}; };
AutoVarEmission EmitAutoVarAlloca(const VarDecl &var); AutoVarEmission EmitAutoVarAlloca(const VarDecl &var);

View File

@ -42,3 +42,9 @@ void t1() {
break; break;
} }
} }
// rdar://problem/9027663
void t2(NSArray *array) {
for (NSArray *array in array) { // expected-warning {{collection expression type 'NSArray *' may not respond}}
}
}