]> granicus.if.org Git - clang/commitdiff
Ignore the "novtable" declspec when not using the Microsoft C++ ABI.
authorBob Wilson <bob.wilson@apple.com>
Mon, 20 Jul 2015 22:57:31 +0000 (22:57 +0000)
committerBob Wilson <bob.wilson@apple.com>
Mon, 20 Jul 2015 22:57:31 +0000 (22:57 +0000)
Clang used to silently ignore __declspec(novtable). It is implemented
now, but leaving the vtable uninitialized does not work when using the
Itanium ABI, where the class layout for complex class hierarchies is
stored in the vtable. It might be possible to honor the novtable
attribute in some simple cases and either report an error or ignore
it in more complex situations, but it’s not clear if that would be
worthwhile. There is also value in having a simple and predictable
behavior, so this changes clang to simply ignore novtable when not using
the Microsoft C++ ABI.

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

13 files changed:
include/clang/Basic/Attr.td
include/clang/Basic/Attributes.h
include/clang/Sema/AttributeList.h
lib/Basic/Attributes.cpp
lib/Lex/PPMacroExpansion.cpp
lib/Parse/ParseDecl.cpp
lib/Parse/ParseDeclCXX.cpp
lib/Sema/AttributeList.cpp
lib/Sema/SemaDeclAttr.cpp
test/Parser/MicrosoftExtensions.cpp
test/SemaCXX/ms-novtable.cpp
test/SemaCXX/ms-unsupported.cpp [new file with mode: 0644]
utils/TableGen/ClangAttrEmitter.cpp

index 11b3263d705e0f3902946e80a90c3bc79957cf30..753e42c950ae36e55933c70f0e01563ba1d87c6d 100644 (file)
@@ -241,14 +241,18 @@ def COnly : LangOpt<"CPlusPlus", 1>;
 class TargetArch<list<string> arches> {
   list<string> Arches = arches;
   list<string> OSes;
+  list<string> CXXABIs;
 }
 def TargetARM : TargetArch<["arm", "thumb"]>;
+def TargetMips : TargetArch<["mips", "mipsel"]>;
 def TargetMSP430 : TargetArch<["msp430"]>;
 def TargetX86 : TargetArch<["x86"]>;
 def TargetWindows : TargetArch<["x86", "x86_64", "arm", "thumb"]> {
   let OSes = ["Win32"];
 }
-def TargetMips : TargetArch<["mips", "mipsel"]>;
+def TargetMicrosoftCXXABI : TargetArch<["x86", "x86_64", "arm", "thumb"]> {
+  let CXXABIs = ["Microsoft"];
+}
 
 class Attr {
   // The various ways in which an attribute can be spelled in source
@@ -1820,7 +1824,7 @@ def TypeTagForDatatype : InheritableAttr {
 
 // Microsoft-related attributes
 
-def MSNoVTable : InheritableAttr {
+def MSNoVTable : InheritableAttr, TargetSpecificAttr<TargetMicrosoftCXXABI> {
   let Spellings = [Declspec<"novtable">];
   let Subjects = SubjectList<[CXXRecord]>;
   let Documentation = [MSNoVTableDocs];
index a64dd5666b73a0dce6672bf6d262f7f8cfe39c40..a2b86841cddf60ab5581f4195b5a6b54a059d7e6 100644 (file)
@@ -11,7 +11,7 @@
 #define LLVM_CLANG_BASIC_ATTRIBUTES_H
 
 #include "clang/Basic/LangOptions.h"
-#include "llvm/ADT/Triple.h"
+#include "clang/Basic/TargetInfo.h"
 
 namespace clang {
 
@@ -31,7 +31,7 @@ enum class AttrSyntax {
 /// \brief Return the version number associated with the attribute if we
 /// recognize and implement the attribute specified by the given information.
 int hasAttribute(AttrSyntax Syntax, const IdentifierInfo *Scope,
-                 const IdentifierInfo *Attr, const llvm::Triple &T,
+                 const IdentifierInfo *Attr, const TargetInfo &Target,
                  const LangOptions &LangOpts);
 
 } // end namespace clang
index 2fedc79401f02e83ea0bdc31a89ff07b008f6c4e..ca456b2f9bb9b27add7bd3f887bb08fa8f1bb85f 100644 (file)
 #define LLVM_CLANG_SEMA_ATTRIBUTELIST_H
 
 #include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/TargetInfo.h"
 #include "clang/Basic/VersionTuple.h"
 #include "clang/Sema/Ownership.h"
 #include "llvm/ADT/PointerUnion.h"
 #include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/Triple.h"
 #include "llvm/Support/Allocator.h"
 #include <cassert>
 
@@ -464,7 +464,7 @@ public:
   bool hasVariadicArg() const;
   bool diagnoseAppertainsTo(class Sema &S, const Decl *D) const;
   bool diagnoseLangOpts(class Sema &S) const;
-  bool existsInTarget(const llvm::Triple &T) const;
+  bool existsInTarget(const TargetInfo &Target) const;
   bool isKnownToGCC() const;
 
   /// \brief If the parsed attribute has a semantic equivalent, and it would
index da9ac793f163b6b26cf459bc5cb5e83c5fa82f4b..c215366fc398a2fd024b385f6e499016a1dda728 100644 (file)
@@ -4,8 +4,8 @@
 using namespace clang;
 
 int clang::hasAttribute(AttrSyntax Syntax, const IdentifierInfo *Scope,
-                         const IdentifierInfo *Attr, const llvm::Triple &T,
-                         const LangOptions &LangOpts) {
+                        const IdentifierInfo *Attr, const TargetInfo &Target,
+                        const LangOptions &LangOpts) {
   StringRef Name = Attr->getName();
   // Normalize the attribute name, __foo__ becomes foo.
   if (Name.size() >= 4 && Name.startswith("__") && Name.endswith("__"))
index 1324ca93451f1aff11b1907456eafa729f09510c..42b1d048c40a55b96ca0b3151f7d11b78bb690ce 100644 (file)
@@ -1633,13 +1633,13 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
       Value = FeatureII->getBuiltinID() != 0;
     } else if (II == Ident__has_attribute)
       Value = hasAttribute(AttrSyntax::GNU, nullptr, FeatureII,
-                           getTargetInfo().getTriple(), getLangOpts());
+                           getTargetInfo(), getLangOpts());
     else if (II == Ident__has_cpp_attribute)
       Value = hasAttribute(AttrSyntax::CXX, ScopeII, FeatureII,
-                           getTargetInfo().getTriple(), getLangOpts());
+                           getTargetInfo(), getLangOpts());
     else if (II == Ident__has_declspec)
       Value = hasAttribute(AttrSyntax::Declspec, nullptr, FeatureII,
-                           getTargetInfo().getTriple(), getLangOpts());
+                           getTargetInfo(), getLangOpts());
     else if (II == Ident__has_extension)
       Value = HasExtension(*this, FeatureII);
     else {
index f46af889e25def8ad0aaec9f79fef6288cb508b7..acfe0ca0e82c23eb647f88a797c00ac7c2f455c3 100644 (file)
@@ -387,7 +387,7 @@ bool Parser::ParseMicrosoftDeclSpecArgs(IdentifierInfo *AttrName,
   // If the attribute isn't known, we will not attempt to parse any
   // arguments.
   if (!hasAttribute(AttrSyntax::Declspec, nullptr, AttrName,
-                    getTargetInfo().getTriple(), getLangOpts())) {
+                    getTargetInfo(), getLangOpts())) {
     // Eat the left paren, then skip to the ending right paren.
     ConsumeParen();
     SkipUntil(tok::r_paren);
index e347d4e27e2697f1136512c07241e5d1ba6bbb90..0fb1de94e8ead0b8503330558b5d9c883ca66f32 100644 (file)
@@ -3612,7 +3612,7 @@ bool Parser::ParseCXX11AttributeArgs(IdentifierInfo *AttrName,
   // If the attribute isn't known, we will not attempt to parse any
   // arguments.
   if (!hasAttribute(AttrSyntax::CXX, ScopeName, AttrName,
-                    getTargetInfo().getTriple(), getLangOpts())) {
+                    getTargetInfo(), getLangOpts())) {
     // Eat the left paren, then skip to the ending right paren.
     ConsumeParen();
     SkipUntil(tok::r_paren);
index 34af6cf63c872aa201d77295398e43798fbbb141..1ea40606f44b063b44c0ee76ffac925c5b0de13c 100644 (file)
@@ -17,6 +17,7 @@
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/Expr.h"
 #include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/TargetInfo.h"
 #include "clang/Sema/SemaInternal.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringSwitch.h"
@@ -155,7 +156,7 @@ struct ParsedAttrInfo {
   bool (*DiagAppertainsToDecl)(Sema &S, const AttributeList &Attr,
                                const Decl *);
   bool (*DiagLangOpts)(Sema &S, const AttributeList &Attr);
-  bool (*ExistsInTarget)(const llvm::Triple &T);
+  bool (*ExistsInTarget)(const TargetInfo &Target);
   unsigned (*SpellingIndexToSemanticSpelling)(const AttributeList &Attr);
 };
 
@@ -195,8 +196,8 @@ bool AttributeList::isTypeAttr() const {
   return getInfo(*this).IsType;
 }
 
-bool AttributeList::existsInTarget(const llvm::Triple &T) const {
-  return getInfo(*this).ExistsInTarget(T);
+bool AttributeList::existsInTarget(const TargetInfo &Target) const {
+  return getInfo(*this).ExistsInTarget(Target);
 }
 
 bool AttributeList::isKnownToGCC() const {
index 9ec3356d048ffd0449e0a70ec1460841f4510ca8..3395381b6a3650c21bcdc2e074b6af9c42d74dfa 100644 (file)
@@ -4583,7 +4583,7 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
   // which do not apply to the current target architecture are treated as
   // though they were unknown attributes.
   if (Attr.getKind() == AttributeList::UnknownAttribute ||
-      !Attr.existsInTarget(S.Context.getTargetInfo().getTriple())) {
+      !Attr.existsInTarget(S.Context.getTargetInfo())) {
     S.Diag(Attr.getLoc(), Attr.isDeclspecAttribute()
                               ? diag::warn_unhandled_ms_attribute_ignored
                               : diag::warn_unknown_attribute_ignored)
index e674d0101e971978b13eacc34ae42148a2d95b40..efb9490697e762df1696db26ff864abe341f1305 100644 (file)
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -triple i386-mingw32 -std=c++14 -fsyntax-only -Wno-unused-getter-return-value -Wno-unused-value -Wmicrosoft -verify -fms-extensions -fms-compatibility -fdelayed-template-parsing
+// RUN: %clang_cc1 %s -triple i386-pc-win32 -std=c++14 -fsyntax-only -Wno-unused-getter-return-value -Wno-unused-value -Wmicrosoft -verify -fms-extensions -fms-compatibility -fdelayed-template-parsing
 
 /* Microsoft attribute tests */
 [repeatable][source_annotation_attribute( Parameter|ReturnValue )]
index 2d55c48df3c71d7557f6a37a8f4d591038448d9b..31975b3b4a8441e76fed326f8bdf38986523fc3e 100644 (file)
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -fsyntax-only -verify -fms-extensions -Wno-microsoft -std=c++11
+// RUN: %clang_cc1 -triple i386-pc-win32 %s -fsyntax-only -verify -fms-extensions -Wno-microsoft -std=c++11
 
 struct __declspec(novtable) S {};
 enum __declspec(novtable) E {}; // expected-warning{{'novtable' attribute only applies to classes}}
diff --git a/test/SemaCXX/ms-unsupported.cpp b/test/SemaCXX/ms-unsupported.cpp
new file mode 100644 (file)
index 0000000..559d703
--- /dev/null
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -triple x86_64-pc-windows-gnu %s -fsyntax-only -verify -fms-extensions -Wno-microsoft -std=c++11
+
+// "novtable" is ignored except with the Microsoft C++ ABI.
+// MinGW uses the Itanium C++ ABI so check that it is ignored there.
+struct __declspec(novtable) S {}; // expected-warning{{__declspec attribute 'novtable' is not supported}}
index 5dc33a000a42af3ca5240a3e9f36f7d1ca10c23c..c96777d1e89a7721897dd2165cf7b0319cbca484 100644 (file)
@@ -1885,7 +1885,8 @@ static void GenerateHasAttrSpellingStringSwitch(
       }
     }
 
-    // It is assumed that there will be an llvm::Triple object named T within
+    // It is assumed that there will be an llvm::Triple object
+    // named "T" and a TargetInfo object named "Target" within
     // scope that can be used to determine whether the attribute exists in
     // a given target.
     std::string Test;
@@ -1902,6 +1903,7 @@ static void GenerateHasAttrSpellingStringSwitch(
       }
       Test += ")";
 
+      // If the attribute is specific to particular OSes, check those.
       std::vector<std::string> OSes;
       if (!R->isValueUnset("OSes")) {
         Test += " && (";
@@ -1916,6 +1918,21 @@ static void GenerateHasAttrSpellingStringSwitch(
         Test += ")";
       }
       
+      // If one or more CXX ABIs are specified, check those as well.
+      if (!R->isValueUnset("CXXABIs")) {
+        Test += " && (";
+        std::vector<std::string> CXXABIs =
+          R->getValueAsListOfStrings("CXXABIs");
+        for (auto AI = CXXABIs.begin(), AE = CXXABIs.end(); AI != AE; ++AI) {
+          std::string Part = *AI;
+
+          Test += "Target.getCXXABI().getKind() == TargetCXXABI::" + Part;
+          if (AI + 1 != AE)
+            Test += " || ";
+        }
+        Test += ")";
+      }
+
       // If this is the C++11 variety, also add in the LangOpts test.
       if (Variety == "CXX11")
         Test += " && LangOpts.CPlusPlus11";
@@ -1962,6 +1979,7 @@ void EmitClangAttrHasAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
     }
   }
 
+  OS << "const llvm::Triple &T = Target.getTriple();\n";
   OS << "switch (Syntax) {\n";
   OS << "case AttrSyntax::GNU:\n";
   OS << "  return llvm::StringSwitch<int>(Name)\n";
@@ -2464,7 +2482,7 @@ static std::string GenerateLangOptRequirements(const Record &R,
 }
 
 static void GenerateDefaultTargetRequirements(raw_ostream &OS) {
-  OS << "static bool defaultTargetRequirements(const llvm::Triple &) {\n";
+  OS << "static bool defaultTargetRequirements(const TargetInfo &) {\n";
   OS << "  return true;\n";
   OS << "}\n\n";
 }
@@ -2533,6 +2551,20 @@ static std::string GenerateTargetRequirements(const Record &Attr,
     Test += ")";
   }
 
+  // Test for the C++ ABI, if specified.
+  if (!R->isValueUnset("CXXABIs")) {
+    Test += " && (";
+    std::vector<std::string> CXXABIs = R->getValueAsListOfStrings("CXXABIs");
+    for (auto I = CXXABIs.begin(), E = CXXABIs.end(); I != E; ++I) {
+      std::string Part = *I;
+      Test += "Target.getCXXABI().getKind() == TargetCXXABI::" + Part;
+      if (I + 1 != E)
+        Test += " || ";
+      FnName += Part;
+    }
+    Test += ")";
+  }
+
   // If this code has already been generated, simply return the previous
   // instance of it.
   static std::set<std::string> CustomTargetSet;
@@ -2540,7 +2572,8 @@ static std::string GenerateTargetRequirements(const Record &Attr,
   if (I != CustomTargetSet.end())
     return *I;
 
-  OS << "static bool " << FnName << "(const llvm::Triple &T) {\n";
+  OS << "static bool " << FnName << "(const TargetInfo &Target) {\n";
+  OS << "  const llvm::Triple &T = Target.getTriple();\n";
   OS << "  llvm::Triple::ArchType Arch = T.getArch();\n";
   if (UsesOS)
     OS << "  llvm::Triple::OSType OS = T.getOS();\n";