Note when a decl is used in AST files.

When an AST file is built based on another AST file, it can use a decl from
the fist file, and therefore mark the "isUsed" bit.  We need to note this in
the AST file so that the bit is set correctly when the second AST file is
loaded.

This patch introduces the distinction between setIsUsed() and markUsed() so
that we don't call into the ASTMutationListener callback when it wouldn't
be appropriate.

Fixes PR16635.

llvm-svn: 190016
This commit is contained in:
Eli Friedman 2013-09-05 00:02:25 +00:00
parent 5c30024fd4
commit 276dd188c4
17 changed files with 83 additions and 28 deletions

View File

@ -90,6 +90,11 @@ public:
const ObjCPropertyDecl *OrigProp, const ObjCPropertyDecl *OrigProp,
const ObjCCategoryDecl *ClassExt) {} const ObjCCategoryDecl *ClassExt) {}
/// \brief A declaration is marked used which was not previously marked used.
///
/// \param D the declaration marked used
virtual void DeclarationMarkedUsed(const Decl *D) {}
// NOTE: If new methods are added they should also be added to // NOTE: If new methods are added they should also be added to
// MultiplexASTMutationListener. // MultiplexASTMutationListener.
}; };

View File

@ -500,7 +500,16 @@ public:
/// whether the function is used. /// whether the function is used.
bool isUsed(bool CheckUsedAttr = true) const; bool isUsed(bool CheckUsedAttr = true) const;
void setUsed(bool U = true) { Used = U; } /// \brief Set whether the declaration is used, in the sense of odr-use.
///
/// This should only be used immediately after creating a declaration.
void setIsUsed(bool U) { Used = U; }
/// \brief Mark the declaration used, in the sense of odr-use.
///
/// This notifies any mutation listeners in addition to setting a bit
/// indicating the declaration is used.
void markUsed(ASTContext &C);
/// \brief Whether this declaration was referenced. /// \brief Whether this declaration was referenced.
bool isReferenced() const; bool isReferenced() const;

View File

@ -743,6 +743,7 @@ public:
virtual void AddedObjCPropertyInClassExtension(const ObjCPropertyDecl *Prop, virtual void AddedObjCPropertyInClassExtension(const ObjCPropertyDecl *Prop,
const ObjCPropertyDecl *OrigProp, const ObjCPropertyDecl *OrigProp,
const ObjCCategoryDecl *ClassExt); const ObjCCategoryDecl *ClassExt);
void DeclarationMarkedUsed(const Decl *D) LLVM_OVERRIDE;
}; };
/// \brief AST and semantic-analysis consumer that generates a /// \brief AST and semantic-analysis consumer that generates a

View File

@ -291,6 +291,16 @@ bool Decl::isUsed(bool CheckUsedAttr) const {
return false; return false;
} }
void Decl::markUsed(ASTContext &C) {
if (Used)
return;
if (C.getASTMutationListener())
C.getASTMutationListener()->DeclarationMarkedUsed(this);
Used = true;
}
bool Decl::isReferenced() const { bool Decl::isReferenced() const {
if (Referenced) if (Referenced)
return true; return true;

View File

@ -107,6 +107,8 @@ public:
virtual void AddedObjCPropertyInClassExtension(const ObjCPropertyDecl *Prop, virtual void AddedObjCPropertyInClassExtension(const ObjCPropertyDecl *Prop,
const ObjCPropertyDecl *OrigProp, const ObjCPropertyDecl *OrigProp,
const ObjCCategoryDecl *ClassExt); const ObjCCategoryDecl *ClassExt);
void DeclarationMarkedUsed(const Decl *D) LLVM_OVERRIDE;
private: private:
std::vector<ASTMutationListener*> Listeners; std::vector<ASTMutationListener*> Listeners;
}; };
@ -175,6 +177,10 @@ void MultiplexASTMutationListener::AddedObjCPropertyInClassExtension(
for (size_t i = 0, e = Listeners.size(); i != e; ++i) for (size_t i = 0, e = Listeners.size(); i != e; ++i)
Listeners[i]->AddedObjCPropertyInClassExtension(Prop, OrigProp, ClassExt); Listeners[i]->AddedObjCPropertyInClassExtension(Prop, OrigProp, ClassExt);
} }
void MultiplexASTMutationListener::DeclarationMarkedUsed(const Decl *D) {
for (size_t i = 0, e = Listeners.size(); i != e; ++i)
Listeners[i]->DeclarationMarkedUsed(D);
}
} // end namespace clang } // end namespace clang

View File

@ -2739,8 +2739,7 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old,
New->setPure(); New->setPure();
// Merge "used" flag. // Merge "used" flag.
if (Old->isUsed(false)) New->setIsUsed(Old->isUsed(false));
New->setUsed();
// Merge attributes from the parameters. These can mismatch with K&R // Merge attributes from the parameters. These can mismatch with K&R
// declarations. // declarations.
@ -3050,8 +3049,7 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
} }
// Merge "used" flag. // Merge "used" flag.
if (Old->isUsed(false)) New->setIsUsed(Old->isUsed(false));
New->setUsed();
// Keep a chain of previous declarations. // Keep a chain of previous declarations.
New->setPreviousDeclaration(Old); New->setPreviousDeclaration(Old);

View File

@ -7951,7 +7951,7 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
SourceLocation Loc = Constructor->getLocation(); SourceLocation Loc = Constructor->getLocation();
Constructor->setBody(new (Context) CompoundStmt(Loc)); Constructor->setBody(new (Context) CompoundStmt(Loc));
Constructor->setUsed(); Constructor->markUsed(Context);
MarkVTableUsed(CurrentLocation, ClassDecl); MarkVTableUsed(CurrentLocation, ClassDecl);
if (ASTMutationListener *L = getASTMutationListener()) { if (ASTMutationListener *L = getASTMutationListener()) {
@ -8289,7 +8289,7 @@ void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation,
SourceLocation Loc = Constructor->getLocation(); SourceLocation Loc = Constructor->getLocation();
Constructor->setBody(new (Context) CompoundStmt(Loc)); Constructor->setBody(new (Context) CompoundStmt(Loc));
Constructor->setUsed(); Constructor->markUsed(Context);
MarkVTableUsed(CurrentLocation, ClassDecl); MarkVTableUsed(CurrentLocation, ClassDecl);
if (ASTMutationListener *L = getASTMutationListener()) { if (ASTMutationListener *L = getASTMutationListener()) {
@ -8421,7 +8421,7 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
SourceLocation Loc = Destructor->getLocation(); SourceLocation Loc = Destructor->getLocation();
Destructor->setBody(new (Context) CompoundStmt(Loc)); Destructor->setBody(new (Context) CompoundStmt(Loc));
Destructor->setUsed(); Destructor->markUsed(Context);
MarkVTableUsed(CurrentLocation, ClassDecl); MarkVTableUsed(CurrentLocation, ClassDecl);
if (ASTMutationListener *L = getASTMutationListener()) { if (ASTMutationListener *L = getASTMutationListener()) {
@ -9117,7 +9117,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
if (getLangOpts().CPlusPlus11 && CopyAssignOperator->isImplicit()) if (getLangOpts().CPlusPlus11 && CopyAssignOperator->isImplicit())
diagnoseDeprecatedCopyOperation(*this, CopyAssignOperator, CurrentLocation); diagnoseDeprecatedCopyOperation(*this, CopyAssignOperator, CurrentLocation);
CopyAssignOperator->setUsed(); CopyAssignOperator->markUsed(Context);
SynthesizedFunctionScope Scope(*this, CopyAssignOperator); SynthesizedFunctionScope Scope(*this, CopyAssignOperator);
DiagnosticErrorTrap Trap(Diags); DiagnosticErrorTrap Trap(Diags);
@ -9562,7 +9562,7 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
return; return;
} }
MoveAssignOperator->setUsed(); MoveAssignOperator->markUsed(Context);
SynthesizedFunctionScope Scope(*this, MoveAssignOperator); SynthesizedFunctionScope Scope(*this, MoveAssignOperator);
DiagnosticErrorTrap Trap(Diags); DiagnosticErrorTrap Trap(Diags);
@ -9915,7 +9915,7 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
/*isStmtExpr=*/ false).takeAs<Stmt>()); /*isStmtExpr=*/ false).takeAs<Stmt>());
} }
CopyConstructor->setUsed(); CopyConstructor->markUsed(Context);
if (ASTMutationListener *L = getASTMutationListener()) { if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(CopyConstructor); L->CompletedImplicitDefinition(CopyConstructor);
} }
@ -10101,7 +10101,7 @@ void Sema::DefineImplicitMoveConstructor(SourceLocation CurrentLocation,
/*isStmtExpr=*/ false).takeAs<Stmt>()); /*isStmtExpr=*/ false).takeAs<Stmt>());
} }
MoveConstructor->setUsed(); MoveConstructor->markUsed(Context);
if (ASTMutationListener *L = getASTMutationListener()) { if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(MoveConstructor); L->CompletedImplicitDefinition(MoveConstructor);
@ -10119,7 +10119,7 @@ static void markLambdaCallOperatorUsed(Sema &S, CXXRecordDecl *Lambda) {
Lambda->lookup( Lambda->lookup(
S.Context.DeclarationNames.getCXXOperatorName(OO_Call)).front()); S.Context.DeclarationNames.getCXXOperatorName(OO_Call)).front());
CallOperator->setReferenced(); CallOperator->setReferenced();
CallOperator->setUsed(); CallOperator->markUsed(S.Context);
} }
void Sema::DefineImplicitLambdaToFunctionPointerConversion( void Sema::DefineImplicitLambdaToFunctionPointerConversion(
@ -10131,7 +10131,7 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion(
// Make sure that the lambda call operator is marked used. // Make sure that the lambda call operator is marked used.
markLambdaCallOperatorUsed(*this, Lambda); markLambdaCallOperatorUsed(*this, Lambda);
Conv->setUsed(); Conv->markUsed(Context);
SynthesizedFunctionScope Scope(*this, Conv); SynthesizedFunctionScope Scope(*this, Conv);
DiagnosticErrorTrap Trap(Diags); DiagnosticErrorTrap Trap(Diags);
@ -10150,7 +10150,7 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion(
// Fill in the __invoke function with a dummy implementation. IR generation // Fill in the __invoke function with a dummy implementation. IR generation
// will fill in the actual details. // will fill in the actual details.
Invoke->setUsed(); Invoke->markUsed(Context);
Invoke->setReferenced(); Invoke->setReferenced();
Invoke->setBody(new (Context) CompoundStmt(Conv->getLocation())); Invoke->setBody(new (Context) CompoundStmt(Conv->getLocation()));
@ -10164,7 +10164,7 @@ void Sema::DefineImplicitLambdaToBlockPointerConversion(
SourceLocation CurrentLocation, SourceLocation CurrentLocation,
CXXConversionDecl *Conv) CXXConversionDecl *Conv)
{ {
Conv->setUsed(); Conv->markUsed(Context);
SynthesizedFunctionScope Scope(*this, Conv); SynthesizedFunctionScope Scope(*this, Conv);
DiagnosticErrorTrap Trap(Diags); DiagnosticErrorTrap Trap(Diags);

View File

@ -9623,7 +9623,7 @@ ExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc,
/// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo". /// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo".
ExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc, ExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc,
LabelDecl *TheDecl) { LabelDecl *TheDecl) {
TheDecl->setUsed(); TheDecl->markUsed(Context);
// Create the AST node. The address of a label always has type 'void*'. // Create the AST node. The address of a label always has type 'void*'.
return Owned(new (Context) AddrLabelExpr(OpLoc, LabLoc, TheDecl, return Owned(new (Context) AddrLabelExpr(OpLoc, LabLoc, TheDecl,
Context.getPointerType(Context.VoidTy))); Context.getPointerType(Context.VoidTy)));
@ -11097,7 +11097,7 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func) {
// decl in the middle of a decl chain. We loop to maintain the invariant // decl in the middle of a decl chain. We loop to maintain the invariant
// that once a decl is used, all decls after it are also used. // that once a decl is used, all decls after it are also used.
for (FunctionDecl *F = Func->getMostRecentDecl();; F = F->getPreviousDecl()) { for (FunctionDecl *F = Func->getMostRecentDecl();; F = F->getPreviousDecl()) {
F->setUsed(true); F->markUsed(Context);
if (F == Func) if (F == Func)
break; break;
} }
@ -11172,7 +11172,7 @@ static ExprResult captureInCapturedRegion(Sema &S, CapturedRegionScopeInfo *RSI,
Expr *Ref = new (S.Context) DeclRefExpr(Var, RefersToEnclosingLocal, Expr *Ref = new (S.Context) DeclRefExpr(Var, RefersToEnclosingLocal,
DeclRefType, VK_LValue, Loc); DeclRefType, VK_LValue, Loc);
Var->setReferenced(true); Var->setReferenced(true);
Var->setUsed(true); Var->markUsed(S.Context);
return Ref; return Ref;
} }
@ -11214,7 +11214,7 @@ static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI,
Expr *Ref = new (S.Context) DeclRefExpr(Var, RefersToEnclosingLocal, Expr *Ref = new (S.Context) DeclRefExpr(Var, RefersToEnclosingLocal,
DeclRefType, VK_LValue, Loc); DeclRefType, VK_LValue, Loc);
Var->setReferenced(true); Var->setReferenced(true);
Var->setUsed(true); Var->markUsed(S.Context);
// When the field has array type, create index variables for each // When the field has array type, create index variables for each
// dimension of the array. We use these index variables to subscript // dimension of the array. We use these index variables to subscript
@ -11660,7 +11660,7 @@ static void MarkVarDeclODRUsed(Sema &SemaRef, VarDecl *Var,
SemaRef.tryCaptureVariable(Var, Loc); SemaRef.tryCaptureVariable(Var, Loc);
Var->setUsed(true); Var->markUsed(SemaRef.Context);
} }
void Sema::UpdateMarkingForLValueToRValue(Expr *E) { void Sema::UpdateMarkingForLValueToRValue(Expr *E) {

View File

@ -1105,7 +1105,7 @@ ExprResult Sema::BuildBlockForLambdaConversion(SourceLocation CurrentLocation,
Lambda->lookup( Lambda->lookup(
Context.DeclarationNames.getCXXOperatorName(OO_Call)).front()); Context.DeclarationNames.getCXXOperatorName(OO_Call)).front());
CallOperator->setReferenced(); CallOperator->setReferenced();
CallOperator->setUsed(); CallOperator->markUsed(Context);
ExprResult Init = PerformCopyInitialization( ExprResult Init = PerformCopyInitialization(
InitializedEntity::InitializeBlock(ConvLocation, InitializedEntity::InitializeBlock(ConvLocation,

View File

@ -2041,7 +2041,7 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
if (RangeVarType->isDependentType()) { if (RangeVarType->isDependentType()) {
// The range is implicitly used as a placeholder when it is dependent. // The range is implicitly used as a placeholder when it is dependent.
RangeVar->setUsed(); RangeVar->markUsed(Context);
// Deduce any 'auto's in the loop variable as 'DependentTy'. We'll fill // Deduce any 'auto's in the loop variable as 'DependentTy'. We'll fill
// them in properly when we instantiate the loop. // them in properly when we instantiate the loop.
@ -2284,7 +2284,7 @@ StmtResult Sema::ActOnGotoStmt(SourceLocation GotoLoc,
SourceLocation LabelLoc, SourceLocation LabelLoc,
LabelDecl *TheDecl) { LabelDecl *TheDecl) {
getCurFunction()->setHasBranchIntoScope(); getCurFunction()->setHasBranchIntoScope();
TheDecl->setUsed(); TheDecl->markUsed(Context);
return Owned(new (Context) GotoStmt(TheDecl, GotoLoc, LabelLoc)); return Owned(new (Context) GotoStmt(TheDecl, GotoLoc, LabelLoc));
} }

View File

@ -3352,7 +3352,7 @@ void Sema::BuildVariableInstantiation(
NewVar->setAccess(OldVar->getAccess()); NewVar->setAccess(OldVar->getAccess());
if (!OldVar->isStaticDataMember()) { if (!OldVar->isStaticDataMember()) {
NewVar->setUsed(OldVar->isUsed(false)); NewVar->setIsUsed(OldVar->isUsed(false));
NewVar->setReferenced(OldVar->isReferenced()); NewVar->setReferenced(OldVar->isReferenced());
} }

View File

@ -26,7 +26,8 @@ enum DeclUpdateKind {
UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION, UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION,
UPD_CXX_ADDED_ANONYMOUS_NAMESPACE, UPD_CXX_ADDED_ANONYMOUS_NAMESPACE,
UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER, UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER,
UPD_CXX_DEDUCED_RETURN_TYPE UPD_CXX_DEDUCED_RETURN_TYPE,
UPD_DECL_MARKED_USED
}; };
TypeIdx TypeIdxFromBuiltin(const BuiltinType *BT); TypeIdx TypeIdxFromBuiltin(const BuiltinType *BT);

View File

@ -377,7 +377,7 @@ void ASTDeclReader::VisitDecl(Decl *D) {
D->setAttrsImpl(Attrs, Reader.getContext()); D->setAttrsImpl(Attrs, Reader.getContext());
} }
D->setImplicit(Record[Idx++]); D->setImplicit(Record[Idx++]);
D->setUsed(Record[Idx++]); D->setIsUsed(Record[Idx++]);
D->setReferenced(Record[Idx++]); D->setReferenced(Record[Idx++]);
D->setTopLevelDeclInObjCContainer(Record[Idx++]); D->setTopLevelDeclInObjCContainer(Record[Idx++]);
D->setAccess((AccessSpecifier)Record[Idx++]); D->setAccess((AccessSpecifier)Record[Idx++]);
@ -2838,6 +2838,11 @@ void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile,
FD, Reader.readType(ModuleFile, Record, Idx)); FD, Reader.readType(ModuleFile, Record, Idx));
break; break;
} }
case UPD_DECL_MARKED_USED: {
D->markUsed(Reader.getContext());
break;
}
} }
} }
} }

View File

@ -4314,6 +4314,7 @@ void ASTWriter::ResolveDeclUpdatesBlocks() {
break; break;
case UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER: case UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER:
case UPD_DECL_MARKED_USED:
++Idx; ++Idx;
break; break;
@ -5370,3 +5371,12 @@ void ASTWriter::AddedObjCPropertyInClassExtension(const ObjCPropertyDecl *Prop,
RewriteDecl(D); RewriteDecl(D);
} }
void ASTWriter::DeclarationMarkedUsed(const Decl *D) {
assert(!WritingAST && "Already writing the AST!");
if (!D->isFromASTFile())
return;
UpdateRecord &Record = DeclUpdates[D];
Record.push_back(UPD_DECL_MARKED_USED);
}

View File

@ -1,3 +1,3 @@
typedef struct { int id; } FILE; typedef struct { int id; } FILE;
int fprintf(FILE*restrict, const char* restrict format, ...); int fprintf(FILE*restrict, const char* restrict format, ...);
extern FILE *__stderrp;

View File

@ -0,0 +1,2 @@
@import cstd.stdio;
static inline void SPXTrace() { fprintf(__stderrp, ""); }

View File

@ -0,0 +1,8 @@
// RUN: rm -rf %t
// RUN: mkdir %t
// RUN: %clang_cc1 -x objective-c-header -emit-pch %S/Inputs/pch-used.h -o %t/pch-used.h.pch -fmodules -fmodules-cache-path=%t/cache -O0 -isystem %S/Inputs/System/usr/include
// RUN: %clang_cc1 %s -include-pch %t/pch-used.h.pch -fmodules -fmodules-cache-path=%t/cache -O0 -isystem %S/Inputs/System/usr/include -emit-llvm -o - | FileCheck %s
void f() { SPXTrace(); }
// CHECK: define internal void @SPXTrace