Split Sema::MarkDeclarationReferenced into multiple functions; the additional entry points are needed to implement C++11 odr-use marking correctly. No functional change in this patch; I'll actually make the change which fixes the odr-use marking in a followup patch.

llvm-svn: 149586
This commit is contained in:
Eli Friedman 2012-02-02 03:46:19 +00:00
parent 961883c1cf
commit fa0df83eba
10 changed files with 270 additions and 216 deletions

View File

@ -2265,7 +2265,19 @@ public:
ExprResult TranformToPotentiallyEvaluated(Expr *E);
ExprResult HandleExprEvaluationContextForTypeof(Expr *E);
void MarkDeclarationReferenced(SourceLocation Loc, Decl *D);
// Functions for marking a declaration referenced. These functions also
// contain the relevant logic for marking if a reference to a function or
// variable is an odr-use (in the C++11 sense). There are separate variants
// for expressions referring to a decl; these exist because odr-use marking
// needs to be delayed for some constant variables when we build one of the
// named expressions.
void MarkAnyDeclReferenced(SourceLocation Loc, Decl *D);
void MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func);
void MarkVariableReferenced(SourceLocation Loc, VarDecl *Var);
void MarkBlockDeclRefReferenced(BlockDeclRefExpr *E);
void MarkDeclRefReferenced(DeclRefExpr *E);
void MarkMemberReferenced(MemberExpr *E);
void MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T);
void MarkDeclarationsReferencedInExpr(Expr *E);

View File

@ -2160,7 +2160,7 @@ static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
D->addAttr(::new (S.Context) CleanupAttr(Attr.getRange(), S.Context, FD));
S.MarkDeclarationReferenced(Attr.getParameterLoc(), FD);
S.MarkFunctionReferenced(Attr.getParameterLoc(), FD);
}
/// Handle __attribute__((format_arg((idx)))) attribute based on

View File

@ -2382,14 +2382,14 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
ParmVarDecl *Param = Constructor->getParamDecl(0);
QualType ParamType = Param->getType().getNonReferenceType();
SemaRef.MarkDeclarationReferenced(Constructor->getLocation(), Param);
Expr *CopyCtorArg =
DeclRefExpr::Create(SemaRef.Context, NestedNameSpecifierLoc(),
SourceLocation(), Param,
Constructor->getLocation(), ParamType,
VK_LValue, 0);
SemaRef.MarkDeclRefReferenced(cast<DeclRefExpr>(CopyCtorArg));
// Cast to the base class to avoid ambiguities.
QualType ArgTy =
SemaRef.Context.getQualifiedType(BaseSpec->getType().getUnqualifiedType(),
@ -2454,8 +2454,6 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
ParmVarDecl *Param = Constructor->getParamDecl(0);
QualType ParamType = Param->getType().getNonReferenceType();
SemaRef.MarkDeclarationReferenced(Constructor->getLocation(), Param);
// Suppress copying zero-width bitfields.
if (Field->isBitField() && Field->getBitWidthValue(SemaRef.Context) == 0)
return false;
@ -2465,6 +2463,8 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
SourceLocation(), Param,
Loc, ParamType, VK_LValue, 0);
SemaRef.MarkDeclRefReferenced(cast<DeclRefExpr>(MemberExprBase));
if (Moving) {
MemberExprBase = CastForMoving(SemaRef, MemberExprBase);
}
@ -2796,7 +2796,7 @@ Sema::SetDelegatingInitializer(CXXConstructorDecl *Constructor,
Constructor->setCtorInitializers(initializer);
if (CXXDestructorDecl *Dtor = LookupDestructor(Constructor->getParent())) {
MarkDeclarationReferenced(Initializer->getSourceLocation(), Dtor);
MarkFunctionReferenced(Initializer->getSourceLocation(), Dtor);
DiagnoseUseOfDecl(Dtor, Initializer->getSourceLocation());
}
@ -3272,7 +3272,7 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
<< Field->getDeclName()
<< FieldType);
MarkDeclarationReferenced(Location, const_cast<CXXDestructorDecl*>(Dtor));
MarkFunctionReferenced(Location, const_cast<CXXDestructorDecl*>(Dtor));
}
llvm::SmallPtrSet<const RecordType *, 8> DirectVirtualBases;
@ -3304,7 +3304,7 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
<< Base->getType()
<< Base->getSourceRange());
MarkDeclarationReferenced(Location, const_cast<CXXDestructorDecl*>(Dtor));
MarkFunctionReferenced(Location, const_cast<CXXDestructorDecl*>(Dtor));
}
// Virtual bases.
@ -3332,7 +3332,7 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
PDiag(diag::err_access_dtor_vbase)
<< VBase->getType());
MarkDeclarationReferenced(Location, const_cast<CXXDestructorDecl*>(Dtor));
MarkFunctionReferenced(Location, const_cast<CXXDestructorDecl*>(Dtor));
}
}
@ -5306,7 +5306,7 @@ bool Sema::CheckDestructor(CXXDestructorDecl *Destructor) {
if (FindDeallocationFunction(Loc, RD, Name, OperatorDelete))
return true;
MarkDeclarationReferenced(Loc, OperatorDelete);
MarkFunctionReferenced(Loc, OperatorDelete);
Destructor->setOperatorDelete(OperatorDelete);
}
@ -9030,7 +9030,7 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
CheckNonNullArguments(NonNull, ExprArgs.get(), ConstructLoc);
}
MarkDeclarationReferenced(ConstructLoc, Constructor);
MarkFunctionReferenced(ConstructLoc, Constructor);
return Owned(CXXConstructExpr::Create(Context, DeclInitType, ConstructLoc,
Constructor, Elidable, Exprs, NumExprs,
HadMultipleCandidates, RequiresZeroInit,
@ -9052,7 +9052,7 @@ bool Sema::InitializeVarWithConstructor(VarDecl *VD,
Expr *Temp = TempResult.takeAs<Expr>();
CheckImplicitConversions(Temp, VD->getLocation());
MarkDeclarationReferenced(VD->getLocation(), Constructor);
MarkFunctionReferenced(VD->getLocation(), Constructor);
Temp = MaybeCreateExprWithCleanups(Temp);
VD->setInit(Temp);
@ -9068,7 +9068,7 @@ void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) {
if (ClassDecl->isDependentContext()) return;
CXXDestructorDecl *Destructor = LookupDestructor(ClassDecl);
MarkDeclarationReferenced(VD->getLocation(), Destructor);
MarkFunctionReferenced(VD->getLocation(), Destructor);
CheckDestructorAccess(VD->getLocation(), Destructor,
PDiag(diag::err_access_dtor_var)
<< VD->getDeclName()
@ -10905,7 +10905,7 @@ void Sema::MarkVirtualMembersReferenced(SourceLocation Loc,
// C++ [basic.def.odr]p2:
// [...] A virtual member function is used if it is not pure. [...]
if (MD->isVirtual() && !MD->isPure())
MarkDeclarationReferenced(Loc, MD);
MarkFunctionReferenced(Loc, MD);
}
// Only classes that have virtual bases need a VTT.
@ -10965,7 +10965,7 @@ void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) {
->getAs<RecordType>()) {
CXXRecordDecl *RD = cast<CXXRecordDecl>(RecordTy->getDecl());
if (CXXDestructorDecl *Destructor = LookupDestructor(RD)) {
MarkDeclarationReferenced(Field->getLocation(), Destructor);
MarkFunctionReferenced(Field->getLocation(), Destructor);
CheckDestructorAccess(Field->getLocation(), Destructor,
PDiag(diag::err_access_dtor_ivar)
<< Context.getBaseElementType(Field->getType()));

View File

@ -1331,8 +1331,6 @@ static CaptureResult shouldCaptureValueReference(Sema &S, SourceLocation loc,
return CR_Error;
}
S.MarkDeclarationReferenced(loc, var);
// The BlocksAttr indicates the variable is bound by-reference.
bool byRef = var->hasAttr<BlocksAttr>();
@ -1411,6 +1409,8 @@ static ExprResult BuildBlockDeclRefExpr(Sema &S, ValueDecl *VD,
NameInfo.getLoc(), true);
}
S.MarkBlockDeclRefReferenced(BDRE);
return S.Owned(BDRE);
}
@ -1442,13 +1442,13 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
}
}
MarkDeclarationReferenced(NameInfo.getLoc(), D);
DeclRefExpr *E = DeclRefExpr::Create(Context,
SS ? SS->getWithLocInContext(Context)
: NestedNameSpecifierLoc(),
SourceLocation(),
D, NameInfo, Ty, VK);
Expr *E = DeclRefExpr::Create(Context,
SS ? SS->getWithLocInContext(Context)
: NestedNameSpecifierLoc(),
SourceLocation(),
D, NameInfo, Ty, VK);
MarkDeclRefReferenced(E);
// Just in case we're building an illegal pointer-to-member.
FieldDecl *FD = dyn_cast<FieldDecl>(D);
@ -2004,7 +2004,7 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
if (SelfExpr.isInvalid())
return ExprError();
MarkDeclarationReferenced(Loc, IV);
MarkAnyDeclReferenced(Loc, IV);
return Owned(new (Context)
ObjCIvarRefExpr(IV, IV->getType(), Loc,
SelfExpr.take(), true, true));
@ -3742,7 +3742,7 @@ Sema::ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc,
DeclRefExpr *ConfigDR = new (Context) DeclRefExpr(
ConfigDecl, ConfigQTy, VK_LValue, LLLLoc);
MarkDeclarationReferenced(LLLLoc, ConfigDecl);
MarkFunctionReferenced(LLLLoc, ConfigDecl);
return ActOnCallExpr(S, ConfigDR, LLLLoc, ExecConfig, GGGLoc, 0,
/*IsExecConfig=*/true);
@ -9436,9 +9436,7 @@ Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext) {
}
void Sema::PopExpressionEvaluationContext() {
// Pop the current expression evaluation context off the stack.
ExpressionEvaluationContextRecord Rec = ExprEvalContexts.back();
ExprEvalContexts.pop_back();
ExpressionEvaluationContextRecord& Rec = ExprEvalContexts.back();
// When are coming out of an unevaluated context, clear out any
// temporaries that we may have created as part of the evaluation of
@ -9453,6 +9451,9 @@ void Sema::PopExpressionEvaluationContext() {
} else {
ExprNeedsCleanups |= Rec.ParentNeedsCleanups;
}
// Pop the current expression evaluation context off the stack.
ExprEvalContexts.pop_back();
}
void Sema::DiscardCleanupsInEvaluationContext() {
@ -9468,55 +9469,49 @@ ExprResult Sema::HandleExprEvaluationContextForTypeof(Expr *E) {
return TranformToPotentiallyEvaluated(E);
}
/// \brief Note that the given declaration was referenced in the source code.
///
/// This routine should be invoke whenever a given declaration is referenced
/// in the source code, and where that reference occurred. If this declaration
/// reference means that the the declaration is used (C++ [basic.def.odr]p2,
/// C99 6.9p3), then the declaration will be marked as used.
///
/// \param Loc the location where the declaration was referenced.
///
/// \param D the declaration that has been referenced by the source code.
void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
assert(D && "No declaration?");
D->setReferenced();
if (D->isUsed(false))
return;
if (!isa<VarDecl>(D) && !isa<FunctionDecl>(D))
return;
bool IsPotentiallyEvaluatedContext(Sema &SemaRef) {
// Do not mark anything as "used" within a dependent context; wait for
// an instantiation.
if (CurContext->isDependentContext())
return;
if (SemaRef.CurContext->isDependentContext())
return false;
switch (ExprEvalContexts.back().Context) {
case Unevaluated:
switch (SemaRef.ExprEvalContexts.back().Context) {
case Sema::Unevaluated:
// We are in an expression that is not potentially evaluated; do nothing.
// (Depending on how you read the standard, we actually do need to do
// something here for null pointer constants, but the standard's
// definition of a null pointer constant is completely crazy.)
return;
return false;
case ConstantEvaluated:
case PotentiallyEvaluated:
case Sema::ConstantEvaluated:
case Sema::PotentiallyEvaluated:
// We are in a potentially evaluated expression (or a constant-expression
// in C++03); we need to do implicit template instantiation, implicitly
// define class members, and mark most declarations as used.
break;
return true;
case PotentiallyEvaluatedIfUsed:
case Sema::PotentiallyEvaluatedIfUsed:
// Referenced declarations will only be used if the construct in the
// containing expression is used.
return;
return false;
}
}
/// \brief Mark a function referenced, and check whether it is odr-used
/// (C++ [basic.def.odr]p2, C99 6.9p3)
void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func) {
assert(Func && "No function?");
Func->setReferenced();
if (Func->isUsed(false))
return;
if (!IsPotentiallyEvaluatedContext(*this))
return;
// Note that this declaration has been used.
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Func)) {
if (Constructor->isDefaulted()) {
if (Constructor->isDefaultConstructor()) {
if (Constructor->isTrivial())
@ -9533,12 +9528,13 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
}
MarkVTableUsed(Loc, Constructor->getParent());
} else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
} else if (CXXDestructorDecl *Destructor =
dyn_cast<CXXDestructorDecl>(Func)) {
if (Destructor->isDefaulted() && !Destructor->isUsed(false))
DefineImplicitDestructor(Loc, Destructor);
if (Destructor->isVirtual())
MarkVTableUsed(Loc, Destructor->getParent());
} else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(D)) {
} else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(Func)) {
if (MethodDecl->isDefaulted() && MethodDecl->isOverloadedOperator() &&
MethodDecl->getOverloadedOperator() == OO_Equal) {
if (!MethodDecl->isUsed(false)) {
@ -9550,99 +9546,143 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
} else if (MethodDecl->isVirtual())
MarkVTableUsed(Loc, MethodDecl->getParent());
}
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
// Recursive functions should be marked when used from another function.
if (CurContext == Function) return;
// Implicit instantiation of function templates and member functions of
// class templates.
if (Function->isImplicitlyInstantiable()) {
bool AlreadyInstantiated = false;
if (FunctionTemplateSpecializationInfo *SpecInfo
= Function->getTemplateSpecializationInfo()) {
if (SpecInfo->getPointOfInstantiation().isInvalid())
SpecInfo->setPointOfInstantiation(Loc);
else if (SpecInfo->getTemplateSpecializationKind()
== TSK_ImplicitInstantiation)
AlreadyInstantiated = true;
} else if (MemberSpecializationInfo *MSInfo
= Function->getMemberSpecializationInfo()) {
if (MSInfo->getPointOfInstantiation().isInvalid())
MSInfo->setPointOfInstantiation(Loc);
else if (MSInfo->getTemplateSpecializationKind()
== TSK_ImplicitInstantiation)
AlreadyInstantiated = true;
}
// Recursive functions should be marked when used from another function.
// FIXME: Is this really right?
if (CurContext == Func) return;
if (!AlreadyInstantiated) {
if (isa<CXXRecordDecl>(Function->getDeclContext()) &&
cast<CXXRecordDecl>(Function->getDeclContext())->isLocalClass())
PendingLocalImplicitInstantiations.push_back(std::make_pair(Function,
Loc));
else if (Function->getTemplateInstantiationPattern()->isConstexpr())
// Do not defer instantiations of constexpr functions, to avoid the
// expression evaluator needing to call back into Sema if it sees a
// call to such a function.
InstantiateFunctionDefinition(Loc, Function);
else
PendingInstantiations.push_back(std::make_pair(Function, Loc));
}
} else {
// Walk redefinitions, as some of them may be instantiable.
for (FunctionDecl::redecl_iterator i(Function->redecls_begin()),
e(Function->redecls_end()); i != e; ++i) {
if (!i->isUsed(false) && i->isImplicitlyInstantiable())
MarkDeclarationReferenced(Loc, *i);
}
}
// Keep track of used but undefined functions.
if (!Function->isPure() && !Function->hasBody() &&
Function->getLinkage() != ExternalLinkage) {
SourceLocation &old = UndefinedInternals[Function->getCanonicalDecl()];
if (old.isInvalid()) old = Loc;
}
Function->setUsed(true);
return;
}
if (VarDecl *Var = dyn_cast<VarDecl>(D)) {
// Implicit instantiation of static data members of class templates.
if (Var->isStaticDataMember() &&
Var->getInstantiatedFromStaticDataMember()) {
MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo();
assert(MSInfo && "Missing member specialization information?");
if (MSInfo->getPointOfInstantiation().isInvalid() &&
MSInfo->getTemplateSpecializationKind()== TSK_ImplicitInstantiation) {
// Implicit instantiation of function templates and member functions of
// class templates.
if (Func->isImplicitlyInstantiable()) {
bool AlreadyInstantiated = false;
if (FunctionTemplateSpecializationInfo *SpecInfo
= Func->getTemplateSpecializationInfo()) {
if (SpecInfo->getPointOfInstantiation().isInvalid())
SpecInfo->setPointOfInstantiation(Loc);
else if (SpecInfo->getTemplateSpecializationKind()
== TSK_ImplicitInstantiation)
AlreadyInstantiated = true;
} else if (MemberSpecializationInfo *MSInfo
= Func->getMemberSpecializationInfo()) {
if (MSInfo->getPointOfInstantiation().isInvalid())
MSInfo->setPointOfInstantiation(Loc);
// This is a modification of an existing AST node. Notify listeners.
if (ASTMutationListener *L = getASTMutationListener())
L->StaticDataMemberInstantiated(Var);
if (Var->isUsableInConstantExpressions())
// Do not defer instantiations of variables which could be used in a
// constant expression.
InstantiateStaticDataMemberDefinition(Loc, Var);
else
PendingInstantiations.push_back(std::make_pair(Var, Loc));
}
else if (MSInfo->getTemplateSpecializationKind()
== TSK_ImplicitInstantiation)
AlreadyInstantiated = true;
}
// Keep track of used but undefined variables. We make a hole in
// the warning for static const data members with in-line
// initializers.
// FIXME: The hole we make for static const data members is too wide!
// We need to implement the C++11 rules for odr-used.
if (Var->hasDefinition() == VarDecl::DeclarationOnly
&& Var->getLinkage() != ExternalLinkage
&& !(Var->isStaticDataMember() && Var->hasInit())) {
SourceLocation &old = UndefinedInternals[Var->getCanonicalDecl()];
if (old.isInvalid()) old = Loc;
if (!AlreadyInstantiated) {
if (isa<CXXRecordDecl>(Func->getDeclContext()) &&
cast<CXXRecordDecl>(Func->getDeclContext())->isLocalClass())
PendingLocalImplicitInstantiations.push_back(std::make_pair(Func,
Loc));
else if (Func->getTemplateInstantiationPattern()->isConstexpr())
// Do not defer instantiations of constexpr functions, to avoid the
// expression evaluator needing to call back into Sema if it sees a
// call to such a function.
InstantiateFunctionDefinition(Loc, Func);
else
PendingInstantiations.push_back(std::make_pair(Func, Loc));
}
} else {
// Walk redefinitions, as some of them may be instantiable.
for (FunctionDecl::redecl_iterator i(Func->redecls_begin()),
e(Func->redecls_end()); i != e; ++i) {
if (!i->isUsed(false) && i->isImplicitlyInstantiable())
MarkFunctionReferenced(Loc, *i);
}
D->setUsed(true);
return;
}
// Keep track of used but undefined functions.
if (!Func->isPure() && !Func->hasBody() &&
Func->getLinkage() != ExternalLinkage) {
SourceLocation &old = UndefinedInternals[Func->getCanonicalDecl()];
if (old.isInvalid()) old = Loc;
}
Func->setUsed(true);
}
/// \brief Mark a variable referenced, and check whether it is odr-used
/// (C++ [basic.def.odr]p2, C99 6.9p3). Note that this should not be
/// used directly for normal expressions referring to VarDecl.
void Sema::MarkVariableReferenced(SourceLocation Loc, VarDecl *Var) {
Var->setReferenced();
if (Var->isUsed(false))
return;
if (!IsPotentiallyEvaluatedContext(*this))
return;
// Implicit instantiation of static data members of class templates.
if (Var->isStaticDataMember() &&
Var->getInstantiatedFromStaticDataMember()) {
MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo();
assert(MSInfo && "Missing member specialization information?");
if (MSInfo->getPointOfInstantiation().isInvalid() &&
MSInfo->getTemplateSpecializationKind()== TSK_ImplicitInstantiation) {
MSInfo->setPointOfInstantiation(Loc);
// This is a modification of an existing AST node. Notify listeners.
if (ASTMutationListener *L = getASTMutationListener())
L->StaticDataMemberInstantiated(Var);
if (Var->isUsableInConstantExpressions())
// Do not defer instantiations of variables which could be used in a
// constant expression.
InstantiateStaticDataMemberDefinition(Loc, Var);
else
PendingInstantiations.push_back(std::make_pair(Var, Loc));
}
}
// Keep track of used but undefined variables. We make a hole in
// the warning for static const data members with in-line
// initializers.
// FIXME: The hole we make for static const data members is too wide!
// We need to implement the C++11 rules for odr-used.
if (Var->hasDefinition() == VarDecl::DeclarationOnly
&& Var->getLinkage() != ExternalLinkage
&& !(Var->isStaticDataMember() && Var->hasInit())) {
SourceLocation &old = UndefinedInternals[Var->getCanonicalDecl()];
if (old.isInvalid()) old = Loc;
}
Var->setUsed(true);
}
static void MarkExprReferenced(Sema &SemaRef, SourceLocation Loc,
Decl *D, Expr *E) {
// TODO: Add special handling for variables
SemaRef.MarkAnyDeclReferenced(Loc, D);
}
/// \brief Perform reference-marking and odr-use handling for a
/// BlockDeclRefExpr.
void Sema::MarkBlockDeclRefReferenced(BlockDeclRefExpr *E) {
MarkExprReferenced(*this, E->getLocation(), E->getDecl(), E);
}
/// \brief Perform reference-marking and odr-use handling for a DeclRefExpr.
void Sema::MarkDeclRefReferenced(DeclRefExpr *E) {
MarkExprReferenced(*this, E->getLocation(), E->getDecl(), E);
}
/// \brief Perform reference-marking and odr-use handling for a MemberExpr.
void Sema::MarkMemberReferenced(MemberExpr *E) {
MarkExprReferenced(*this, E->getMemberLoc(), E->getMemberDecl(), E);
}
/// \brief Perform marking for a reference to an aribitrary declaration. It
/// marks the declaration referenced, and performs odr-use checking for functions
/// and variables. This method should not be used when building an normal
/// expression which refers to a variable.
void Sema::MarkAnyDeclReferenced(SourceLocation Loc, Decl *D) {
if (VarDecl *VD = dyn_cast<VarDecl>(D))
MarkVariableReferenced(Loc, VD);
else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
MarkFunctionReferenced(Loc, FD);
else
D->setReferenced();
}
namespace {
@ -9666,7 +9706,7 @@ namespace {
bool MarkReferencedDecls::TraverseTemplateArgument(
const TemplateArgument &Arg) {
if (Arg.getKind() == TemplateArgument::Declaration) {
S.MarkDeclarationReferenced(Loc, Arg.getAsDecl());
S.MarkAnyDeclReferenced(Loc, Arg.getAsDecl());
}
return Inherited::TraverseTemplateArgument(Arg);
@ -9699,37 +9739,37 @@ namespace {
explicit EvaluatedExprMarker(Sema &S) : Inherited(S.Context), S(S) { }
void VisitDeclRefExpr(DeclRefExpr *E) {
S.MarkDeclarationReferenced(E->getLocation(), E->getDecl());
S.MarkDeclRefReferenced(E);
}
void VisitMemberExpr(MemberExpr *E) {
S.MarkDeclarationReferenced(E->getMemberLoc(), E->getMemberDecl());
S.MarkMemberReferenced(E);
Inherited::VisitMemberExpr(E);
}
void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
S.MarkDeclarationReferenced(E->getLocStart(),
S.MarkFunctionReferenced(E->getLocStart(),
const_cast<CXXDestructorDecl*>(E->getTemporary()->getDestructor()));
Visit(E->getSubExpr());
}
void VisitCXXNewExpr(CXXNewExpr *E) {
if (E->getConstructor())
S.MarkDeclarationReferenced(E->getLocStart(), E->getConstructor());
S.MarkFunctionReferenced(E->getLocStart(), E->getConstructor());
if (E->getOperatorNew())
S.MarkDeclarationReferenced(E->getLocStart(), E->getOperatorNew());
S.MarkFunctionReferenced(E->getLocStart(), E->getOperatorNew());
if (E->getOperatorDelete())
S.MarkDeclarationReferenced(E->getLocStart(), E->getOperatorDelete());
S.MarkFunctionReferenced(E->getLocStart(), E->getOperatorDelete());
Inherited::VisitCXXNewExpr(E);
}
void VisitCXXDeleteExpr(CXXDeleteExpr *E) {
if (E->getOperatorDelete())
S.MarkDeclarationReferenced(E->getLocStart(), E->getOperatorDelete());
S.MarkFunctionReferenced(E->getLocStart(), E->getOperatorDelete());
QualType Destroyed = S.Context.getBaseElementType(E->getDestroyedType());
if (const RecordType *DestroyedRec = Destroyed->getAs<RecordType>()) {
CXXRecordDecl *Record = cast<CXXRecordDecl>(DestroyedRec->getDecl());
S.MarkDeclarationReferenced(E->getLocStart(),
S.MarkFunctionReferenced(E->getLocStart(),
S.LookupDestructor(Record));
}
@ -9737,12 +9777,12 @@ namespace {
}
void VisitCXXConstructExpr(CXXConstructExpr *E) {
S.MarkDeclarationReferenced(E->getLocStart(), E->getConstructor());
S.MarkFunctionReferenced(E->getLocStart(), E->getConstructor());
Inherited::VisitCXXConstructExpr(E);
}
void VisitBlockDeclRefExpr(BlockDeclRefExpr *E) {
S.MarkDeclarationReferenced(E->getLocation(), E->getDecl());
S.MarkBlockDeclRefReferenced(E);
}
void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {

View File

@ -645,7 +645,7 @@ ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E,
if (!Destructor)
return Owned(E);
MarkDeclarationReferenced(E->getExprLoc(), Destructor);
MarkFunctionReferenced(E->getExprLoc(), Destructor);
CheckDestructorAccess(E->getExprLoc(), Destructor,
PDiag(diag::err_access_dtor_exception) << Ty);
return Owned(E);
@ -1188,16 +1188,16 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
// Mark the new and delete operators as referenced.
if (OperatorNew)
MarkDeclarationReferenced(StartLoc, OperatorNew);
MarkFunctionReferenced(StartLoc, OperatorNew);
if (OperatorDelete)
MarkDeclarationReferenced(StartLoc, OperatorDelete);
MarkFunctionReferenced(StartLoc, OperatorDelete);
// C++0x [expr.new]p17:
// If the new expression creates an array of objects of class type,
// access and ambiguity control are done for the destructor.
if (ArraySize && Constructor) {
if (CXXDestructorDecl *dtor = LookupDestructor(Constructor->getParent())) {
MarkDeclarationReferenced(StartLoc, dtor);
MarkFunctionReferenced(StartLoc, dtor);
CheckDestructorAccess(StartLoc, dtor,
PDiag(diag::err_access_dtor)
<< Context.getBaseElementType(AllocType));
@ -1517,7 +1517,7 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
case OR_Success: {
// Got one!
FunctionDecl *FnDecl = Best->Function;
MarkDeclarationReferenced(StartLoc, FnDecl);
MarkFunctionReferenced(StartLoc, FnDecl);
// The first argument is size_t, and the first parameter must be size_t,
// too. This is checked on declaration and can be assumed. (It can't be
// asserted on, though, since invalid decls are left in there.)
@ -1956,7 +1956,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
if (!PointeeRD->hasTrivialDestructor())
if (CXXDestructorDecl *Dtor = LookupDestructor(PointeeRD)) {
MarkDeclarationReferenced(StartLoc,
MarkFunctionReferenced(StartLoc,
const_cast<CXXDestructorDecl*>(Dtor));
DiagnoseUseOfDecl(Dtor, StartLoc);
}
@ -2005,7 +2005,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
return ExprError();
}
MarkDeclarationReferenced(StartLoc, OperatorDelete);
MarkFunctionReferenced(StartLoc, OperatorDelete);
// Check access and ambiguity of operator delete and destructor.
if (PointeeRD) {
@ -2049,7 +2049,7 @@ ExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar,
ConditionVar->getType().getNonReferenceType(),
VK_LValue));
MarkDeclarationReferenced(ConditionVar->getLocation(), ConditionVar);
MarkDeclRefReferenced(cast<DeclRefExpr>(Condition.get()));
if (ConvertToBoolean) {
Condition = CheckBooleanCondition(Condition.take(), StmtLoc);
@ -3609,7 +3609,7 @@ static bool FindConditionalOverload(Sema &Self, ExprResult &LHS, ExprResult &RHS
break;
RHS = move(RHSRes);
if (Best->Function)
Self.MarkDeclarationReferenced(QuestionLoc, Best->Function);
Self.MarkFunctionReferenced(QuestionLoc, Best->Function);
return false;
}
@ -4210,7 +4210,7 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) {
CXXTemporary *Temp = CXXTemporary::Create(Context, Destructor);
if (Destructor) {
MarkDeclarationReferenced(E->getExprLoc(), Destructor);
MarkFunctionReferenced(E->getExprLoc(), Destructor);
CheckDestructorAccess(E->getExprLoc(), Destructor,
PDiag(diag::err_access_dtor_temp)
<< E->getType());
@ -4687,7 +4687,7 @@ ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl,
ExprValueKind VK = Expr::getValueKindForType(ResultType);
ResultType = ResultType.getNonLValueExprType(Context);
MarkDeclarationReferenced(Exp.get()->getLocStart(), Method);
MarkFunctionReferenced(Exp.get()->getLocStart(), Method);
CXXMemberCallExpr *CE =
new (Context) CXXMemberCallExpr(Context, ME, 0, 0, ResultType, VK,
Exp.get()->getLocEnd());

View File

@ -776,7 +776,8 @@ Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS,
}
/// \brief Build a MemberExpr AST node.
static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow,
static MemberExpr *BuildMemberExpr(Sema &SemaRef,
ASTContext &C, Expr *Base, bool isArrow,
const CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
ValueDecl *Member,
@ -786,9 +787,12 @@ static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow,
ExprValueKind VK, ExprObjectKind OK,
const TemplateArgumentListInfo *TemplateArgs = 0) {
assert((!isArrow || Base->isRValue()) && "-> base must be a pointer rvalue");
return MemberExpr::Create(C, Base, isArrow, SS.getWithLocInContext(C),
TemplateKWLoc, Member, FoundDecl, MemberNameInfo,
TemplateArgs, Ty, VK, OK);
MemberExpr *E =
MemberExpr::Create(C, Base, isArrow, SS.getWithLocInContext(C),
TemplateKWLoc, Member, FoundDecl, MemberNameInfo,
TemplateArgs, Ty, VK, OK);
SemaRef.MarkMemberReferenced(E);
return E;
}
ExprResult
@ -908,9 +912,8 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
BaseExpr, OpLoc);
if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) {
MarkDeclarationReferenced(MemberLoc, Var);
return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, TemplateKWLoc,
Var, FoundDecl, MemberNameInfo,
return Owned(BuildMemberExpr(*this, Context, BaseExpr, IsArrow, SS,
TemplateKWLoc, Var, FoundDecl, MemberNameInfo,
Var->getType().getNonReferenceType(),
VK_LValue, OK_Ordinary));
}
@ -926,17 +929,16 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
type = MemberFn->getType();
}
MarkDeclarationReferenced(MemberLoc, MemberDecl);
return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, TemplateKWLoc,
MemberFn, FoundDecl, MemberNameInfo,
type, valueKind, OK_Ordinary));
return Owned(BuildMemberExpr(*this, Context, BaseExpr, IsArrow, SS,
TemplateKWLoc, MemberFn, FoundDecl,
MemberNameInfo, type, valueKind,
OK_Ordinary));
}
assert(!isa<FunctionDecl>(MemberDecl) && "member function not C++ method?");
if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) {
MarkDeclarationReferenced(MemberLoc, MemberDecl);
return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, TemplateKWLoc,
Enum, FoundDecl, MemberNameInfo,
return Owned(BuildMemberExpr(*this, Context, BaseExpr, IsArrow, SS,
TemplateKWLoc, Enum, FoundDecl, MemberNameInfo,
Enum->getType(), VK_RValue, OK_Ordinary));
}
@ -1540,13 +1542,12 @@ BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow,
MemberType = S.Context.getQualifiedType(MemberType, Combined);
}
S.MarkDeclarationReferenced(MemberNameInfo.getLoc(), Field);
ExprResult Base =
S.PerformObjectMemberConversion(BaseExpr, SS.getScopeRep(),
FoundDecl, Field);
if (Base.isInvalid())
return ExprError();
return S.Owned(BuildMemberExpr(S.Context, Base.take(), IsArrow, SS,
return S.Owned(BuildMemberExpr(S, S.Context, Base.take(), IsArrow, SS,
/*TemplateKWLoc=*/SourceLocation(),
Field, FoundDecl, MemberNameInfo,
MemberType, VK, OK));

View File

@ -3156,7 +3156,7 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
// This is the overload that will actually be used for the initialization, so
// mark it as used.
S.MarkDeclarationReferenced(DeclLoc, Function);
S.MarkFunctionReferenced(DeclLoc, Function);
// Compute the returned type of the conversion.
if (isa<CXXConversionDecl>(Function))
@ -3679,7 +3679,7 @@ static void TryUserDefinedConversion(Sema &S,
}
FunctionDecl *Function = Best->Function;
S.MarkDeclarationReferenced(DeclLoc, Function);
S.MarkFunctionReferenced(DeclLoc, Function);
bool HadMultipleCandidates = (CandidateSet.size() > 1);
if (isa<CXXConstructorDecl>(Function)) {
@ -4388,7 +4388,7 @@ static ExprResult CopyObject(Sema &S,
return S.Owned(CurInitExpr);
}
S.MarkDeclarationReferenced(Loc, Constructor);
S.MarkFunctionReferenced(Loc, Constructor);
// Determine the arguments required to actually perform the
// constructor call (we might have derived-to-base conversions, or
@ -4531,7 +4531,7 @@ PerformConstructorInitialization(Sema &S,
// An explicitly-constructed temporary, e.g., X(1, 2).
unsigned NumExprs = ConstructorArgs.size();
Expr **Exprs = (Expr **)ConstructorArgs.take();
S.MarkDeclarationReferenced(Loc, Constructor);
S.MarkFunctionReferenced(Loc, Constructor);
S.DiagnoseUseOfDecl(Constructor, Loc);
TypeSourceInfo *TSInfo = Entity.getTypeSourceInfo();
@ -4899,7 +4899,7 @@ InitializationSequence::Perform(Sema &S,
= S.LookupDestructor(cast<CXXRecordDecl>(Record->getDecl()));
S.CheckDestructorAccess(CurInit.get()->getLocStart(), Destructor,
S.PDiag(diag::err_access_dtor_temp) << T);
S.MarkDeclarationReferenced(CurInit.get()->getLocStart(), Destructor);
S.MarkFunctionReferenced(CurInit.get()->getLocStart(), Destructor);
S.DiagnoseUseOfDecl(Destructor, CurInit.get()->getLocStart());
}
}

View File

@ -2893,7 +2893,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
// Record the standard conversion we used and the conversion function.
if (CXXConstructorDecl *Constructor
= dyn_cast<CXXConstructorDecl>(Best->Function)) {
S.MarkDeclarationReferenced(From->getLocStart(), Constructor);
S.MarkFunctionReferenced(From->getLocStart(), Constructor);
// C++ [over.ics.user]p1:
// If the user-defined conversion is specified by a
@ -2923,7 +2923,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
}
if (CXXConversionDecl *Conversion
= dyn_cast<CXXConversionDecl>(Best->Function)) {
S.MarkDeclarationReferenced(From->getLocStart(), Conversion);
S.MarkFunctionReferenced(From->getLocStart(), Conversion);
// C++ [over.ics.user]p1:
//
@ -3793,7 +3793,7 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
return false;
if (Best->Function)
S.MarkDeclarationReferenced(DeclLoc, Best->Function);
S.MarkFunctionReferenced(DeclLoc, Best->Function);
ICS.setUserDefined();
ICS.UserDefined.Before = Best->Conversions[0].Standard;
ICS.UserDefined.After = Best->FinalConversion;
@ -8817,7 +8817,7 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *AddressOfExpr,
Fn = Resolver.getMatchingFunctionDecl();
assert(Fn);
FoundResult = *Resolver.getMatchingFunctionAccessPair();
MarkDeclarationReferenced(AddressOfExpr->getLocStart(), Fn);
MarkFunctionReferenced(AddressOfExpr->getLocStart(), Fn);
if (Complain)
CheckAddressOfMemberAccess(AddressOfExpr, FoundResult);
}
@ -9380,7 +9380,7 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE,
switch (CandidateSet.BestViableFunction(*this, Fn->getLocStart(), Best)) {
case OR_Success: {
FunctionDecl *FDecl = Best->Function;
MarkDeclarationReferenced(Fn->getExprLoc(), FDecl);
MarkFunctionReferenced(Fn->getExprLoc(), FDecl);
CheckUnresolvedLookupAccess(ULE, Best->FoundDecl);
DiagnoseUseOfDecl(FDecl, ULE->getNameLoc());
Fn = FixOverloadedFunctionReference(Fn, Best->FoundDecl, FDecl);
@ -9534,7 +9534,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
// We matched an overloaded operator. Build a call to that
// operator.
MarkDeclarationReferenced(OpLoc, FnDecl);
MarkFunctionReferenced(OpLoc, FnDecl);
// Convert the arguments.
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
@ -9755,7 +9755,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// We matched an overloaded operator. Build a call to that
// operator.
MarkDeclarationReferenced(OpLoc, FnDecl);
MarkFunctionReferenced(OpLoc, FnDecl);
// Convert the arguments.
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
@ -9962,7 +9962,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
// We matched an overloaded operator. Build a call to that
// operator.
MarkDeclarationReferenced(LLoc, FnDecl);
MarkFunctionReferenced(LLoc, FnDecl);
CheckMemberOperatorAccess(LLoc, Args[0], Args[1], Best->FoundDecl);
DiagnoseUseOfDecl(Best->FoundDecl, LLoc);
@ -10211,7 +10211,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
Best)) {
case OR_Success:
Method = cast<CXXMethodDecl>(Best->Function);
MarkDeclarationReferenced(UnresExpr->getMemberLoc(), Method);
MarkFunctionReferenced(UnresExpr->getMemberLoc(), Method);
FoundDecl = Best->FoundDecl;
CheckUnresolvedMemberAccess(UnresExpr, Best->FoundDecl);
DiagnoseUseOfDecl(Best->FoundDecl, UnresExpr->getNameLoc());
@ -10476,7 +10476,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
RParenLoc);
}
MarkDeclarationReferenced(LParenLoc, Best->Function);
MarkFunctionReferenced(LParenLoc, Best->Function);
CheckMemberOperatorAccess(LParenLoc, Object.get(), 0, Best->FoundDecl);
DiagnoseUseOfDecl(Best->FoundDecl, LParenLoc);
@ -10666,7 +10666,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc) {
return ExprError();
}
MarkDeclarationReferenced(OpLoc, Best->Function);
MarkFunctionReferenced(OpLoc, Best->Function);
CheckMemberOperatorAccess(OpLoc, Base, 0, Best->FoundDecl);
DiagnoseUseOfDecl(Best->FoundDecl, OpLoc);

View File

@ -3630,7 +3630,7 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
// Create the template argument.
Converted = TemplateArgument(Entity->getCanonicalDecl());
S.MarkDeclarationReferenced(Arg->getLocStart(), Entity);
S.MarkAnyDeclReferenced(Arg->getLocStart(), Entity);
return false;
}

View File

@ -5949,7 +5949,7 @@ TreeTransform<Derived>::TransformDeclRefExpr(DeclRefExpr *E) {
// Mark it referenced in the new context regardless.
// FIXME: this is a bit instantiation-specific.
SemaRef.MarkDeclarationReferenced(E->getLocation(), ND);
SemaRef.MarkDeclRefReferenced(E);
return SemaRef.Owned(E);
}
@ -6293,7 +6293,8 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) {
// Mark it referenced in the new context regardless.
// FIXME: this is a bit instantiation-specific.
SemaRef.MarkDeclarationReferenced(E->getMemberLoc(), Member);
SemaRef.MarkMemberReferenced(E);
return SemaRef.Owned(E);
}
@ -7117,11 +7118,11 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
// Mark any declarations we need as referenced.
// FIXME: instantiation-specific.
if (Constructor)
SemaRef.MarkDeclarationReferenced(E->getLocStart(), Constructor);
SemaRef.MarkFunctionReferenced(E->getLocStart(), Constructor);
if (OperatorNew)
SemaRef.MarkDeclarationReferenced(E->getLocStart(), OperatorNew);
SemaRef.MarkFunctionReferenced(E->getLocStart(), OperatorNew);
if (OperatorDelete)
SemaRef.MarkDeclarationReferenced(E->getLocStart(), OperatorDelete);
SemaRef.MarkFunctionReferenced(E->getLocStart(), OperatorDelete);
if (E->isArray() && Constructor &&
!E->getAllocatedType()->isDependentType()) {
@ -7130,7 +7131,7 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
if (const RecordType *RecordT = ElementType->getAs<RecordType>()) {
CXXRecordDecl *Record = cast<CXXRecordDecl>(RecordT->getDecl());
if (CXXDestructorDecl *Destructor = SemaRef.LookupDestructor(Record)) {
SemaRef.MarkDeclarationReferenced(E->getLocStart(), Destructor);
SemaRef.MarkFunctionReferenced(E->getLocStart(), Destructor);
}
}
}
@ -7202,15 +7203,15 @@ TreeTransform<Derived>::TransformCXXDeleteExpr(CXXDeleteExpr *E) {
// Mark any declarations we need as referenced.
// FIXME: instantiation-specific.
if (OperatorDelete)
SemaRef.MarkDeclarationReferenced(E->getLocStart(), OperatorDelete);
SemaRef.MarkFunctionReferenced(E->getLocStart(), OperatorDelete);
if (!E->getArgument()->isTypeDependent()) {
QualType Destroyed = SemaRef.Context.getBaseElementType(
E->getDestroyedType());
if (const RecordType *DestroyedRec = Destroyed->getAs<RecordType>()) {
CXXRecordDecl *Record = cast<CXXRecordDecl>(DestroyedRec->getDecl());
SemaRef.MarkDeclarationReferenced(E->getLocStart(),
SemaRef.LookupDestructor(Record));
SemaRef.MarkFunctionReferenced(E->getLocStart(),
SemaRef.LookupDestructor(Record));
}
}
@ -7540,7 +7541,7 @@ TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) {
!ArgumentChanged) {
// Mark the constructor as referenced.
// FIXME: Instantiation-specific
SemaRef.MarkDeclarationReferenced(E->getLocStart(), Constructor);
SemaRef.MarkFunctionReferenced(E->getLocStart(), Constructor);
return SemaRef.Owned(E);
}
@ -7601,7 +7602,7 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr(
Constructor == E->getConstructor() &&
!ArgumentChanged) {
// FIXME: Instantiation-specific
SemaRef.MarkDeclarationReferenced(E->getLocStart(), Constructor);
SemaRef.MarkFunctionReferenced(E->getLocStart(), Constructor);
return SemaRef.MaybeBindToTemporary(E);
}
@ -8253,7 +8254,7 @@ TreeTransform<Derived>::TransformBlockDeclRefExpr(BlockDeclRefExpr *E) {
ND == E->getDecl()) {
// Mark it referenced in the new context regardless.
// FIXME: this is a bit instantiation-specific.
SemaRef.MarkDeclarationReferenced(E->getLocation(), ND);
SemaRef.MarkBlockDeclRefReferenced(E);
return SemaRef.Owned(E);
}