Hi Richard,

This is mostly an implementation of your suggestion on how to handle
the Used flag.

At first I thought the best candidate for holding the flag was the
first decl. Doing that would remove the need the propagate the flag to
newer decls. The problem is that there are cases where we want to know
if a particular decl has the UsedAttr, so we cannot just add a
UsedAttr to the first decl.

The next best candidate was the last decl. This requires merging the
flag, but that is not too hard.

Yet another option would be checking the first decl for the flag and
the last one for the attribute. There is a link from the first to the
last, so going from one to the other is fairly fast.

The patch also
* Fixes a small bug: We would consider func unused in

static void func();
void bar() { void func() __attribute__((used)); }
static void func() {}

* Removes the argument to setIsUsed. Given its meaning, it does'n make
sense to clear the flag.

* Removes the special case in MarkFunctionReferenced.

Cheers,
Rafael
diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h
index 716b885..946a703 100644
--- a/include/clang/AST/DeclBase.h
+++ b/include/clang/AST/DeclBase.h
@@ -49,6 +49,7 @@ struct PrintingPolicy;
 class Stmt;
 class StoredDeclsMap;
 class TranslationUnitDecl;
+class UsedAttr;
 class UsingDirectiveDecl;
 }
 
@@ -263,7 +264,7 @@ private:
 
   /// \brief Whether this declaration was "used", meaning that a definition is
   /// required.
-  unsigned Used : 1;
+  mutable unsigned Used : 1;
 
   /// \brief Whether this declaration was "referenced".
   /// The difference with 'Used' is whether the reference appears in a
@@ -505,10 +506,12 @@ public:
   /// whether the function is used.
   bool isUsed(bool CheckUsedAttr = true) const;
 
+  UsedAttr *getUsedAttr() const;
+
   /// \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; }
+  void setIsUsed();
 
   /// \brief Mark the declaration used, in the sense of odr-use.
   ///
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 88e1d04..3d6c240 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -7916,7 +7916,7 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
     return false;
 
   // Aliases and used decls are required.
-  if (D->hasAttr<AliasAttr>() || D->hasAttr<UsedAttr>())
+  if (D->hasAttr<AliasAttr>() || D->getUsedAttr())
     return true;
 
   if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index be1992a..de3e939 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -280,25 +280,49 @@ unsigned Decl::getMaxAlignment() const {
   return Align;
 }
 
-bool Decl::isUsed(bool CheckUsedAttr) const { 
+bool Decl::isUsed(bool CheckUsedAttr) const {
   if (Used)
     return true;
-  
+
   // Check for used attribute.
   if (CheckUsedAttr && hasAttr<UsedAttr>())
     return true;
 
-  return false; 
+  const Decl *D = getMostRecentDecl();
+
+  if (D->Used) {
+    Used = true;
+    return true;
+  }
+
+  // Check for used attribute.
+  if (CheckUsedAttr && D->hasAttr<UsedAttr>())
+    return true;
+
+  return false;
+}
+
+UsedAttr *Decl::getUsedAttr() const {
+  if (UsedAttr *Attr = getAttr<UsedAttr>())
+    return Attr;
+  const Decl *D = getMostRecentDecl();
+  return D->getAttr<UsedAttr>();
+}
+
+void Decl::setIsUsed() {
+  Decl *D = getMostRecentDecl();
+  D->Used = true;
+  Used = true;
 }
 
 void Decl::markUsed(ASTContext &C) {
-  if (Used)
+  if (isUsed(false))
     return;
 
   if (C.getASTMutationListener())
     C.getASTMutationListener()->DeclarationMarkedUsed(this);
 
-  Used = true;
+  setIsUsed();
 }
 
 bool Decl::isReferenced() const { 
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index 0f8ab1b..6a8b472 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -330,7 +330,7 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D,
   if (const SectionAttr *SA = D.getAttr<SectionAttr>())
     var->setSection(SA->getName());
 
-  if (D.hasAttr<UsedAttr>())
+  if (D.getUsedAttr())
     CGM.AddUsedGlobal(var);
 
   // We may have to cast the constant because of the initializer
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index d0f34dd..b61fd0a 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -713,7 +713,7 @@ void CodeGenModule::SetCommonAttributes(const Decl *D,
   else
     GV->setVisibility(llvm::GlobalValue::DefaultVisibility);
 
-  if (D->hasAttr<UsedAttr>())
+  if (D->getUsedAttr())
     AddUsedGlobal(GV);
 
   if (const SectionAttr *SA = D->getAttr<SectionAttr>())
@@ -1689,7 +1689,7 @@ void CodeGenModule::MaybeHandleStaticInExternC(const SomeDecl *D,
 
   // Must have 'used' attribute, or else inline assembly can't rely on
   // the name existing.
-  if (!D->template hasAttr<UsedAttr>())
+  if (!D->getUsedAttr())
     return;
 
   // Must have internal linkage and an ordinary name.
diff --git a/lib/CodeGen/ModuleBuilder.cpp b/lib/CodeGen/ModuleBuilder.cpp
index bc7acbc..7f66968 100644
--- a/lib/CodeGen/ModuleBuilder.cpp
+++ b/lib/CodeGen/ModuleBuilder.cpp
@@ -100,7 +100,7 @@ namespace {
              M != MEnd; ++M)
           if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*M))
             if (Method->doesThisDeclarationHaveABody() &&
-                (Method->hasAttr<UsedAttr>() || 
+                (Method->getUsedAttr() ||
                  Method->hasAttr<ConstructorAttr>()))
               Builder->EmitTopLevelDecl(Method);
       }
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 80f95e6..4928e23 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -2099,6 +2099,12 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) {
 /// mergeDeclAttributes - Copy attributes from the Old decl to the New one.
 void Sema::mergeDeclAttributes(NamedDecl *New, Decl *Old,
                                AvailabilityMergeKind AMK) {
+  if (UsedAttr *OldAttr = Old->getUsedAttr()) {
+    UsedAttr *NewAttr = OldAttr->clone(Context);
+    NewAttr->setInherited(true);
+    New->addAttr(NewAttr);
+  }
+
   if (!Old->hasAttrs() && !New->hasAttrs())
     return;
 
@@ -2136,6 +2142,10 @@ void Sema::mergeDeclAttributes(NamedDecl *New, Decl *Old,
       }
     }
 
+    // Already handled.
+    if (isa<UsedAttr>(*i))
+      continue;
+
     if (mergeDeclAttribute(*this, New, *i, Override))
       foundAny = true;
   }
@@ -2801,7 +2811,8 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old,
     New->setPure();
 
   // Merge "used" flag.
-  New->setIsUsed(Old->getMostRecentDecl()->isUsed(false));
+  if (Old->isUsed(false))
+    New->setIsUsed();
 
   // Merge attributes from the parameters.  These can mismatch with K&R
   // declarations.
@@ -3114,7 +3125,8 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
   }
 
   // Merge "used" flag.
-  New->setIsUsed(Old->getMostRecentDecl()->isUsed(false));
+  if (Old->isUsed(false))
+    New->setIsUsed();
 
   // Keep a chain of previous declarations.
   New->setPreviousDecl(Old);
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 56eeab3..2aa023b 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -11218,17 +11218,7 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func) {
       UndefinedButUsed.insert(std::make_pair(Func->getCanonicalDecl(), Loc));
   }
 
-  // Normally the most current decl is marked used while processing the use and
-  // any subsequent decls are marked used by decl merging. This fails with
-  // template instantiation since marking can happen at the end of the file
-  // and, because of the two phase lookup, this function is called with at
-  // 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.
-  for (FunctionDecl *F = Func->getMostRecentDecl();; F = F->getPreviousDecl()) {
-    F->markUsed(Context);
-    if (F == Func)
-      break;
-  }
+  Func->markUsed(Context);
 }
 
 static void
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index d1512c2..f90a8e6 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -3378,7 +3378,8 @@ void Sema::BuildVariableInstantiation(
   NewVar->setAccess(OldVar->getAccess());
 
   if (!OldVar->isStaticDataMember()) {
-    NewVar->setIsUsed(OldVar->isUsed(false));
+    if (OldVar->isUsed(false))
+      NewVar->setIsUsed();
     NewVar->setReferenced(OldVar->isReferenced());
   }
 
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index 463af77..278c441 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -386,7 +386,7 @@ void ASTDeclReader::VisitDecl(Decl *D) {
     D->setAttrsImpl(Attrs, Reader.getContext());
   }
   D->setImplicit(Record[Idx++]);
-  D->setIsUsed(Record[Idx++]);
+  D->Used = Record[Idx++];
   D->setReferenced(Record[Idx++]);
   D->setTopLevelDeclInObjCContainer(Record[Idx++]);
   D->setAccess((AccessSpecifier)Record[Idx++]);
@@ -2987,7 +2987,7 @@ void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile,
     case UPD_DECL_MARKED_USED: {
       // FIXME: This doesn't send the right notifications if there are
       // ASTMutationListeners other than an ASTWriter.
-      D->setIsUsed(true);
+      D->Used = true;
       break;
     }
     }
diff --git a/test/SemaCXX/warn-unused-filescoped.cpp b/test/SemaCXX/warn-unused-filescoped.cpp
index 65f10e6..b0af5b3 100644
--- a/test/SemaCXX/warn-unused-filescoped.cpp
+++ b/test/SemaCXX/warn-unused-filescoped.cpp
@@ -187,4 +187,10 @@ namespace UndefinedInternalStaticMember {
   }
 }
 
+namespace test8 {
+static void func();
+void bar() { void func() __attribute__((used)); }
+static void func() {}
+}
+
 #endif
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to