When building the copy expression for a __block variable, make sure

there's a respectable point of instantiation.  Also, make sure we do
this operation even when instantiating a dependently-typed variable.

llvm-svn: 123818
This commit is contained in:
John McCall 2011-01-19 11:48:09 +00:00
parent 33ddac05bb
commit 8b7fd8f156
4 changed files with 73 additions and 58 deletions

View File

@ -716,6 +716,7 @@ public:
bool &Redeclaration);
void CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous,
bool &Redeclaration);
void CheckCompleteVariableDeclaration(VarDecl *var);
NamedDecl* ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
QualType R, TypeSourceInfo *TInfo,
LookupResult &Previous,

View File

@ -3056,26 +3056,6 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (isExplicitSpecialization && !NewVD->isInvalidDecl() &&
CheckMemberSpecialization(NewVD, Previous))
NewVD->setInvalidDecl();
// For variables declared as __block which require copy construction,
// must capture copy initialization expression here.
if (!NewVD->isInvalidDecl() && NewVD->hasAttr<BlocksAttr>()) {
QualType T = NewVD->getType();
if (!T->isDependentType() && !T->isReferenceType() &&
T->getAs<RecordType>() && !T->isUnionType()) {
Expr *E = new (Context) DeclRefExpr(NewVD, T,
VK_LValue, SourceLocation());
ExprResult Res = PerformCopyInitialization(
InitializedEntity::InitializeBlock(NewVD->getLocation(),
T, false),
SourceLocation(),
Owned(E));
if (!Res.isInvalid()) {
Res = MaybeCreateExprWithCleanups(Res);
Expr *Init = Res.takeAs<Expr>();
Context.setBlockVarCopyInits(NewVD, Init);
}
}
}
}
// attributes declared post-definition are currently ignored
@ -4712,24 +4692,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
// Attach the initializer to the decl.
VDecl->setInit(Init);
if (getLangOptions().CPlusPlus) {
if (!VDecl->isInvalidDecl() &&
!VDecl->getDeclContext()->isDependentContext() &&
VDecl->hasGlobalStorage() && !VDecl->isStaticLocal() &&
!Init->isConstantInitializer(Context,
VDecl->getType()->isReferenceType()))
Diag(VDecl->getLocation(), diag::warn_global_constructor)
<< Init->getSourceRange();
// Make sure we mark the destructor as used if necessary.
QualType InitType = VDecl->getType();
while (const ArrayType *Array = Context.getAsArrayType(InitType))
InitType = Context.getBaseElementType(Array);
if (const RecordType *Record = InitType->getAs<RecordType>())
FinalizeVarWithDestructor(VDecl, Record);
}
return;
CheckCompleteVariableDeclaration(VDecl);
}
/// ActOnInitializerError - Given that there was an error parsing an
@ -4923,22 +4886,62 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl,
MultiExprArg(*this, 0, 0));
if (Init.isInvalid())
Var->setInvalidDecl();
else if (Init.get()) {
else if (Init.get())
Var->setInit(MaybeCreateExprWithCleanups(Init.get()));
if (getLangOptions().CPlusPlus && !Var->isInvalidDecl() &&
Var->hasGlobalStorage() && !Var->isStaticLocal() &&
!Var->getDeclContext()->isDependentContext() &&
!Var->getInit()->isConstantInitializer(Context, false))
Diag(Var->getLocation(), diag::warn_global_constructor);
}
}
if (!Var->isInvalidDecl() && getLangOptions().CPlusPlus && Record)
FinalizeVarWithDestructor(Var, Record);
CheckCompleteVariableDeclaration(Var);
}
}
void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
if (var->isInvalidDecl()) return;
// All the following checks are C++ only.
if (!getLangOptions().CPlusPlus) return;
QualType baseType = Context.getBaseElementType(var->getType());
if (baseType->isDependentType()) return;
// __block variables might require us to capture a copy-initializer.
if (var->hasAttr<BlocksAttr>()) {
// It's currently invalid to ever have a __block variable with an
// array type; should we diagnose that here?
// Regardless, we don't want to ignore array nesting when
// constructing this copy.
QualType type = var->getType();
if (type->isStructureOrClassType()) {
SourceLocation poi = var->getLocation();
Expr *varRef = new (Context) DeclRefExpr(var, type, VK_LValue, poi);
ExprResult result =
PerformCopyInitialization(
InitializedEntity::InitializeBlock(poi, type, false),
poi, Owned(varRef));
if (!result.isInvalid()) {
result = MaybeCreateExprWithCleanups(result);
Expr *init = result.takeAs<Expr>();
Context.setBlockVarCopyInits(var, init);
}
}
}
// Check for global constructors.
if (!var->getDeclContext()->isDependentContext() &&
var->hasGlobalStorage() &&
!var->isStaticLocal() &&
var->getInit() &&
!var->getInit()->isConstantInitializer(Context,
baseType->isReferenceType()))
Diag(var->getLocation(), diag::warn_global_constructor)
<< var->getInit()->getSourceRange();
// Require the destructor.
if (const RecordType *recordType = baseType->getAs<RecordType>())
FinalizeVarWithDestructor(var, recordType);
}
Sema::DeclGroupPtrTy
Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
Decl **Group, unsigned NumDecls) {

View File

@ -5641,16 +5641,7 @@ void Sema::AddCXXDirectInitializerToDecl(Decl *RealDecl,
VDecl->setInit(Result.takeAs<Expr>());
VDecl->setCXXDirectInitializer(true);
if (!VDecl->isInvalidDecl() &&
!VDecl->getDeclContext()->isDependentContext() &&
VDecl->hasGlobalStorage() && !VDecl->isStaticLocal() &&
!VDecl->getInit()->isConstantInitializer(Context,
VDecl->getType()->isReferenceType()))
Diag(VDecl->getLocation(), diag::warn_global_constructor)
<< VDecl->getInit()->getSourceRange();
if (const RecordType *Record = VDecl->getType()->getAs<RecordType>())
FinalizeVarWithDestructor(VDecl, Record);
CheckCompleteVariableDeclaration(VDecl);
}
/// \brief Given a constructor and the set of arguments provided for the

View File

@ -74,3 +74,23 @@ namespace N1 {
});
}
}
// Make sure we successfully instantiate the copy constructor of a
// __block variable's type.
namespace N2 {
template <int n> struct A {
A() {}
A(const A &other) {
int invalid[-n]; // expected-error 2 {{array with a negative size}}
}
};
void test1() {
__block A<1> x; // expected-note {{requested here}}
}
template <int n> void test2() {
__block A<n> x; // expected-note {{requested here}}
}
template void test2<2>();
}