Add a warning for when an array-to-pointer decay is performed on an array

temporary or an array subobject of a class temporary, and the resulting value
is used to initialize a pointer which outlives the temporary. Such a pointer
is always left dangling after the initialization completes and the array's
lifetime ends.

In order to detect this situation, this change also adds an
LValueClassification of LV_ArrayTemporary for temporaries of array type which
aren't subobjects of class temporaries. These occur in C++11 T{...} and GNU C++
(T){...} expressions, when T is an array type. Previously we treated the former
as a generic prvalue and the latter as a class temporary.

llvm-svn: 157955
This commit is contained in:
Richard Smith
2012-06-04 22:27:30 +00:00
parent 06caff46c0
commit eb3cad53e7
6 changed files with 117 additions and 9 deletions

View File

@@ -4747,6 +4747,43 @@ PerformConstructorInitialization(Sema &S,
return move(CurInit);
}
/// Determine whether the specified InitializedEntity definitely has a lifetime
/// longer than the current full-expression. Conservatively returns false if
/// it's unclear.
static bool
InitializedEntityOutlivesFullExpression(const InitializedEntity &Entity) {
const InitializedEntity *Top = &Entity;
while (Top->getParent())
Top = Top->getParent();
switch (Top->getKind()) {
case InitializedEntity::EK_Variable:
case InitializedEntity::EK_Result:
case InitializedEntity::EK_Exception:
case InitializedEntity::EK_Member:
case InitializedEntity::EK_New:
case InitializedEntity::EK_Base:
case InitializedEntity::EK_Delegating:
return true;
case InitializedEntity::EK_ArrayElement:
case InitializedEntity::EK_VectorElement:
case InitializedEntity::EK_BlockElement:
case InitializedEntity::EK_ComplexElement:
// Could not determine what the full initialization is. Assume it might not
// outlive the full-expression.
return false;
case InitializedEntity::EK_Parameter:
case InitializedEntity::EK_Temporary:
case InitializedEntity::EK_LambdaCapture:
// The entity being initialized might not outlive the full-expression.
return false;
}
llvm_unreachable("unknown entity kind");
}
ExprResult
InitializationSequence::Perform(Sema &S,
const InitializedEntity &Entity,
@@ -4826,6 +4863,18 @@ InitializationSequence::Perform(Sema &S,
<< Init->getSourceRange();
}
// Diagnose cases where we initialize a pointer to an array temporary, and the
// pointer obviously outlives the temporary.
if (Args.size() == 1 && Args.get()[0]->getType()->isArrayType() &&
Entity.getType()->isPointerType() &&
InitializedEntityOutlivesFullExpression(Entity)) {
Expr *Init = Args.get()[0];
Expr::LValueClassification Kind = Init->ClassifyLValue(S.Context);
if (Kind == Expr::LV_ClassTemporary || Kind == Expr::LV_ArrayTemporary)
S.Diag(Init->getLocStart(), diag::warn_temporary_array_to_pointer_decay)
<< Init->getSourceRange();
}
QualType DestType = Entity.getType().getNonReferenceType();
// FIXME: Ugly hack around the fact that Entity.getType() is not
// the same as Entity.getDecl()->getType() in cases involving type merging,