forked from OSchip/llvm-project
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:
parent
5c30024fd4
commit
276dd188c4
|
@ -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.
|
||||||
};
|
};
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
@import cstd.stdio;
|
||||||
|
static inline void SPXTrace() { fprintf(__stderrp, ""); }
|
|
@ -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
|
Loading…
Reference in New Issue