]> granicus.if.org Git - clang/commitdiff
Disable caching of visibility.
authorRafael Espindola <rafael.espindola@gmail.com>
Sat, 12 Jan 2013 06:42:30 +0000 (06:42 +0000)
committerRafael Espindola <rafael.espindola@gmail.com>
Sat, 12 Jan 2013 06:42:30 +0000 (06:42 +0000)
The testcase in pr14929 shows that this is extremely hard to do. If we choose
to apply the attribute, that causes the visibility of some decls to change and
that can happen really late (during codegen).

Current gcc warns and ignores the attribute in this testcase with a warning.
This suggest that the correct solution is to find a point in the compilation
where we can compute the visibility and
* assert it was never computed before
* reject any attempts to compute it again in the future (with warnings).

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@172305 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/Decl.h
include/clang/AST/DeclBase.h
include/clang/AST/Type.h
lib/AST/ASTContext.cpp
lib/AST/Decl.cpp
lib/AST/Type.cpp
lib/Sema/SemaAttr.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclAttr.cpp
test/CodeGenCXX/visibility-inlines-hidden.cpp
test/CodeGenCXX/visibility.cpp

index 12b6c4a980703961ddfe0aaa45e6aab450012684..da12a5f5917dad54f5d26d197afdfd21b2062d4e 100644 (file)
@@ -109,6 +109,7 @@ class NamedDecl : public Decl {
 
 private:
   NamedDecl *getUnderlyingDeclImpl();
+  void verifyLinkage() const;
 
 protected:
   NamedDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName N)
@@ -228,12 +229,6 @@ public:
              "Enum truncated!");
     }
 
-    bool operator==(const LinkageInfo &Other) {
-      return linkage_ == Other.linkage_ &&
-       visibility_ == Other.visibility_ &&
-       explicit_ == Other.explicit_;
-    }
-
     static LinkageInfo external() {
       return LinkageInfo();
     }
@@ -329,7 +324,7 @@ public:
 
   /// \brief Clear the linkage cache in response to a change
   /// to the declaration.
-  void ClearLVCache();
+  void ClearLinkageCache();
 
   /// \brief Looks through UsingDecls and ObjCCompatibleAliasDecls for
   /// the underlying named decl.
@@ -3337,7 +3332,7 @@ void Redeclarable<decl_type>::setPreviousDeclaration(decl_type *PrevDecl) {
   // First one will point to this one as latest.
   First->RedeclLink = LatestDeclLink(static_cast<decl_type*>(this));
   if (NamedDecl *ND = dyn_cast<NamedDecl>(static_cast<decl_type*>(this)))
-    ND->ClearLVCache();
+    ND->ClearLinkageCache();
 }
 
 // Inline function definitions.
index c91284d54a000a9689b1895027714b3d31bed25b..115edf6d92219571fdb8367717524accb80d7aa4 100644 (file)
@@ -242,7 +242,7 @@ private:
   SourceLocation Loc;
 
   /// DeclKind - This indicates which class this is.
-  unsigned DeclKind : 6;
+  unsigned DeclKind : 8;
 
   /// InvalidDecl - This indicates a semantic error occurred.
   unsigned InvalidDecl :  1;
@@ -284,16 +284,15 @@ protected:
   /// IdentifierNamespace - This specifies what IDNS_* namespace this lives in.
   unsigned IdentifierNamespace : 12;
 
-  /// These fields are only valid for NamedDecls subclasses.
+  /// \brief Whether the \c CachedLinkage field is active.
+  ///
+  /// This field is only valid for NamedDecls subclasses.
+  mutable unsigned HasCachedLinkage : 1;
+
+  /// \brief If \c HasCachedLinkage, the linkage of this declaration.
   ///
-  /// \brief Nonzero if the cache (i.e. the bitfields here starting
-  /// with 'Cache') is valid.  If so, then this is a
-  /// LangOptions::VisibilityMode+1.
-  mutable unsigned CacheValidAndVisibility : 2;
-  /// \brief the linkage of this declaration.
+  /// This field is only valid for NamedDecls subclasses.
   mutable unsigned CachedLinkage : 2;
-  /// \brief true if the visibility is explicit.
-  mutable unsigned CachedVisibilityExplicit : 1;
 
   friend class ASTDeclWriter;
   friend class ASTDeclReader;
@@ -310,7 +309,7 @@ protected:
       HasAttrs(false), Implicit(false), Used(false), Referenced(false),
       Access(AS_none), FromASTFile(0), Hidden(0),
       IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
-      CacheValidAndVisibility(0)
+      HasCachedLinkage(0)
   {
     if (StatisticsEnabled) add(DK);
   }
@@ -320,7 +319,7 @@ protected:
       HasAttrs(false), Implicit(false), Used(false), Referenced(false),
       Access(AS_none), FromASTFile(0), Hidden(0),
       IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
-      CacheValidAndVisibility(0)
+      HasCachedLinkage(0)
   {
     if (StatisticsEnabled) add(DK);
   }
index 98e2b6fb469c4c54eee2af855214289cf556ce73..2f1b48eb0f44b3cd299c60ceb0fc6343eeb7dfdc 100644 (file)
@@ -1781,7 +1781,7 @@ public:
   std::pair<Linkage,Visibility> getLinkageAndVisibility() const;
 
   /// \brief Note that the linkage is no longer known.
-  void ClearLVCache();
+  void ClearLinkageCache();
 
   const char *getTypeClassName() const;
 
index 409219a5715633a5f223e417b4ce5b3189db729f..83e6d6bd286d195bb1a7024fe519b5e5bb73eb2b 100644 (file)
@@ -958,7 +958,6 @@ ASTContext::setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl,
          "Already noted what static data member was instantiated from");
   InstantiatedFromStaticDataMember[Inst] 
     = new (*this) MemberSpecializationInfo(Tmpl, TSK, PointOfInstantiation);
-  Inst->ClearLVCache();
 }
 
 FunctionDecl *ASTContext::getClassScopeSpecializationPattern(
index bf5bfaaef10b3df043523c7f86ed594b9762a930..986430595bd61e228b2f95d907658e5a2d7a9229 100644 (file)
@@ -104,14 +104,8 @@ getLVForTemplateParameterList(const TemplateParameterList *Params) {
   return LV;
 }
 
-/// Compute the linkage and visibility for the given declaration.
-static LinkageInfo computeLVForDecl(const NamedDecl *D, bool OnlyTemplate);
-
-static LinkageInfo getLVForDecl(const NamedDecl *D, bool OnlyTemplate) {
-  if (!OnlyTemplate)
-    return D->getLinkageAndVisibility();
-  return computeLVForDecl(D, OnlyTemplate);
-}
+/// getLVForDecl - Get the linkage and visibility for the given declaration.
+static LinkageInfo getLVForDecl(const NamedDecl *D, bool OnlyTemplate);
 
 /// \brief Get the most restrictive linkage for the types and
 /// declarations in the given template argument list.
@@ -575,18 +569,18 @@ static void clearLinkageForClass(const CXXRecordDecl *record) {
          i = record->decls_begin(), e = record->decls_end(); i != e; ++i) {
     Decl *child = *i;
     if (isa<NamedDecl>(child))
-      cast<NamedDecl>(child)->ClearLVCache();
+      cast<NamedDecl>(child)->ClearLinkageCache();
   }
 }
 
 void NamedDecl::anchor() { }
 
-void NamedDecl::ClearLVCache() {
+void NamedDecl::ClearLinkageCache() {
   // Note that we can't skip clearing the linkage of children just
   // because the parent doesn't have cached linkage:  we don't cache
   // when computing linkage for parent contexts.
 
-  CacheValidAndVisibility = 0;
+  HasCachedLinkage = 0;
 
   // If we're changing the linkage of a class, we need to reset the
   // linkage of child declarations, too.
@@ -597,51 +591,66 @@ void NamedDecl::ClearLVCache() {
         dyn_cast<ClassTemplateDecl>(const_cast<NamedDecl*>(this))) {
     // Clear linkage for the template pattern.
     CXXRecordDecl *record = temp->getTemplatedDecl();
-    record->CacheValidAndVisibility = 0;
+    record->HasCachedLinkage = 0;
     clearLinkageForClass(record);
 
     // We need to clear linkage for specializations, too.
     for (ClassTemplateDecl::spec_iterator
            i = temp->spec_begin(), e = temp->spec_end(); i != e; ++i)
-      i->ClearLVCache();
+      i->ClearLinkageCache();
   }
 
   // Clear cached linkage for function template decls, too.
   if (FunctionTemplateDecl *temp =
         dyn_cast<FunctionTemplateDecl>(const_cast<NamedDecl*>(this))) {
-    temp->getTemplatedDecl()->ClearLVCache();
+    temp->getTemplatedDecl()->ClearLinkageCache();
     for (FunctionTemplateDecl::spec_iterator
            i = temp->spec_begin(), e = temp->spec_end(); i != e; ++i)
-      i->ClearLVCache();
+      i->ClearLinkageCache();
   }
     
 }
 
 Linkage NamedDecl::getLinkage() const {
-  return getLinkageAndVisibility().linkage();
+  if (HasCachedLinkage) {
+    assert(Linkage(CachedLinkage) ==
+           getLVForDecl(this, true).linkage());
+    return Linkage(CachedLinkage);
+  }
+
+  CachedLinkage = getLVForDecl(this, true).linkage();
+  HasCachedLinkage = 1;
+
+#ifndef NDEBUG
+  verifyLinkage();
+#endif
+
+  return Linkage(CachedLinkage);
 }
 
 LinkageInfo NamedDecl::getLinkageAndVisibility() const {
-  if (CacheValidAndVisibility) {
-    Linkage L = static_cast<Linkage>(CachedLinkage);
-    Visibility V = static_cast<Visibility>(CacheValidAndVisibility - 1);
-    bool Explicit = CachedVisibilityExplicit;
-    LinkageInfo LV(L, V, Explicit);
-    assert(LV == computeLVForDecl(this, false));
-    return LV;
+  LinkageInfo LI = getLVForDecl(this, false);
+  if (HasCachedLinkage) {
+    assert(Linkage(CachedLinkage) == LI.linkage());
+    return LI;
   }
-  LinkageInfo LV = computeLVForDecl(this, false);
-  CachedLinkage = LV.linkage();
-  CacheValidAndVisibility = LV.visibility() + 1;
-  CachedVisibilityExplicit = LV.visibilityExplicit();
+  HasCachedLinkage = 1;
+  CachedLinkage = LI.linkage();
 
 #ifndef NDEBUG
+  verifyLinkage();
+#endif
+
+  return LI;
+}
+
+void NamedDecl::verifyLinkage() const {
   // In C (because of gnu inline) and in c++ with microsoft extensions an
   // static can follow an extern, so we can have two decls with different
   // linkages.
   const LangOptions &Opts = getASTContext().getLangOpts();
   if (!Opts.CPlusPlus || Opts.MicrosoftExt)
-    return LV;
+    return;
 
   // We have just computed the linkage for this decl. By induction we know
   // that all other computed linkages match, check that the one we just computed
@@ -651,15 +660,12 @@ LinkageInfo NamedDecl::getLinkageAndVisibility() const {
     NamedDecl *T = cast<NamedDecl>(*I);
     if (T == this)
       continue;
-    if (T->CacheValidAndVisibility != 0) {
+    if (T->HasCachedLinkage != 0) {
       D = T;
       break;
     }
   }
   assert(!D || D->CachedLinkage == CachedLinkage);
-#endif
-
-  return LV;
 }
 
 llvm::Optional<Visibility> NamedDecl::getExplicitVisibility() const {
@@ -723,7 +729,7 @@ llvm::Optional<Visibility> NamedDecl::getExplicitVisibility() const {
   return llvm::Optional<Visibility>();
 }
 
-static LinkageInfo computeLVForDecl(const NamedDecl *D, bool OnlyTemplate) {
+static LinkageInfo getLVForDecl(const NamedDecl *D, bool OnlyTemplate) {
   // Objective-C: treat all Objective-C declarations as having external
   // linkage.
   switch (D->getKind()) {
@@ -1192,7 +1198,7 @@ VarDecl *VarDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
 void VarDecl::setStorageClass(StorageClass SC) {
   assert(isLegalForVariable(SC));
   if (getStorageClass() != SC)
-    ClearLVCache();
+    ClearLinkageCache();
   
   VarDeclBits.SClass = SC;
 }
@@ -1714,9 +1720,6 @@ void FunctionDecl::setBody(Stmt *B) {
   Body = B;
   if (B)
     EndRangeLoc = B->getLocEnd();
-  for (redecl_iterator R = redecls_begin(), REnd = redecls_end(); R != REnd;
-       ++R)
-    R->ClearLVCache();
 }
 
 void FunctionDecl::setPure(bool P) {
@@ -1825,7 +1828,7 @@ FunctionDecl *FunctionDecl::getCanonicalDecl() {
 void FunctionDecl::setStorageClass(StorageClass SC) {
   assert(isLegalForFunction(SC));
   if (getStorageClass() != SC)
-    ClearLVCache();
+    ClearLinkageCache();
   
   SClass = SC;
 }
@@ -2595,8 +2598,8 @@ TagDecl* TagDecl::getCanonicalDecl() {
 void TagDecl::setTypedefNameForAnonDecl(TypedefNameDecl *TDD) { 
   TypedefNameDeclOrQualifier = TDD; 
   if (TypeForDecl)
-    const_cast<Type*>(TypeForDecl)->ClearLVCache();
-  ClearLVCache();
+    const_cast<Type*>(TypeForDecl)->ClearLinkageCache();
+  ClearLinkageCache();
 }
 
 void TagDecl::startDefinition() {
index bb79b9b57bf890ffae630ab71af457cf6d48e8b8..45ec4edbc581ece2f0925bda0a819f6ea0844976 100644 (file)
@@ -2190,7 +2190,7 @@ std::pair<Linkage,Visibility> Type::getLinkageAndVisibility() const {
   return std::make_pair(TypeBits.getLinkage(), TypeBits.getVisibility());
 }
 
-void Type::ClearLVCache() {
+void Type::ClearLinkageCache() {
   TypeBits.CacheValidAndVisibility = 0;
   if (QualType(this, 0) != CanonicalType)
     CanonicalType->TypeBits.CacheValidAndVisibility = 0;
index 3bfb8f22b461aefc4996fdfd272f03e585040724..b212b3fee006603a5de334725a97609ada7fa731 100644 (file)
@@ -321,7 +321,6 @@ void Sema::AddPushedVisibilityAttribute(Decl *D) {
     = (VisibilityAttr::VisibilityType) rawType;
   SourceLocation loc = Stack->back().second;
 
-  ND->ClearLVCache();
   D->addAttr(::new (Context) VisibilityAttr(loc, Context, type));
 }
 
index c3a2ad11230fe7d325c7bda489d33809ea754964..b9d141bc351aca5c04613d865c638cfe166e1b36 100644 (file)
@@ -1824,18 +1824,14 @@ DeclHasAttr(const Decl *D, const Attr *A) {
 
 bool Sema::mergeDeclAttribute(NamedDecl *D, InheritableAttr *Attr) {
   InheritableAttr *NewAttr = NULL;
-  if (AvailabilityAttr *AA = dyn_cast<AvailabilityAttr>(Attr)) {
+  if (AvailabilityAttr *AA = dyn_cast<AvailabilityAttr>(Attr))
     NewAttr = mergeAvailabilityAttr(D, AA->getRange(), AA->getPlatform(),
                                     AA->getIntroduced(), AA->getDeprecated(),
                                     AA->getObsoleted(), AA->getUnavailable(),
                                     AA->getMessage());
-    if (NewAttr)
-      D->ClearLVCache();
-  } else if (VisibilityAttr *VA = dyn_cast<VisibilityAttr>(Attr)) {
+  else if (VisibilityAttr *VA = dyn_cast<VisibilityAttr>(Attr))
     NewAttr = mergeVisibilityAttr(D, VA->getRange(), VA->getVisibility());
-    if (NewAttr)
-      D->ClearLVCache();
-  } else if (DLLImportAttr *ImportA = dyn_cast<DLLImportAttr>(Attr))
+  else if (DLLImportAttr *ImportA = dyn_cast<DLLImportAttr>(Attr))
     NewAttr = mergeDLLImportAttr(D, ImportA->getRange());
   else if (DLLExportAttr *ExportA = dyn_cast<DLLExportAttr>(Attr))
     NewAttr = mergeDLLExportAttr(D, ExportA->getRange());
@@ -6695,7 +6691,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
     }
     VDecl->setTypeSourceInfo(DeducedType);
     VDecl->setType(DeducedType->getType());
-    VDecl->ClearLVCache();
+    VDecl->ClearLinkageCache();
     
     // In ARC, infer lifetime.
     if (getLangOpts().ObjCAutoRefCount && inferObjCARCLifetime(VDecl))
index 225ee24d0fce3e81fc503465bf7bd87b4e8ca523..9c17d6eabdaad09307197319650012ee170807b8 100644 (file)
@@ -2043,7 +2043,6 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range,
   VersionTuple MergedDeprecated = Deprecated;
   VersionTuple MergedObsoleted = Obsoleted;
   bool FoundAny = false;
-  bool DroppedAny = false;
 
   if (D->hasAttrs()) {
     AttrVec &Attrs = D->getAttrs();
@@ -2078,7 +2077,6 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range,
         Diag(OldAA->getLocation(), diag::warn_mismatched_availability);
         Diag(Range.getBegin(), diag::note_previous_attribute);
         Attrs.erase(Attrs.begin() + i);
-        DroppedAny = true;
         --e;
         continue;
       }
@@ -2098,7 +2096,6 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range,
                                 MergedIntroduced2, MergedDeprecated2,
                                 MergedObsoleted2)) {
         Attrs.erase(Attrs.begin() + i);
-        DroppedAny = true;
         --e;
         continue;
       }
@@ -2110,9 +2107,6 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range,
     }
   }
 
-  if (DroppedAny)
-    D->ClearLVCache();
-
   if (FoundAny &&
       MergedIntroduced == Introduced &&
       MergedDeprecated == Deprecated &&
@@ -2159,10 +2153,8 @@ static void handleAvailabilityAttr(Sema &S, Decl *D,
                                                       Deprecated.Version,
                                                       Obsoleted.Version,
                                                       IsUnavailable, Str);
-  if (NewAttr) {
+  if (NewAttr)
     D->addAttr(NewAttr);
-    ND->ClearLVCache();
-  }
 }
 
 VisibilityAttr *Sema::mergeVisibilityAttr(Decl *D, SourceRange Range,
@@ -2179,8 +2171,6 @@ VisibilityAttr *Sema::mergeVisibilityAttr(Decl *D, SourceRange Range,
     Diag(ExistingAttr->getLocation(), diag::err_mismatched_visibility);
     Diag(Range.getBegin(), diag::note_previous_attribute);
     D->dropAttr<VisibilityAttr>();
-    NamedDecl *ND = cast<NamedDecl>(D);
-    ND->ClearLVCache();
   }
   return ::new (Context) VisibilityAttr(Range, Context, Vis);
 }
@@ -2224,11 +2214,8 @@ static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr) {
   }
 
   VisibilityAttr *NewAttr = S.mergeVisibilityAttr(D, Attr.getRange(), type);
-  if (NewAttr) {
+  if (NewAttr)
     D->addAttr(NewAttr);
-    NamedDecl *ND = cast<NamedDecl>(D);
-    ND->ClearLVCache();
-  }
 }
 
 static void handleObjCMethodFamilyAttr(Sema &S, Decl *decl,
index 0681adda839f64f3f0f44b9c0b7a94cedbad7571..e5bc743e4da9de0ad217f6a1395b4e75f3d8952c 100644 (file)
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-unknown-unknown -fvisibility-inlines-hidden -emit-llvm -o - %s -O2 -disable-llvm-optzns | FileCheck %s
+// RUN: %clang_cc1 -triple i386-unknown-unknown -std=c++11 -fvisibility-inlines-hidden -emit-llvm -o - %s -O2 -disable-llvm-optzns | FileCheck %s
 
 // The trickery with optimization in the run line is to get IR
 // generation to emit available_externally function bodies, but not
@@ -147,3 +147,18 @@ namespace test5 {
   template <int Idx_nocapture> void Op() {
   }
 }
+
+namespace test6 {
+  // just don't crash.
+  template <typename T>
+  void f(T x) {
+  }
+  struct C {
+    static void g() {
+      f([](){});
+    }
+  };
+  void g() {
+    C::g();
+  }
+}
index 014503911a49853a6bc39a6fd4bb976a41c910f7..a196dda643dcc7ab99b107bde26fcf8702ce5bc8 100644 (file)
@@ -1112,3 +1112,47 @@ namespace test60 {
     // CHECK-HIDDEN: define linkonce_odr hidden void @_ZN6test604testINS_1bENS_1aEEEvv
   }
 }
+
+namespace test61 {
+  template <typename T1>
+  struct Class1
+  {
+    void f1() { f2(); }
+    inline void f2();
+  };
+  template<>
+  inline void Class1<int>::f2()
+  {
+  }
+  void g(Class1<int> *x) {
+    x->f1();
+  }
+}
+namespace test61 {
+  // Just test that we don't crash. Currently we apply this attribute. Current
+  // gcc issues a warning about it being unused since "the type is already
+  // defined". We should probably do the same.
+  template class __attribute__ ((visibility("hidden"))) Class1<int>;
+}
+
+namespace test62 {
+  template <typename T1>
+  struct Class1
+  {
+    void f1() { f2(); }
+    inline void f2() {}
+  };
+  template<>
+  inline void Class1<int>::f2()
+  {
+  }
+  void g(Class1<int> *x) {
+    x->f2();
+  }
+}
+namespace test62 {
+  template class __attribute__ ((visibility("hidden"))) Class1<int>;
+  // Just test that we don't crash. Currently we apply this attribute. Current
+  // gcc issues a warning about it being unused since "the type is already
+  // defined". We should probably do the same.
+}