pcc updated this revision to Diff 50667.
pcc marked 3 inline comments as done.
pcc added a comment.

- Address review comments


http://reviews.llvm.org/D17893

Files:
  include/clang/AST/DeclCXX.h
  include/clang/Basic/Attr.td
  include/clang/Basic/AttrDocs.td
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Basic/LangOptions.h
  include/clang/Driver/Options.td
  include/clang/Sema/Sema.h
  lib/AST/DeclCXX.cpp
  lib/Basic/LangOptions.cpp
  lib/Driver/Tools.cpp
  lib/Frontend/CompilerInvocation.cpp
  lib/Sema/Sema.cpp
  lib/Sema/SemaDeclAttr.cpp
  lib/Sema/SemaDeclCXX.cpp
  test/Driver/funstable-cxx-abi.cpp
  test/SemaCXX/Inputs/unstable-abi-list-global1.txt
  test/SemaCXX/Inputs/unstable-abi-list-global2.txt
  test/SemaCXX/Inputs/unstable-abi-list.txt
  test/SemaCXX/attr-stability.cpp
  test/SemaCXX/unstable-cxx-abi-global1.cpp
  test/SemaCXX/unstable-cxx-abi-global2.cpp
  test/SemaCXX/unstable-cxx-abi-warning.cpp
  test/SemaCXX/unstable-cxx-abi.cpp

Index: test/SemaCXX/unstable-cxx-abi.cpp
===================================================================
--- /dev/null
+++ test/SemaCXX/unstable-cxx-abi.cpp
@@ -0,0 +1,91 @@
+// RUN: %clang_cc1 %s -std=c++11 -fsyntax-only -verify -funstable-c++-abi-classes=%S/Inputs/unstable-abi-list.txt -Wstable-c++-abi
+
+struct stable { // expected-note 3{{base 'stable' uses the stable ABI}} expected-warning {{stable C++ ABI was inferred for class 'stable'}} expected-note-re {{add the global namespace to file {{.*}} to silence this warning}}
+  virtual void f();
+};
+struct [[clang::unstable_abi]] unstable { // expected-note 3{{base 'unstable' uses the unstable ABI}}
+  virtual void f();
+};
+
+struct
+[[clang::stable_abi]] // expected-note {{stable ABI specified by attribute}}
+[[clang::unstable_abi]] // expected-note {{unstable ABI specified by attribute}}
+bistable { // expected-error {{inconsistent ABI for class 'bistable'}}
+  virtual void f();
+};
+
+struct mixed_bases : stable, unstable {}; // expected-error {{inconsistent ABI for class 'mixed_bases'}}
+struct mixed_base_vbase : stable, virtual unstable {}; // expected-error {{inconsistent ABI for class 'mixed_base_vbase'}}
+
+struct
+[[clang::unstable_abi]] // expected-note {{unstable ABI specified by attribute}}
+mixed_attr_base : stable { // expected-error {{inconsistent ABI for class 'mixed_attr_base'}}
+};
+
+struct
+[[clang::stable_abi]] // expected-note {{stable ABI specified by attribute}}
+mixed_attr_base2 : unstable { // expected-error {{inconsistent ABI for class 'mixed_attr_base2'}}
+};
+
+namespace std {
+
+struct unstable {
+  virtual void f();
+};
+
+}
+
+namespace std {
+
+namespace {
+
+struct unstable2 {
+  virtual void f();
+};
+
+namespace foo {
+
+struct unstable {
+  virtual void f();
+};
+
+}
+
+}
+
+namespace bar {
+
+struct stable { // expected-warning {{stable C++ ABI was inferred for class 'stable'}} expected-note-re {{add namespace 'std::bar' to file {{.*}} to silence this warning}}
+  virtual void f();
+};
+
+}
+
+struct non_dynamic {
+  struct unstable3 {
+    virtual void f();
+  };
+  void mf() {
+    struct unstable4 {
+      virtual void f();
+    };
+    struct unstable_derived : unstable, unstable4 {};
+  }
+};
+
+void f() {
+  struct unstable5 {
+    virtual void f();
+  };
+  struct unstable_derived : unstable, unstable5 {};
+}
+
+}
+
+struct stable2 : std::non_dynamic { // expected-warning {{stable C++ ABI was inferred for class 'stable2'}}  expected-note-re {{add the global namespace to file {{.*}} to silence this warning}}
+  virtual void f();
+};
+
+struct unstable_derived : unstable, std::unstable2, std::foo::unstable,
+                          std::non_dynamic::unstable3 {};
+struct stable_derived : stable, std::bar::stable, stable2 {};
Index: test/SemaCXX/unstable-cxx-abi-warning.cpp
===================================================================
--- /dev/null
+++ test/SemaCXX/unstable-cxx-abi-warning.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 %s -std=c++11 -fsyntax-only -verify -Wstable-c++-abi
+// RUN: %clang_cc1 %s -std=c++11 -fsyntax-only -verify -Wstable-c++-abi -funstable-c++-abi-classes=%S/Inputs/unstable-abi-list.txt -funstable-c++-abi-classes=%S/Inputs/unstable-abi-list-global1.txt
+
+namespace ns {
+
+class non_dynamic {};
+
+class dynamic { // expected-warning {{stable C++ ABI was inferred for class 'dynamic'}} expected-note {{add attribute clang::unstable_abi or clang::stable_abi to silence this warning}}
+  virtual void f();
+};
+
+}
Index: test/SemaCXX/unstable-cxx-abi-global2.cpp
===================================================================
--- /dev/null
+++ test/SemaCXX/unstable-cxx-abi-global2.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 %s -std=c++11 -fsyntax-only -verify -funstable-c++-abi-classes
+// RUN: %clang_cc1 %s -std=c++11 -fsyntax-only -verify -funstable-c++-abi-classes=%S/Inputs/unstable-abi-list-global2.txt
+
+namespace foo {
+
+struct unstable { // expected-note {{base 'unstable' uses the unstable ABI}}
+  virtual void f();
+};
+
+}
+
+struct unstable {
+  virtual void f();
+};
+
+struct [[clang::stable_abi]] stable { // expected-note {{base 'stable' uses the stable ABI}}
+  virtual void f();
+};
+
+struct unstable_derived : foo::unstable, unstable {};
+struct mixed_bases : foo::unstable, stable {}; // expected-error {{inconsistent ABI for class 'mixed_bases'}}
Index: test/SemaCXX/unstable-cxx-abi-global1.cpp
===================================================================
--- /dev/null
+++ test/SemaCXX/unstable-cxx-abi-global1.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 %s -std=c++11 -fsyntax-only -verify -funstable-c++-abi-classes=%S/Inputs/unstable-abi-list-global1.txt
+
+namespace foo {
+
+struct stable { // expected-note {{base 'stable' uses the stable ABI}}
+  virtual void f();
+};
+
+}
+
+struct unstable { // expected-note {{base 'unstable' uses the unstable ABI}}
+  virtual void f();
+};
+
+struct mixed_bases : foo::stable, unstable {};  // expected-error {{inconsistent ABI for class 'mixed_bases'}}
Index: test/SemaCXX/attr-stability.cpp
===================================================================
--- /dev/null
+++ test/SemaCXX/attr-stability.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -DABI=stable_abi %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -DABI=unstable_abi %s
+
+int i [[clang::ABI]]; // expected-warning {{attribute only applies to struct, union or class}}
+typedef int t [[clang::ABI]]; // expected-warning {{attribute only applies to struct, union or class}}
+[[clang::ABI]] void f(); // expected-warning {{attribute only applies to struct, union or class}}
+void f() [[clang::ABI]]; // expected-error {{attribute cannot be applied to types}}
+
+struct [[clang::ABI]] s { // expected-warning {{unused C++ ABI stability attribute on non-dynamic class}}
+  int i [[clang::ABI]]; // expected-warning {{attribute only applies to struct, union or class}}
+  [[clang::ABI]] void f(); // expected-warning {{attribute only applies to struct, union or class}}
+};
Index: test/SemaCXX/Inputs/unstable-abi-list.txt
===================================================================
--- /dev/null
+++ test/SemaCXX/Inputs/unstable-abi-list.txt
@@ -0,0 +1,2 @@
+unstable_glob::**
+std::*
Index: test/SemaCXX/Inputs/unstable-abi-list-global2.txt
===================================================================
--- /dev/null
+++ test/SemaCXX/Inputs/unstable-abi-list-global2.txt
@@ -0,0 +1 @@
+**
Index: test/SemaCXX/Inputs/unstable-abi-list-global1.txt
===================================================================
--- /dev/null
+++ test/SemaCXX/Inputs/unstable-abi-list-global1.txt
@@ -0,0 +1 @@
+*
Index: test/Driver/funstable-cxx-abi.cpp
===================================================================
--- /dev/null
+++ test/Driver/funstable-cxx-abi.cpp
@@ -0,0 +1,6 @@
+// RUN: %clang -funstable-c++-abi-classes -### %s 2>&1 | FileCheck -check-prefix=CLASSES %s
+// CLASSES: "-funstable-c++-abi-classes"
+
+// RUN: %clang -funstable-c++-abi-classes=foo.txt -### %s 2>&1 | FileCheck -check-prefix=CLASSES-ARG %s
+// CLASSES-ARG: "-funstable-c++-abi-classes=foo.txt"
+// CLASSES-ARG: "-fdepfile-entry=foo.txt"
Index: lib/Sema/SemaDeclCXX.cpp
===================================================================
--- lib/Sema/SemaDeclCXX.cpp
+++ lib/Sema/SemaDeclCXX.cpp
@@ -4887,6 +4887,146 @@
   }
 }
 
+void Sema::checkClassABI(CXXRecordDecl *Record) {
+  // This can only be done accurately for non-dependent types, as the
+  // determination uses the class's bases, which may be dependent.
+  if (Record->isDependentType())
+    return;
+
+  // No need to do this for non-dynamic classes.
+  if (!Record->isDynamicClass()) {
+    if (auto *A = Record->getAttr<StableABIAttr>())
+      Diag(A->getLocation(), diag::warn_unused_abi_stability_attr);
+    if (auto *A = Record->getAttr<UnstableABIAttr>())
+      Diag(A->getLocation(), diag::warn_unused_abi_stability_attr);
+    return;
+  }
+
+  // First, see if this class inherits an ABI from a dynamic base class. If the
+  // bases disagree on which ABI to use, diagnose.
+  bool InheritsABI = false;
+  bool InheritedABIIsUnstable;
+  CXXRecordDecl *InheritedABIFrom;
+
+  for (CXXBaseSpecifier &B : Record->bases()) {
+    auto Base = B.getType()->getAsCXXRecordDecl();
+    // Base can be null in invalid programs (see PR16677).
+    if (!Base || !Base->isDynamicClass())
+      continue;
+    if (InheritsABI) {
+      if (Base->isUnstableCXXABI() != InheritedABIIsUnstable) {
+        Diag(Record->getLocation(), diag::err_abi_mismatch) << Record;
+        CXXRecordDecl *Stable =
+            InheritedABIIsUnstable ? Base : InheritedABIFrom;
+        CXXRecordDecl *Unstable =
+            InheritedABIIsUnstable ? InheritedABIFrom : Base;
+        Diag(Stable->getLocation(), diag::note_abi_stability_base)
+            << Stable << /*Unstable=*/false;
+        Diag(Unstable->getLocation(), diag::note_abi_stability_base)
+            << Unstable << /*Unstable=*/true;
+      }
+    } else {
+      InheritsABI = true;
+      InheritedABIIsUnstable = Base->isUnstableCXXABI();
+      InheritedABIFrom = Base;
+    }
+  }
+
+  bool HasStableAttr = Record->hasAttr<StableABIAttr>();
+  bool HasUnstableAttr = Record->hasAttr<UnstableABIAttr>();
+  if (HasStableAttr && HasUnstableAttr) {
+    Diag(Record->getLocation(), diag::err_abi_mismatch) << Record;
+    Diag(Record->getAttr<StableABIAttr>()->getLocation(),
+         diag::note_abi_stability_attr) << /*Unstable=*/false;
+    Diag(Record->getAttr<UnstableABIAttr>()->getLocation(),
+         diag::note_abi_stability_attr) << /*Unstable=*/true;
+  }
+
+  // If the class inherited an ABI, the inherited ABI must agree with the
+  // class's attributes.
+  if (HasStableAttr && InheritsABI && InheritedABIIsUnstable) {
+    Diag(Record->getLocation(), diag::err_abi_mismatch) << Record;
+    Diag(InheritedABIFrom->getLocation(), diag::note_abi_stability_base)
+        << InheritedABIFrom << /*Unstable=*/true;
+    Diag(Record->getAttr<StableABIAttr>()->getLocation(),
+         diag::note_abi_stability_attr) << /*Unstable=*/false;
+  }
+  if (HasUnstableAttr && InheritsABI && !InheritedABIIsUnstable) {
+    Diag(Record->getLocation(), diag::err_abi_mismatch) << Record;
+    Diag(InheritedABIFrom->getLocation(), diag::note_abi_stability_base)
+        << InheritedABIFrom << /*Unstable=*/false;
+    Diag(Record->getAttr<UnstableABIAttr>()->getLocation(),
+         diag::note_abi_stability_attr) << /*Unstable=*/true;
+  }
+
+  if (HasStableAttr) {
+    return;
+  } else if (HasUnstableAttr) {
+    Record->setIsUnstableCXXABI();
+    return;
+  } else if (InheritsABI) {
+    if (InheritedABIIsUnstable)
+      Record->setIsUnstableCXXABI();
+    return;
+  }
+
+  // This class's ABI is not inherited or based on an attribute. Infer it from
+  // context.
+  if (UnstableABIContexts.empty() &&
+      UnstableABIGlobContexts.empty() &&
+      Diags.isIgnored(diag::warn_cxx_stable_abi, Record->getLocation()))
+    return;
+
+  // Find the innermost context not enclosed by an anonymous namespace, which
+  // is the context enclosing the outermost anonymous namespace.
+  DeclContext *NSContext = Record->getEnclosingNamespaceContext();
+  DeclContext *OutermostAnonNS = nullptr;
+  DeclContext *DC = NSContext;
+  while (DC) {
+    if (DC->isNamespace() && cast<NamespaceDecl>(DC)->isAnonymousNamespace())
+      OutermostAnonNS = DC;
+    DC = DC->getParent();
+  }
+  DeclContext *InnermostExternalDC = NSContext;
+  if (OutermostAnonNS)
+    InnermostExternalDC = OutermostAnonNS->getParent();
+  InnermostExternalDC = InnermostExternalDC->getPrimaryContext();
+
+  // Check if that context is in our set of contexts.
+  if (UnstableABIContexts.count(InnermostExternalDC)) {
+    Record->setIsUnstableCXXABI();
+    return;
+  }
+
+  // Check if that context or an enclosing context is in our set of glob
+  // contexts.
+  DC = InnermostExternalDC;
+  while (1) {
+    if (UnstableABIGlobContexts.count(DC)) {
+      Record->setIsUnstableCXXABI();
+      return;
+    }
+    DC = DC->getParent();
+    if (!DC)
+      break;
+    DC = DC->getPrimaryContext();
+  }
+
+  // Okay, we have inferred the stable ABI for this record. Warn if this is a
+  // non-system header.
+  if (!SourceMgr.isInSystemHeader(Record->getLocation())) {
+    Diag(Record->getLocation(), diag::warn_cxx_stable_abi)
+        << Record;
+    if (!getLangOpts().UnstableABIContextNamesPath.empty()) {
+      Diag(Record->getLocation(), diag::note_add_unstable_abi_file)
+          << InnermostExternalDC
+          << getLangOpts().UnstableABIContextNamesPath;
+    } else {
+      Diag(Record->getLocation(), diag::note_add_abi_stability_attr);
+    }
+  }
+}
+
 /// \brief Perform semantic checks on a class definition that has been
 /// completing, introducing implicitly-declared members, checking for
 /// abstract types, etc.
@@ -5026,6 +5166,8 @@
   DeclareInheritingConstructors(Record);
 
   checkClassLevelDLLAttribute(Record);
+
+  checkClassABI(Record);
 }
 
 /// Look up the special member function that would be called by a special
@@ -7250,7 +7392,18 @@
                                                  StartLoc, Loc, II, PrevNS);
   if (IsInvalid)
     Namespc->setInvalidDecl();
-  
+
+  // See if this namespace should be added to the set of unstable ABI contexts.
+  if ((!PrevNS || IsStd) && II &&
+      !getLangOpts().UnstableABIContextNames.empty()) {
+    NamespaceDecl *FirstNS = Namespc->getOriginalNamespace();
+    std::string Name = Namespc->getQualifiedNameAsString();
+    if (getLangOpts().isUnstableABIContextName(Name + "::*"))
+      UnstableABIContexts.insert(FirstNS);
+    else if (getLangOpts().isUnstableABIContextName(Name + "::**"))
+      UnstableABIGlobContexts.insert(FirstNS);
+  }
+
   ProcessDeclAttributeList(DeclRegionScope, Namespc, AttrList);
 
   // FIXME: Should we be merging attributes?
Index: lib/Sema/SemaDeclAttr.cpp
===================================================================
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -5675,6 +5675,12 @@
   case AttributeList::AT_InternalLinkage:
     handleInternalLinkageAttr(S, D, Attr);
     break;
+  case AttributeList::AT_StableABI:
+    handleSimpleAttribute<StableABIAttr>(S, D, Attr);
+    break;
+  case AttributeList::AT_UnstableABI:
+    handleSimpleAttribute<UnstableABIAttr>(S, D, Attr);
+    break;
 
   // Microsoft attributes:
   case AttributeList::AT_MSNoVTable:
Index: lib/Sema/Sema.cpp
===================================================================
--- lib/Sema/Sema.cpp
+++ lib/Sema/Sema.cpp
@@ -128,6 +128,11 @@
 
   // Initilization of data sharing attributes stack for OpenMP
   InitDataSharingAttributesStack();
+
+  if (LangOpts.isUnstableABIContextName("*"))
+    UnstableABIContexts.insert(ctxt.getTranslationUnitDecl());
+  if (LangOpts.isUnstableABIContextName("**"))
+    UnstableABIGlobContexts.insert(ctxt.getTranslationUnitDecl());
 }
 
 void Sema::addImplicitTypedef(StringRef Name, QualType T) {
Index: lib/Frontend/CompilerInvocation.cpp
===================================================================
--- lib/Frontend/CompilerInvocation.cpp
+++ lib/Frontend/CompilerInvocation.cpp
@@ -1477,6 +1477,29 @@
   return DefaultVisibility;
 }
 
+static void parseUnstableABIContextNameFile(std::vector<std::string> &Names,
+                                            StringRef Path,
+                                            DiagnosticsEngine &Diags) {
+  llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileOrErr =
+      llvm::MemoryBuffer::getFile(Path);
+  if (std::error_code EC = FileOrErr.getError()) {
+    Diags.Report(diag::err_fe_error_opening) << Path << EC.message();
+    return;
+  }
+
+  SmallVector<StringRef, 16> Lines;
+  SplitString(FileOrErr.get()->getBuffer(), Lines, "\n\r");
+  for (auto Line : Lines) {
+    auto Idx = Line.find('#');
+    if (Idx != StringRef::npos)
+      Line = Line.substr(0, Idx);
+
+    Line = Line.trim();
+    if (!Line.empty())
+      Names.push_back(Line);
+  }
+}
+
 static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
                           const TargetOptions &TargetOpts,
                           DiagnosticsEngine &Diags) {
@@ -1952,6 +1975,23 @@
   Opts.SanitizeAddressFieldPadding =
       getLastArgIntValue(Args, OPT_fsanitize_address_field_padding, 0, Diags);
   Opts.SanitizerBlacklistFiles = Args.getAllArgValues(OPT_fsanitize_blacklist);
+
+  if (Args.hasArg(OPT_funstable_cxx_abi_classes))
+    Opts.UnstableABIContextNames.push_back("**");
+
+  unsigned NumFiles = 0;
+  for (const Arg *A : Args.filtered(OPT_funstable_cxx_abi_classes_EQ)) {
+    ++NumFiles;
+    Opts.UnstableABIContextNamesPath = A->getValue();
+    parseUnstableABIContextNameFile(Opts.UnstableABIContextNames, A->getValue(),
+                                    Diags);
+  }
+
+  std::sort(Opts.UnstableABIContextNames.begin(),
+            Opts.UnstableABIContextNames.end());
+
+  if (NumFiles != 1)
+    Opts.UnstableABIContextNamesPath.clear();
 }
 
 static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
Index: lib/Driver/Tools.cpp
===================================================================
--- lib/Driver/Tools.cpp
+++ lib/Driver/Tools.cpp
@@ -5715,6 +5715,18 @@
       CmdArgs.push_back(I->getFilename());
     }
 
+  // Add unstable C++ ABI flags.
+  if (Args.hasArg(options::OPT_funstable_cxx_abi_classes))
+    CmdArgs.push_back("-funstable-c++-abi-classes");
+
+  for (const Arg *A :
+       Args.filtered(options::OPT_funstable_cxx_abi_classes_EQ)) {
+    CmdArgs.push_back(Args.MakeArgString(
+        std::string("-funstable-c++-abi-classes=") + A->getValue()));
+    CmdArgs.push_back(
+        Args.MakeArgString(std::string("-fdepfile-entry=") + A->getValue()));
+  }
+
   // Finally add the compile command to the compilation.
   if (Args.hasArg(options::OPT__SLASH_fallback) &&
       Output.getType() == types::TY_Object &&
Index: lib/Basic/LangOptions.cpp
===================================================================
--- lib/Basic/LangOptions.cpp
+++ lib/Basic/LangOptions.cpp
@@ -43,3 +43,8 @@
       return true;
   return false;
 }
+
+bool LangOptions::isUnstableABIContextName(const std::string &Name) const {
+  return std::binary_search(UnstableABIContextNames.begin(),
+                            UnstableABIContextNames.end(), Name);
+}
Index: lib/AST/DeclCXX.cpp
===================================================================
--- lib/AST/DeclCXX.cpp
+++ lib/AST/DeclCXX.cpp
@@ -70,8 +70,8 @@
       ImplicitCopyAssignmentHasConstParam(true),
       HasDeclaredCopyConstructorWithConstParam(false),
       HasDeclaredCopyAssignmentWithConstParam(false), IsLambda(false),
-      IsParsingBaseSpecifiers(false), NumBases(0), NumVBases(0), Bases(),
-      VBases(), Definition(D), FirstFriend() {}
+      IsParsingBaseSpecifiers(false), IsUnstableABI(false), NumBases(0),
+      NumVBases(0), Bases(), VBases(), Definition(D), FirstFriend() {}
 
 CXXBaseSpecifier *CXXRecordDecl::DefinitionData::getBasesSlowCase() const {
   return Bases.get(Definition->getASTContext().getExternalSource());
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -9343,6 +9343,20 @@
   // Emitting members of dllexported classes is delayed until the class
   // (including field initializers) is fully parsed.
   SmallVector<CXXRecordDecl*, 4> DelayedDllExportClasses;
+
+  /// A set of contexts that imply the unstable ABI for that context and any
+  /// enclosed contexts, excluding named namespaces.
+  llvm::DenseSet<DeclContext *> UnstableABIContexts;
+
+  /// A set of contexts that imply the unstable ABI for that context and any
+  /// enclosed contexts, including namespaces.
+  llvm::DenseSet<DeclContext *> UnstableABIGlobContexts;
+
+  /// Determine the ABI for this class using its attributes, bases and implicit
+  /// contexts. Check for conflicts between bases or between a base and an
+  /// attribute. Set the class's isUnstableCXXABI() flag according to the
+  /// result.
+  void checkClassABI(CXXRecordDecl *RD);
 };
 
 /// \brief RAII object that enters a new expression evaluation context.
Index: include/clang/Driver/Options.td
===================================================================
--- include/clang/Driver/Options.td
+++ include/clang/Driver/Options.td
@@ -1116,6 +1116,12 @@
 def funsigned_bitfields : Flag<["-"], "funsigned-bitfields">, Group<f_Group>;
 def funsigned_char : Flag<["-"], "funsigned-char">, Group<f_Group>;
 def fno_unsigned_char : Flag<["-"], "fno-unsigned-char">;
+def funstable_cxx_abi_classes : Flag<["-"], "funstable-c++-abi-classes">,
+  Group<f_Group>, Flags<[CC1Option]>,
+  HelpText<"Use the unstable C++ class ABI for all classes">;
+def funstable_cxx_abi_classes_EQ : Joined<["-"], "funstable-c++-abi-classes=">,
+  Group<f_Group>, Flags<[CC1Option]>,
+  HelpText<"Path to a list of namespaces that automatically use the unstable C++ class ABI">;
 def funwind_tables : Flag<["-"], "funwind-tables">, Group<f_Group>;
 def fuse_cxa_atexit : Flag<["-"], "fuse-cxa-atexit">, Group<f_Group>;
 def fuse_init_array : Flag<["-"], "fuse-init-array">, Group<f_Group>, Flags<[CC1Option]>,
Index: include/clang/Basic/LangOptions.h
===================================================================
--- include/clang/Basic/LangOptions.h
+++ include/clang/Basic/LangOptions.h
@@ -118,6 +118,17 @@
   /// host code generation.
   std::string OMPHostIRFile;
 
+  /// List of context names that should use the unstable ABI. This list is
+  /// sorted.
+  std::vector<std::string> UnstableABIContextNames;
+
+  /// If the unstable ABI context names were loaded from a single file, this
+  /// names the file.
+  std::string UnstableABIContextNamesPath;
+
+  /// Returns whether the argument names an unstable ABI context.
+  bool isUnstableABIContextName(const std::string &Name) const;
+
   LangOptions();
 
   // Define accessors/mutators for language options of enumeration type.
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -8369,4 +8369,22 @@
   "parameterized class %0 already conforms to the protocols listed; did you "
   "forget a '*'?">, InGroup<ObjCProtocolQualifiers>;
 
+def err_abi_mismatch : Error<
+  "inconsistent ABI for class %0">;
+def note_abi_stability_base : Note<
+  "base %0 uses the %select{stable|unstable}1 ABI">;
+def note_abi_stability_attr : Note<
+  "%select{stable|unstable}0 ABI specified by attribute">;
+
+def warn_unused_abi_stability_attr : Warning<
+  "unused C++ ABI stability attribute on non-dynamic class">,
+  InGroup<DiagGroup<"unused-stability-attr">>;
+def warn_cxx_stable_abi : Warning<
+  "stable C++ ABI was inferred for class %0">,
+  InGroup<DiagGroup<"stable-c++-abi">>, DefaultIgnore;
+def note_add_unstable_abi_file : Note<
+  "add %0 to file %1 to silence this warning">;
+def note_add_abi_stability_attr : Note<
+  "add attribute clang::unstable_abi or clang::stable_abi to silence this warning">;
+
 } // end of sema component.
Index: include/clang/Basic/AttrDocs.td
===================================================================
--- include/clang/Basic/AttrDocs.td
+++ include/clang/Basic/AttrDocs.td
@@ -2172,3 +2172,20 @@
 the old manged name and the new code will use the new mangled name with tags.
   }];
 }
+
+def ABIStabilityDocs : Documentation {
+  let Category = DocCatType;
+  let Content = [{
+The ``[[clang::stable_abi]]`` and ``[[clang::unstable_abi]]`` attributes
+control whether Clang has permission to use an unstable ABI for the attached
+class. It is an ODR violation to use ``[[clang::unstable_abi]]`` to define
+the same class in two translation units compiled with different versions of
+Clang. Specifically, mixing different head revisions or major releases is
+not allowed, but mixing different point releases is fine.
+
+Classes inherit ABI from their dynamic base classes (i.e. classes that have
+virtual member functions or virtual bases). It is an error to derive from
+two or more bases if their ABIs are incompatible, or to use an attribute to
+specify an ABI that is incompatible with a base.
+  }];
+}
Index: include/clang/Basic/Attr.td
===================================================================
--- include/clang/Basic/Attr.td
+++ include/clang/Basic/Attr.td
@@ -1576,6 +1576,18 @@
   let Documentation = [Undocumented];
 }
 
+def StableABI : InheritableAttr {
+  let Spellings = [CXX11<"clang", "stable_abi">];
+  let Subjects = SubjectList<[Record]>;
+  let Documentation = [ABIStabilityDocs];
+}
+
+def UnstableABI : InheritableAttr {
+  let Spellings = [CXX11<"clang", "unstable_abi">];
+  let Subjects = SubjectList<[Record]>;
+  let Documentation = [ABIStabilityDocs];
+}
+
 def AnyX86Interrupt : InheritableAttr, TargetSpecificAttr<TargetAnyX86> {
   // NOTE: If you add any additional spellings, ARMInterrupt's,
   // MSP430Interrupt's and MipsInterrupt's spellings must match.
Index: include/clang/AST/DeclCXX.h
===================================================================
--- include/clang/AST/DeclCXX.h
+++ include/clang/AST/DeclCXX.h
@@ -473,6 +473,9 @@
     /// \brief Whether we are currently parsing base specifiers.
     bool IsParsingBaseSpecifiers : 1;
 
+    /// \brief Whether the class uses the unstable ABI.
+    bool IsUnstableABI : 1;
+
     /// \brief The number of base class specifiers in Bases.
     unsigned NumBases;
 
@@ -708,6 +711,11 @@
     return data().IsParsingBaseSpecifiers;
   }
 
+  void setIsUnstableCXXABI() { data().IsUnstableABI = true; }
+  bool isUnstableCXXABI() const {
+    return data().IsUnstableABI;
+  }
+
   /// \brief Sets the base classes of this struct or class.
   void setBases(CXXBaseSpecifier const * const *Bases, unsigned NumBases);
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to