pcc updated this revision to Diff 52732.
pcc added a comment.
- Update command line flag docs
http://reviews.llvm.org/D18635
Files:
docs/ControlFlowIntegrity.rst
docs/LTOVisibility.rst
docs/UsersManual.rst
docs/index.rst
include/clang/Basic/Attr.td
include/clang/Basic/AttrDocs.td
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Driver/Options.td
include/clang/Frontend/CodeGenOptions.def
include/clang/Frontend/CodeGenOptions.h
include/clang/Sema/AttributeList.h
include/clang/Sema/Sema.h
lib/CodeGen/CGClass.cpp
lib/CodeGen/CGVTables.cpp
lib/CodeGen/CodeGenModule.cpp
lib/CodeGen/CodeGenModule.h
lib/CodeGen/MicrosoftCXXABI.cpp
lib/Driver/SanitizerArgs.cpp
lib/Driver/Tools.cpp
lib/Frontend/CompilerInvocation.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclAttr.cpp
lib/Sema/SemaDeclCXX.cpp
runtime/CMakeLists.txt
runtime/vtables_blacklist.txt
test/CodeGenCXX/bitset-blacklist.cpp
test/CodeGenCXX/bitset-inference.cpp
test/CodeGenCXX/bitsets.cpp
test/CodeGenCXX/cfi-blacklist.cpp
test/CodeGenCXX/cfi-cast.cpp
test/CodeGenCXX/cfi-nvcall.cpp
test/CodeGenCXX/cfi-stats.cpp
test/Driver/default-class-scope.c
test/Driver/fsanitize.c
test/Driver/whole-program-vtables.c
test/Frontend/default-class-scope.c
test/SemaCXX/attr-linkage-unit-scope.cpp
utils/TableGen/ClangAttrEmitter.cpp
Index: utils/TableGen/ClangAttrEmitter.cpp
===================================================================
--- utils/TableGen/ClangAttrEmitter.cpp
+++ utils/TableGen/ClangAttrEmitter.cpp
@@ -2527,6 +2527,7 @@
case ObjCProtocol | ObjCInterface:
return "ExpectedObjectiveCInterfaceOrProtocol";
case Field | Var: return "ExpectedFieldOrGlobalVar";
+ case GenericRecord | Namespace: return "ExpectedRecordOrNamespace";
}
PrintFatalError(S.getLoc(),
Index: test/SemaCXX/attr-linkage-unit-scope.cpp
===================================================================
--- /dev/null
+++ test/SemaCXX/attr-linkage-unit-scope.cpp
@@ -0,0 +1,51 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -DATTR=linkage_unit_scope %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -DATTR=global_scope %s
+
+int i [[clang::ATTR]]; // expected-warning {{attribute only applies to struct, union, class or namespace}}
+typedef int t [[clang::ATTR]]; // expected-warning {{attribute only applies to struct, union, class or namespace}}
+[[clang::ATTR]] void f(); // expected-warning {{attribute only applies to struct, union, class or namespace}}
+void f() [[clang::ATTR]]; // expected-error {{attribute cannot be applied to types}}
+
+struct [[clang::ATTR]] s1 {
+ int i [[clang::ATTR]]; // expected-warning {{attribute only applies to struct, union, class or namespace}}
+ [[clang::ATTR]] void f(); // expected-warning {{attribute only applies to struct, union, class or namespace}}
+};
+
+struct [[clang::ATTR(1)]] s2 { // expected-error {{attribute takes no arguments}}
+ virtual void f();
+};
+
+struct
+[[clang::linkage_unit_scope]] // expected-error{{'linkage_unit_scope' and 'global_scope' attributes are not compatible}}
+[[clang::global_scope]] // expected-note{{conflicting attribute is here}}
+s3 {};
+
+struct
+[[clang::global_scope]] // expected-error{{'global_scope' and 'linkage_unit_scope' attributes are not compatible}}
+[[clang::linkage_unit_scope]] // expected-note{{conflicting attribute is here}}
+s4 {};
+
+struct [[clang::ATTR]] s5;
+struct s5 {};
+
+struct s6;
+struct [[clang::ATTR]] s6 {};
+
+struct [[clang::ATTR]] s7;
+struct s7;
+struct s7 {};
+
+struct [[clang::ATTR]] s8;
+struct s8;
+struct [[clang::ATTR]] s8 {};
+
+struct s9;
+struct [[clang::ATTR]] s9;
+
+struct [[clang::linkage_unit_scope]] s10; //expected-error{{attributes are not compatible}}
+struct [[clang::global_scope]] s10 {}; // expected-note{{conflicting attribute is here}}
+
+namespace [[clang::ATTR]] ns1 {}
+
+namespace [[clang::linkage_unit_scope]] ns2 {} // expected-error{{attributes are not compatible}}
+namespace [[clang::global_scope]] ns2 {} // expected-note{{conflicting attribute is here}}
Index: test/Frontend/default-class-scope.c
===================================================================
--- /dev/null
+++ test/Frontend/default-class-scope.c
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -fdefault-class-scope=global %s
+// RUN: %clang_cc1 -fdefault-class-scope=attrs %s
+// RUN: %clang_cc1 -fdefault-class-scope=linkage-unit %s
+
+// RUN: not %clang_cc1 -fdefault-class-scope=foo %s 2>&1 | FileCheck %s
+// CHECK: error: invalid value 'foo' in '-fdefault-class-scope=foo'
Index: test/Driver/whole-program-vtables.c
===================================================================
--- test/Driver/whole-program-vtables.c
+++ test/Driver/whole-program-vtables.c
@@ -1,11 +1,2 @@
// RUN: %clang -target x86_64-unknown-linux -fwhole-program-vtables -### %s 2>&1 | FileCheck --check-prefix=NO-LTO %s
// NO-LTO: invalid argument '-fwhole-program-vtables' only allowed with '-flto'
-
-// RUN: %clang -target x86_64-unknown-linux -resource-dir=%S/Inputs/resource_dir -flto -fwhole-program-vtables -### -c %s 2>&1 | FileCheck --check-prefix=BLACKLIST %s
-// BLACKLIST: "-fwhole-program-vtables-blacklist={{.*}}vtables_blacklist.txt"
-
-// RUN: %clang -target x86_64-unknown-linux -fwhole-program-vtables-blacklist=nonexistent.txt -flto -fwhole-program-vtables -### -c %s 2>&1 | FileCheck --check-prefix=NON-EXISTENT-BLACKLIST %s
-// NON-EXISTENT-BLACKLIST: no such file or directory: 'nonexistent.txt'
-
-// RUN: %clang -target x86_64-unknown-linux -fwhole-program-vtables-blacklist=%S/Inputs/resource_dir/vtables_blacklist.txt -flto -fwhole-program-vtables -### -c %s 2>&1 | FileCheck --check-prefix=CUSTOM-BLACKLIST %s
-// CUSTOM-BLACKLIST: "-fwhole-program-vtables-blacklist={{.*}}Inputs/resource_dir/vtables_blacklist.txt"
Index: test/Driver/fsanitize.c
===================================================================
--- test/Driver/fsanitize.c
+++ test/Driver/fsanitize.c
@@ -274,6 +274,10 @@
// RUN: %clang -target mips-unknown-linux -fsanitize=cfi-icall %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-ICALL-MIPS
// CHECK-CFI-ICALL-MIPS: unsupported option '-fsanitize=cfi-icall' for target 'mips-unknown-linux'
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi -flto -c %s -fdefault-class-scope=attrs -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-CLASS-SCOPE
+// CHECK-CFI-CLASS-SCOPE: -fdefault-class-scope=linkage-unit
+// CHECK-CFI-CLASS-SCOPE: -fdefault-class-scope=attrs
+
// RUN: %clang -target x86_64-linux-gnu -fsanitize-trap=address -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-TRAP
// CHECK-ASAN-TRAP: error: unsupported argument 'address' to option '-fsanitize-trap'
Index: test/Driver/default-class-scope.c
===================================================================
--- /dev/null
+++ test/Driver/default-class-scope.c
@@ -0,0 +1,2 @@
+// RUN: %clang -target x86_64-unknown-linux -fdefault-class-scope=attrs -### %s 2>&1 | FileCheck --check-prefix=ATTRS %s
+// ATTRS: "-fdefault-class-scope=attrs"
Index: test/CodeGenCXX/cfi-stats.cpp
===================================================================
--- test/CodeGenCXX/cfi-stats.cpp
+++ test/CodeGenCXX/cfi-stats.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-vcall,cfi-nvcall,cfi-derived-cast,cfi-unrelated-cast,cfi-icall -fsanitize-stats -emit-llvm -o - %s | FileCheck --check-prefix=CHECK %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux -fvisibility hidden -fsanitize=cfi-vcall,cfi-nvcall,cfi-derived-cast,cfi-unrelated-cast,cfi-icall -fsanitize-stats -emit-llvm -o - %s | FileCheck --check-prefix=CHECK %s
// CHECK: [[STATS:@[^ ]*]] = internal global { i8*, i32, [5 x [2 x i8*]] } { i8* null, i32 5, [5 x [2 x i8*]]
// CHECK: {{\[\[}}2 x i8*] zeroinitializer,
Index: test/CodeGenCXX/cfi-nvcall.cpp
===================================================================
--- test/CodeGenCXX/cfi-nvcall.cpp
+++ test/CodeGenCXX/cfi-nvcall.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-nvcall -emit-llvm -o - %s | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-nvcall,cfi-cast-strict -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-STRICT %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux -fdefault-class-scope=linkage-unit -fsanitize=cfi-nvcall -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux -fdefault-class-scope=linkage-unit -fsanitize=cfi-nvcall,cfi-cast-strict -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-STRICT %s
struct A {
virtual void f();
Index: test/CodeGenCXX/cfi-cast.cpp
===================================================================
--- test/CodeGenCXX/cfi-cast.cpp
+++ test/CodeGenCXX/cfi-cast.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-linux -std=c++11 -fsanitize=cfi-derived-cast -fsanitize-trap=cfi-derived-cast -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-DCAST %s
-// RUN: %clang_cc1 -triple x86_64-unknown-linux -std=c++11 -fsanitize=cfi-unrelated-cast -fsanitize-trap=cfi-unrelated-cast -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-UCAST %s
-// RUN: %clang_cc1 -triple x86_64-unknown-linux -std=c++11 -fsanitize=cfi-unrelated-cast,cfi-cast-strict -fsanitize-trap=cfi-unrelated-cast,cfi-cast-strict -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-UCAST-STRICT %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux -fdefault-class-scope=linkage-unit -std=c++11 -fsanitize=cfi-derived-cast -fsanitize-trap=cfi-derived-cast -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-DCAST %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux -fdefault-class-scope=linkage-unit -std=c++11 -fsanitize=cfi-unrelated-cast -fsanitize-trap=cfi-unrelated-cast -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-UCAST %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux -fdefault-class-scope=linkage-unit -std=c++11 -fsanitize=cfi-unrelated-cast,cfi-cast-strict -fsanitize-trap=cfi-unrelated-cast,cfi-cast-strict -emit-llvm -o - %s | FileCheck -check-prefix=CHECK-UCAST-STRICT %s
// In this test the main thing we are searching for is something like
// 'metadata !"1B"' where "1B" is the mangled name of the class we are
Index: test/CodeGenCXX/cfi-blacklist.cpp
===================================================================
--- /dev/null
+++ test/CodeGenCXX/cfi-blacklist.cpp
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -fvisibility hidden -fms-extensions -fsanitize=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=NOBL %s
+// RUN: echo "type:std::*" > %t.txt
+// RUN: %clang_cc1 -fvisibility hidden -fms-extensions -fsanitize=cfi-vcall -fsanitize-blacklist=%t.txt -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=NOSTD %s
+
+struct S1 {
+ virtual void f();
+};
+
+namespace std {
+
+struct S2 {
+ virtual void f();
+};
+
+}
+
+// CHECK: define{{.*}}s1f
+// NOBL: llvm.bitset.test
+// NOSTD: llvm.bitset.test
+void s1f(S1 *s1) {
+ s1->f();
+}
+
+// CHECK: define{{.*}}s2f
+// NOBL: llvm.bitset.test
+// NOSTD-NOT: llvm.bitset.test
+void s2f(std::S2 *s2) {
+ s2->f();
+}
Index: test/CodeGenCXX/bitsets.cpp
===================================================================
--- test/CodeGenCXX/bitsets.cpp
+++ test/CodeGenCXX/bitsets.cpp
@@ -1,12 +1,12 @@
// Tests for the cfi-vcall feature:
-// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-vcall -fsanitize-trap=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=ITANIUM --check-prefix=ITANIUM-NDIAG --check-prefix=NDIAG %s
-// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=ITANIUM --check-prefix=ITANIUM-DIAG --check-prefix=DIAG --check-prefix=DIAG-ABORT %s
-// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-vcall -fsanitize-recover=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=ITANIUM --check-prefix=DIAG --check-prefix=DIAG-RECOVER %s
-// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fsanitize=cfi-vcall -fsanitize-trap=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=MS --check-prefix=NDIAG %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux -fdefault-class-scope=linkage-unit -fsanitize=cfi-vcall -fsanitize-trap=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=ITANIUM --check-prefix=ITANIUM-NDIAG --check-prefix=NDIAG %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux -fdefault-class-scope=linkage-unit -fsanitize=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=ITANIUM --check-prefix=ITANIUM-DIAG --check-prefix=DIAG --check-prefix=DIAG-ABORT %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux -fdefault-class-scope=linkage-unit -fsanitize=cfi-vcall -fsanitize-recover=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=ITANIUM --check-prefix=DIAG --check-prefix=DIAG-RECOVER %s
+// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fdefault-class-scope=linkage-unit -fsanitize=cfi-vcall -fsanitize-trap=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CFI --check-prefix=MS --check-prefix=NDIAG %s
// Tests for the whole-program-vtables feature:
-// RUN: %clang_cc1 -triple x86_64-unknown-linux -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=VTABLE-OPT --check-prefix=ITANIUM %s
-// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=VTABLE-OPT --check-prefix=MS %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux -fdefault-class-scope=linkage-unit -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=VTABLE-OPT --check-prefix=ITANIUM %s
+// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fdefault-class-scope=linkage-unit -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=VTABLE-OPT --check-prefix=MS %s
// MS: @[[VTA:[0-9]*]] {{.*}} comdat($"\01??_7A@@6B@")
// MS: @[[VTB:[0-9]*]] {{.*}} comdat($"\01??_7B@@6B0@@")
Index: test/CodeGenCXX/bitset-inference.cpp
===================================================================
--- /dev/null
+++ test/CodeGenCXX/bitset-inference.cpp
@@ -0,0 +1,98 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux -std=c++11 -fms-extensions -fvisibility hidden -fwhole-program-vtables -fdefault-class-scope=attrs -emit-llvm -o - %s | FileCheck --check-prefix=ITANIUM %s
+// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -std=c++11 -fms-extensions -fwhole-program-vtables -fdefault-class-scope=attrs -emit-llvm -o - %s | FileCheck --check-prefix=MS %s
+// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fdefault-class-scope=global -std=c++11 -fms-extensions -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=MS-INFER-GLOBAL %s
+// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -fdefault-class-scope=linkage-unit -std=c++11 -fms-extensions -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=MS-INFER-LU %s
+
+struct C1 {
+ virtual void f();
+};
+
+struct __attribute__((visibility("default"))) C2 {
+ virtual void f();
+};
+
+struct __declspec(dllexport) C3 {
+ virtual void f();
+};
+
+struct __declspec(dllimport) C4 {
+ virtual void f();
+};
+
+struct __attribute__((visibility("default"))) [[clang::linkage_unit_scope]] C5 {
+ virtual void f();
+};
+
+struct [[clang::global_scope]] C6 {
+ virtual void f();
+};
+
+struct __declspec(uuid("00000000-0000-0000-0000-000000000000")) C7 {
+ virtual void f();
+};
+
+namespace [[clang::global_scope]] ns {}
+
+namespace ns {
+
+struct C8 {
+ virtual void f();
+ struct C9 {
+ virtual void f();
+ };
+ struct [[clang::linkage_unit_scope]] C10 {
+ virtual void f();
+ };
+};
+
+struct [[clang::linkage_unit_scope]] C11;
+struct C11 {
+ virtual void f();
+};
+
+}
+
+void f(C1 *c1, C2 *c2, C3 *c3, C4 *c4, C5 *c5, C6 *c6, C7 *c7, ns::C8 *c8,
+ ns::C8::C9 *c9, ns::C8::C10 *c10, ns::C11 *c11) {
+ // ITANIUM: bitset.test{{.*}}!"_ZTS2C1"
+ // MS: bitset.test{{.*}}!"?AUC1@@"
+ // MS-INFER-GLOBAL-NOT: bitset.test{{.*}}!"?AUC1@@"
+ // MS-INFER-LU: bitset.test{{.*}}!"?AUC1@@"
+ c1->f();
+ // ITANIUM-NOT: bitset.test{{.*}}!"_ZTS2C2"
+ // MS: bitset.test{{.*}}!"?AUC2@@"
+ c2->f();
+ // ITANIUM: bitset.test{{.*}}!"_ZTS2C3"
+ // MS-NOT: bitset.test{{.*}}!"?AUC3@@"
+ // MS-INFER-LU: bitset.test{{.*}}!"?AUC3@@"
+ c3->f();
+ // ITANIUM: bitset.test{{.*}}!"_ZTS2C4"
+ // MS-NOT: bitset.test{{.*}}!"?AUC4@@"
+ c4->f();
+ // ITANIUM: bitset.test{{.*}}!"_ZTS2C5"
+ // MS: bitset.test{{.*}}!"?AUC5@@"
+ // MS-INFER-GLOBAL: bitset.test{{.*}}!"?AUC5@@"
+ // MS-INFER-LU: bitset.test{{.*}}!"?AUC5@@"
+ c5->f();
+ // ITANIUM-NOT: bitset.test{{.*}}!"_ZTS2C6"
+ // MS-NOT: bitset.test{{.*}}!"?AUC6@@"
+ // MS-INFER-GLOBAL-NOT: bitset.test{{.*}}!"?AUC6@@"
+ c6->f();
+ // ITANIUM-NOT: bitset.test{{.*}}!"_ZTS2C7"
+ // MS-NOT: bitset.test{{.*}}!"?AUC7@@"
+ // MS-INFER-LU-NOT: bitset.test{{.*}}!"?AUC7@@"
+ c7->f();
+ // ITANIUM-NOT: bitset.test{{.*}}!"_ZTSN2ns2C8E"
+ // MS-NOT: bitset.test{{.*}}!"?AUC8@ns@@"
+ // MS-INFER-LU-NOT: bitset.test{{.*}}!"?AUC8@ns@@"
+ c8->f();
+ // ITANIUM-NOT: bitset.test{{.*}}!"_ZTSN2ns2C82C9E"
+ // MS-NOT: bitset.test{{.*}}!"?AUC9@C8@ns@@"
+ c9->f();
+ // ITANIUM: bitset.test{{.*}}!"_ZTSN2ns2C83C10E"
+ // MS: bitset.test{{.*}}!"?AUC10@C8@ns@@"
+ c10->f();
+ // ITANIUM: bitset.test{{.*}}!"_ZTSN2ns3C11E"
+ // MS: bitset.test{{.*}}!"?AUC11@ns@@"
+ c11->f();
+}
Index: test/CodeGenCXX/bitset-blacklist.cpp
===================================================================
--- test/CodeGenCXX/bitset-blacklist.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-// RUN: echo "type:attr:uuid" > %t.txt
-// RUN: %clang_cc1 -fms-extensions -fsanitize=cfi-vcall -fsanitize-blacklist=%t.txt -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=NOUUID %s
-// RUN: %clang_cc1 -fms-extensions -fwhole-program-vtables -fwhole-program-vtables-blacklist=%t.txt -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=NOUUID %s
-// RUN: echo "type:std::*" > %t.txt
-// RUN: %clang_cc1 -fms-extensions -fsanitize=cfi-vcall -fsanitize-blacklist=%t.txt -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=NOSTD %s
-// RUN: %clang_cc1 -fms-extensions -fwhole-program-vtables -fwhole-program-vtables-blacklist=%t.txt -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=NOSTD %s
-
-struct __declspec(uuid("00000000-0000-0000-0000-000000000000")) S1 {
- virtual void f();
-};
-
-namespace std {
-
-struct S2 {
- virtual void f();
-};
-
-}
-
-// CHECK: define{{.*}}s1f
-// NOSTD: llvm.bitset.test
-// NOUUID-NOT: llvm.bitset.test
-void s1f(S1 *s1) {
- s1->f();
-}
-
-// CHECK: define{{.*}}s2f
-// NOSTD-NOT: llvm.bitset.test
-// NOUUID: llvm.bitset.test
-void s2f(std::S2 *s2) {
- s2->f();
-}
Index: runtime/vtables_blacklist.txt
===================================================================
--- runtime/vtables_blacklist.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-# Standard library types.
-type:std::*
-
-# The stdext namespace contains Microsoft standard library extensions.
-type:stdext::*
-
-# Types with a uuid attribute, i.e. COM types.
-type:attr:uuid
Index: runtime/CMakeLists.txt
===================================================================
--- runtime/CMakeLists.txt
+++ runtime/CMakeLists.txt
@@ -148,15 +148,3 @@
VERBATIM)
endif()
endif()
-
-set(src "${CMAKE_CURRENT_SOURCE_DIR}/vtables_blacklist.txt")
-set(dst "${LLVM_LIBRARY_OUTPUT_INTDIR}/clang/${CLANG_VERSION}/vtables_blacklist.txt")
-add_custom_command(OUTPUT ${dst}
- DEPENDS ${src}
- COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src} ${dst}
- COMMENT "Copying vtables blacklist")
-add_custom_target(vtables_blacklist DEPENDS ${dst})
-if(TARGET clang)
- add_dependencies(clang vtables_blacklist)
-endif()
-install(FILES ${src} DESTINATION lib${LLVM_LIBDIR_SUFFIX}/clang/${CLANG_VERSION})
Index: lib/Sema/SemaDeclCXX.cpp
===================================================================
--- lib/Sema/SemaDeclCXX.cpp
+++ lib/Sema/SemaDeclCXX.cpp
@@ -7253,7 +7253,9 @@
ProcessDeclAttributeList(DeclRegionScope, Namespc, AttrList);
- // FIXME: Should we be merging attributes?
+ if (PrevNS)
+ mergeDeclAttributes(Namespc, PrevNS);
+
if (const VisibilityAttr *Attr = Namespc->getAttr<VisibilityAttr>())
PushNamespaceVisibilityAttr(Attr, Loc);
Index: lib/Sema/SemaDeclAttr.cpp
===================================================================
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -246,9 +246,9 @@
/// \brief Diagnose mutually exclusive attributes when present on a given
/// declaration. Returns true if diagnosed.
-template <typename AttrTy>
+template <typename AttrTy, typename NameTy>
static bool checkAttrMutualExclusion(Sema &S, Decl *D, SourceRange Range,
- IdentifierInfo *Ident) {
+ NameTy Ident) {
if (AttrTy *A = D->getAttr<AttrTy>()) {
S.Diag(Range.getBegin(), diag::err_attributes_are_not_compatible) << Ident
<< A;
@@ -5223,6 +5223,30 @@
<< Attr.getName() << "2.0";
}
+InheritableAttr *Sema::mergeClassScopeAttr(Decl *D, SourceRange Range,
+ int SpellingIndex,
+ bool IsLinkageUnitScope) {
+ if (IsLinkageUnitScope) {
+ if (checkAttrMutualExclusion<GlobalScopeAttr>(
+ *this, D, Range, "'linkage_unit_scope'"))
+ return nullptr;
+ return ::new (Context) LinkageUnitScopeAttr(Range, Context, SpellingIndex);
+ } else {
+ if (checkAttrMutualExclusion<LinkageUnitScopeAttr>(
+ *this, D, Range, "'global_scope'"))
+ return nullptr;
+ return ::new (Context)
+ GlobalScopeAttr(Range, Context, SpellingIndex);
+ }
+}
+
+static void handleClassScopeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (InheritableAttr *A = S.mergeClassScopeAttr(
+ D, Attr.getRange(), Attr.getAttributeSpellingListIndex(),
+ Attr.getKind() == AttributeList::AT_LinkageUnitScope))
+ D->addAttr(A);
+}
+
/// Handles semantic checking for features that are common to all attributes,
/// such as checking whether a parameter was properly specified, or the correct
/// number of arguments were passed, etc.
@@ -5724,6 +5748,10 @@
case AttributeList::AT_InternalLinkage:
handleInternalLinkageAttr(S, D, Attr);
break;
+ case AttributeList::AT_LinkageUnitScope:
+ case AttributeList::AT_GlobalScope:
+ handleClassScopeAttr(S, D, Attr);
+ break;
// Microsoft attributes:
case AttributeList::AT_MSNoVTable:
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -2192,7 +2192,12 @@
Sema::AvailabilityMergeKind AMK) {
InheritableAttr *NewAttr = nullptr;
unsigned AttrSpellingListIndex = Attr->getSpellingListIndex();
- if (const auto *AA = dyn_cast<AvailabilityAttr>(Attr))
+ if (isa<LinkageUnitScopeAttr>(Attr) || isa<GlobalScopeAttr>(Attr))
+ NewAttr = S.mergeClassScopeAttr(D, Attr->getRange(), AttrSpellingListIndex,
+ isa<LinkageUnitScopeAttr>(Attr));
+ else if (isa<NamespaceDecl>(D))
+ return false;
+ else if (const auto *AA = dyn_cast<AvailabilityAttr>(Attr))
NewAttr = S.mergeAvailabilityAttr(D, AA->getRange(), AA->getPlatform(),
AA->getIntroduced(), AA->getDeprecated(),
AA->getObsoleted(), AA->getUnavailable(),
Index: lib/Frontend/CompilerInvocation.cpp
===================================================================
--- lib/Frontend/CompilerInvocation.cpp
+++ lib/Frontend/CompilerInvocation.cpp
@@ -482,8 +482,21 @@
Opts.DebugColumnInfo = Args.hasArg(OPT_dwarf_column_info);
Opts.EmitCodeView = Args.hasArg(OPT_gcodeview);
Opts.WholeProgramVTables = Args.hasArg(OPT_fwhole_program_vtables);
- Opts.WholeProgramVTablesBlacklistFiles =
- Args.getAllArgValues(OPT_fwhole_program_vtables_blacklist_EQ);
+ if (Arg *A = Args.getLastArg(OPT_fdefault_class_scope_EQ)) {
+ unsigned Val =
+ llvm::StringSwitch<unsigned>(A->getValue())
+ .Case("global", unsigned(CodeGenOptions::ClassScopeGlobal))
+ .Case("attrs", unsigned(CodeGenOptions::ClassScopeAttrs))
+ .Case("linkage-unit",
+ unsigned(CodeGenOptions::ClassScopeLinkageUnit))
+ .Default(~0U);
+ if (Val == ~0U)
+ Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args)
+ << A->getValue();
+ else
+ Opts.setDefaultClassScope(
+ static_cast<CodeGenOptions::ClassScopeKind>(Val));
+ }
Opts.SplitDwarfFile = Args.getLastArgValue(OPT_split_dwarf_file);
Opts.DebugTypeExtRefs = Args.hasArg(OPT_dwarf_ext_refs);
Opts.DebugExplicitImport = Triple.isPS4CPU();
Index: lib/Driver/Tools.cpp
===================================================================
--- lib/Driver/Tools.cpp
+++ lib/Driver/Tools.cpp
@@ -4391,32 +4391,6 @@
CmdArgs.push_back("-ffunction-sections");
}
- if (Args.hasFlag(options::OPT_fwhole_program_vtables,
- options::OPT_fno_whole_program_vtables, false)) {
- if (!D.isUsingLTO())
- D.Diag(diag::err_drv_argument_only_allowed_with)
- << "-fwhole-program-vtables"
- << "-flto";
- CmdArgs.push_back("-fwhole-program-vtables");
-
- clang::SmallString<64> Path(D.ResourceDir);
- llvm::sys::path::append(Path, "vtables_blacklist.txt");
- if (llvm::sys::fs::exists(Path)) {
- SmallString<64> BlacklistOpt("-fwhole-program-vtables-blacklist=");
- BlacklistOpt += Path.str();
- CmdArgs.push_back(Args.MakeArgString(BlacklistOpt));
- }
-
- for (const Arg *A :
- Args.filtered(options::OPT_fwhole_program_vtables_blacklist_EQ)) {
- A->claim();
- if (!llvm::sys::fs::exists(A->getValue()))
- D.Diag(clang::diag::err_drv_no_such_file) << A->getValue();
- }
-
- Args.AddAllArgs(CmdArgs, options::OPT_fwhole_program_vtables_blacklist_EQ);
- }
-
if (Args.hasFlag(options::OPT_fdata_sections, options::OPT_fno_data_sections,
UseSeparateSections)) {
CmdArgs.push_back("-fdata-sections");
@@ -5752,6 +5726,18 @@
CmdArgs.push_back(I->getFilename());
}
+ bool WholeProgramVTables =
+ Args.hasFlag(options::OPT_fwhole_program_vtables,
+ options::OPT_fno_whole_program_vtables, false);
+ if (WholeProgramVTables) {
+ if (!D.isUsingLTO())
+ D.Diag(diag::err_drv_argument_only_allowed_with)
+ << "-fwhole-program-vtables"
+ << "-flto";
+ CmdArgs.push_back("-fwhole-program-vtables");
+ }
+ Args.AddLastArg(CmdArgs, options::OPT_fdefault_class_scope_EQ);
+
// Finally add the compile command to the compilation.
if (Args.hasArg(options::OPT__SLASH_fallback) &&
Output.getType() == types::TY_Object &&
Index: lib/Driver/SanitizerArgs.cpp
===================================================================
--- lib/Driver/SanitizerArgs.cpp
+++ lib/Driver/SanitizerArgs.cpp
@@ -39,6 +39,7 @@
TrappingSupported =
(Undefined & ~Vptr) | UnsignedIntegerOverflow | LocalBounds | CFI,
TrappingDefault = CFI,
+ CFIClasses = CFIVCall | CFINVCall | CFIDerivedCast | CFIUnrelatedCast,
};
enum CoverageFeature {
@@ -674,6 +675,9 @@
TC.getCompilerRT(Args, "stats")));
addIncludeLinkerOption(TC, Args, CmdArgs, "__sanitizer_stats_register");
}
+
+ if (Sanitizers.hasOneOf(CFIClasses))
+ CmdArgs.push_back(Args.MakeArgString("-fdefault-class-scope=linkage-unit"));
}
SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A,
Index: lib/CodeGen/MicrosoftCXXABI.cpp
===================================================================
--- lib/CodeGen/MicrosoftCXXABI.cpp
+++ lib/CodeGen/MicrosoftCXXABI.cpp
@@ -1519,15 +1519,13 @@
: CharUnits::Zero();
if (Info->PathToBaseWithVPtr.empty()) {
- if (!CGM.IsBitSetBlacklistedRecord(RD))
- CGM.CreateVTableBitSetEntry(BitsetsMD, VTable, AddressPoint, RD);
+ CGM.CreateVTableBitSetEntry(BitsetsMD, VTable, AddressPoint, RD);
return;
}
// Add a bitset entry for the least derived base belonging to this vftable.
- if (!CGM.IsBitSetBlacklistedRecord(Info->PathToBaseWithVPtr.back()))
- CGM.CreateVTableBitSetEntry(BitsetsMD, VTable, AddressPoint,
- Info->PathToBaseWithVPtr.back());
+ CGM.CreateVTableBitSetEntry(BitsetsMD, VTable, AddressPoint,
+ Info->PathToBaseWithVPtr.back());
// Add a bitset entry for each derived class that is laid out at the same
// offset as the least derived base.
@@ -1545,12 +1543,11 @@
Offset = VBI->second.VBaseOffset;
if (!Offset.isZero())
return;
- if (!CGM.IsBitSetBlacklistedRecord(DerivedRD))
- CGM.CreateVTableBitSetEntry(BitsetsMD, VTable, AddressPoint, DerivedRD);
+ CGM.CreateVTableBitSetEntry(BitsetsMD, VTable, AddressPoint, DerivedRD);
}
// Finally do the same for the most derived class.
- if (Info->FullOffsetInMDC.isZero() && !CGM.IsBitSetBlacklistedRecord(RD))
+ if (Info->FullOffsetInMDC.isZero())
CGM.CreateVTableBitSetEntry(BitsetsMD, VTable, AddressPoint, RD);
}
Index: lib/CodeGen/CodeGenModule.h
===================================================================
--- lib/CodeGen/CodeGenModule.h
+++ lib/CodeGen/CodeGenModule.h
@@ -490,8 +490,6 @@
/// MDNodes.
llvm::DenseMap<QualType, llvm::Metadata *> MetadataIdMap;
- SanitizerBlacklist WholeProgramVTablesBlacklist;
-
public:
CodeGenModule(ASTContext &C, const HeaderSearchOptions &headersearchopts,
const PreprocessorOptions &ppopts,
@@ -1118,9 +1116,9 @@
/// Returns whether we need bit sets attached to vtables.
bool NeedVTableBitSets();
- /// Returns whether the given record is blacklisted from whole-program
- /// transformations (i.e. CFI or whole-program vtable optimization).
- bool IsBitSetBlacklistedRecord(const CXXRecordDecl *RD);
+ /// Returns whether the given record has linkage-unit scope and therefore may
+ /// participate in (single-module) CFI and whole-program vtable optimization.
+ bool HasLinkageUnitScope(const CXXRecordDecl *RD);
/// Emit bit set entries for the given vtable using the given layout if
/// vptr CFI is enabled.
Index: lib/CodeGen/CodeGenModule.cpp
===================================================================
--- lib/CodeGen/CodeGenModule.cpp
+++ lib/CodeGen/CodeGenModule.cpp
@@ -97,9 +97,7 @@
NSConcreteStackBlock(nullptr), BlockObjectAssign(nullptr),
BlockObjectDispose(nullptr), BlockDescriptorType(nullptr),
GenericBlockLiteralType(nullptr), LifetimeStartFn(nullptr),
- LifetimeEndFn(nullptr), SanitizerMD(new SanitizerMetadata(*this)),
- WholeProgramVTablesBlacklist(CGO.WholeProgramVTablesBlacklistFiles,
- C.getSourceManager()) {
+ LifetimeEndFn(nullptr), SanitizerMD(new SanitizerMetadata(*this)) {
// Initialize the type cache.
llvm::LLVMContext &LLVMContext = M.getContext();
Index: lib/CodeGen/CGVTables.cpp
===================================================================
--- lib/CodeGen/CGVTables.cpp
+++ lib/CodeGen/CGVTables.cpp
@@ -910,21 +910,36 @@
getLangOpts().Sanitize.has(SanitizerKind::CFIUnrelatedCast);
}
-bool CodeGenModule::IsBitSetBlacklistedRecord(const CXXRecordDecl *RD) {
- std::string TypeName = RD->getQualifiedNameAsString();
- auto isInBlacklist = [&](const SanitizerBlacklist &BL) {
- if (RD->hasAttr<UuidAttr>() && BL.isBlacklistedType("attr:uuid"))
- return true;
+bool CodeGenModule::HasLinkageUnitScope(const CXXRecordDecl *RD) {
+ LinkageInfo LV = RD->getLinkageAndVisibility();
+ if (!isExternallyVisible(LV.getLinkage()))
+ return true;
- return BL.isBlacklistedType(TypeName);
- };
+ // These attributes override our checks below.
+ const DeclContext *DC = RD;
+ while (DC) {
+ const Decl *D = cast<Decl>(DC);
+ if (D->hasAttr<LinkageUnitScopeAttr>()) {
+ return true;
+ } else if (D->hasAttr<GlobalScopeAttr>() || D->hasAttr<UuidAttr>()) {
+ return false;
+ }
+ DC = DC->getParent();
+ }
- return isInBlacklist(WholeProgramVTablesBlacklist) ||
- ((LangOpts.Sanitize.has(SanitizerKind::CFIVCall) ||
- LangOpts.Sanitize.has(SanitizerKind::CFINVCall) ||
- LangOpts.Sanitize.has(SanitizerKind::CFIDerivedCast) ||
- LangOpts.Sanitize.has(SanitizerKind::CFIUnrelatedCast)) &&
- isInBlacklist(getContext().getSanitizerBlacklist()));
+ switch (getCodeGenOpts().getDefaultClassScope()) {
+ case CodeGenOptions::ClassScopeGlobal:
+ return false;
+ case CodeGenOptions::ClassScopeLinkageUnit:
+ return true;
+ case CodeGenOptions::ClassScopeAttrs:
+ // Use object format-specific attributes to see if the record is visible
+ // outside the linkage unit.
+ if (getTriple().isOSBinFormatCOFF())
+ return !RD->hasAttr<DLLExportAttr>() && !RD->hasAttr<DLLImportAttr>();
+ else
+ return LV.getVisibility() == HiddenVisibility;
+ }
}
void CodeGenModule::EmitVTableBitSetEntries(llvm::GlobalVariable *VTable,
@@ -938,12 +953,8 @@
typedef std::pair<const CXXRecordDecl *, unsigned> BSEntry;
std::vector<BSEntry> BitsetEntries;
// Create a bit set entry for each address point.
- for (auto &&AP : VTLayout.getAddressPoints()) {
- if (IsBitSetBlacklistedRecord(AP.first.getBase()))
- continue;
-
+ for (auto &&AP : VTLayout.getAddressPoints())
BitsetEntries.push_back(std::make_pair(AP.first.getBase(), AP.second));
- }
// Sort the bit set entries for determinism.
std::sort(BitsetEntries.begin(), BitsetEntries.end(),
Index: lib/CodeGen/CGClass.cpp
===================================================================
--- lib/CodeGen/CGClass.cpp
+++ lib/CodeGen/CGClass.cpp
@@ -2489,7 +2489,7 @@
llvm::Value *VTable,
SourceLocation Loc) {
if (CGM.getCodeGenOpts().WholeProgramVTables &&
- !CGM.IsBitSetBlacklistedRecord(RD)) {
+ CGM.HasLinkageUnitScope(RD)) {
llvm::Metadata *MD =
CGM.CreateMetadataIdentifierForType(QualType(RD->getTypeForDecl(), 0));
llvm::Value *BitSetName =
@@ -2565,7 +2565,12 @@
llvm::Value *VTable,
CFITypeCheckKind TCK,
SourceLocation Loc) {
- if (CGM.IsBitSetBlacklistedRecord(RD))
+ if (!CGM.getCodeGenOpts().SanitizeCfiCrossDso &&
+ !CGM.HasLinkageUnitScope(RD))
+ return;
+
+ std::string TypeName = RD->getQualifiedNameAsString();
+ if (getContext().getSanitizerBlacklist().isBlacklistedType(TypeName))
return;
SanitizerScope SanScope(this);
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -2145,6 +2145,9 @@
unsigned AttrSpellingListIndex);
CommonAttr *mergeCommonAttr(Decl *D, SourceRange Range, IdentifierInfo *Ident,
unsigned AttrSpellingListIndex);
+ InheritableAttr *mergeClassScopeAttr(Decl *D, SourceRange Range,
+ int SpellingIndex,
+ bool IsLinkageUnitScope);
void mergeDeclAttributes(NamedDecl *New, Decl *Old,
AvailabilityMergeKind AMK = AMK_Redeclaration);
Index: include/clang/Sema/AttributeList.h
===================================================================
--- include/clang/Sema/AttributeList.h
+++ include/clang/Sema/AttributeList.h
@@ -904,7 +904,8 @@
ExpectedVariableEnumFieldOrTypedef,
ExpectedFunctionMethodEnumOrClass,
ExpectedStructClassVariableFunctionOrInlineNamespace,
- ExpectedForMaybeUnused
+ ExpectedForMaybeUnused,
+ ExpectedRecordOrNamespace,
};
} // end namespace clang
Index: include/clang/Frontend/CodeGenOptions.h
===================================================================
--- include/clang/Frontend/CodeGenOptions.h
+++ include/clang/Frontend/CodeGenOptions.h
@@ -86,6 +86,13 @@
ProfileIRInstr, // IR level PGO instrumentation in LLVM.
};
+ enum ClassScopeKind {
+ ClassScopeGlobal, // Infer global scope for all classes.
+ ClassScopeAttrs, // Infer scope from visibility/dllimport/dllexport
+ // attributes.
+ ClassScopeLinkageUnit, // Infer linkage unit scope for all classes.
+ };
+
/// The code model to use (-mcmodel).
std::string CodeModel;
@@ -202,9 +209,6 @@
/// \brief A list of all -fno-builtin-* function names (e.g., memset).
std::vector<std::string> NoBuiltinFuncs;
- /// List of blacklist files for the whole-program vtable optimization feature.
- std::vector<std::string> WholeProgramVTablesBlacklistFiles;
-
public:
// Define accessors/mutators for code generation options of enumeration type.
#define CODEGENOPT(Name, Bits, Default)
Index: include/clang/Frontend/CodeGenOptions.def
===================================================================
--- include/clang/Frontend/CodeGenOptions.def
+++ include/clang/Frontend/CodeGenOptions.def
@@ -184,6 +184,9 @@
CODEGENOPT(WholeProgramVTables, 1, 0) ///< Whether to apply whole-program
/// vtable optimization.
+ENUM_CODEGENOPT(DefaultClassScope, ClassScopeKind, 2,
+ ClassScopeAttrs) ///< How to derive a class's scope for
+ /// vtable opt and CFI.
/// The user specified number of registers to be used for integral arguments,
/// or 0 if unspecified.
Index: include/clang/Driver/Options.td
===================================================================
--- include/clang/Driver/Options.td
+++ include/clang/Driver/Options.td
@@ -1134,9 +1134,9 @@
Flags<[CC1Option]>,
HelpText<"Enables whole-program vtable optimization. Requires -flto">;
def fno_whole_program_vtables : Flag<["-"], "fno-whole-program-vtables">, Group<f_Group>;
-def fwhole_program_vtables_blacklist_EQ : Joined<["-"], "fwhole-program-vtables-blacklist=">,
- Group<f_Group>, Flags<[CC1Option]>,
- HelpText<"Path to a blacklist file for whole-program vtable optimization">;
+def fdefault_class_scope_EQ : Joined<["-"], "fdefault-class-scope=">, Group<f_Group>,
+ Flags<[CC1Option]>,
+ HelpText<"Default class scope for vtable opt and CFI">;
def fwrapv : Flag<["-"], "fwrapv">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Treat signed integer overflow as two's complement">;
def fwritable_strings : Flag<["-"], "fwritable-strings">, Group<f_Group>, Flags<[CC1Option]>,
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -2487,7 +2487,8 @@
"interface or protocol declarations|kernel functions|non-K&R-style functions|"
"variables, enums, fields and typedefs|functions, methods, enums, and classes|"
"structs, classes, variables, functions, and inline namespaces|"
- "variables, functions, methods, types, enumerations, enumerators, labels, and non-static data members}1">,
+ "variables, functions, methods, types, enumerations, enumerators, labels, and non-static data members|"
+ "struct, union, class or namespace}1">,
InGroup<IgnoredAttributes>;
def err_attribute_wrong_decl_type : Error<warn_attribute_wrong_decl_type.Text>;
def warn_type_attribute_wrong_type : Warning<
Index: include/clang/Basic/AttrDocs.td
===================================================================
--- include/clang/Basic/AttrDocs.td
+++ include/clang/Basic/AttrDocs.td
@@ -2341,3 +2341,10 @@
string argument which is the message to display when emitting the warning.
}];
}
+
+def ClassScopeDocs : Documentation {
+ let Category = DocCatType;
+ let Content = [{
+See :ref:`Overriding Class Scope Inferences with Attributes <class-scope-attrs>`.
+ }];
+}
Index: include/clang/Basic/Attr.td
===================================================================
--- include/clang/Basic/Attr.td
+++ include/clang/Basic/Attr.td
@@ -1604,6 +1604,18 @@
let Documentation = [Undocumented];
}
+def LinkageUnitScope : InheritableAttr {
+ let Spellings = [CXX11<"clang", "linkage_unit_scope">];
+ let Subjects = SubjectList<[Record, Namespace]>;
+ let Documentation = [ClassScopeDocs];
+}
+
+def GlobalScope : InheritableAttr {
+ let Spellings = [CXX11<"clang", "global_scope">];
+ let Subjects = SubjectList<[Record, Namespace]>;
+ let Documentation = [ClassScopeDocs];
+}
+
def AnyX86Interrupt : InheritableAttr, TargetSpecificAttr<TargetAnyX86> {
// NOTE: If you add any additional spellings, ARMInterrupt's,
// MSP430Interrupt's and MipsInterrupt's spellings must match.
Index: docs/index.rst
===================================================================
--- docs/index.rst
+++ docs/index.rst
@@ -31,6 +31,7 @@
SanitizerStats
SanitizerSpecialCaseList
ControlFlowIntegrity
+ LTOVisibility
SafeStack
Modules
MSVCCompatibility
Index: docs/UsersManual.rst
===================================================================
--- docs/UsersManual.rst
+++ docs/UsersManual.rst
@@ -1056,17 +1056,8 @@
.. option:: -fwhole-program-vtables
Enable whole-program vtable optimizations, such as single-implementation
- devirtualization and virtual constant propagation. Requires ``-flto``.
-
- By default, the compiler will assume that all type hierarchies are
- closed except those in the ``std`` namespace, the ``stdext`` namespace
- and classes with the ``__declspec(uuid())`` attribute.
-
-.. option:: -fwhole-program-vtables-blacklist=path
-
- Allows the user to specify the path to a list of additional classes to
- blacklist from whole-program vtable optimizations. This list is in the
- :ref:`CFI blacklist <cfi-blacklist>` format.
+ devirtualization and virtual constant propagation, for classes with internal
+ linkage or :doc:`hidden LTO visibility <LTOVisibility>`. Requires ``-flto``.
.. option:: -fno-assume-sane-operator-new
Index: docs/LTOVisibility.rst
===================================================================
--- /dev/null
+++ docs/LTOVisibility.rst
@@ -0,0 +1,43 @@
+==============
+LTO Visibility
+==============
+
+LTO visibility is a concept used by the compiler to determine which classes
+the virtual function call optimization and control flow integrity features
+apply to. These features use whole-program information, so they require
+visibility of entire class hierarchies to work correctly.
+
+It is effectively an ODR violation to declare a class with hidden LTO
+visibility in multiple linkage units, or to declare such a class in an
+translation unit not built with LTO. A class with default LTO visibility
+has no such restrictions, but the tradeoff is that the virtual function
+call optimization and control flow integrity features can only be applied to
+classes with internal linkage (e.g. classes declared in unnamed namespaces)
+or classes with LTO visibility.
+
+LTO visibility is based on symbol visibility or, on the Windows platform,
+the dllimport and dllexport attributes. When targeting non-Windows platforms,
+classes with a visibility other than hidden visibility receive default LTO
+visibility. When targeting Windows, classes with dllimport or dllexport
+attributes receive default LTO visibility. All other classes receive hidden
+LTO visibility.
+
+This mechanism will produce the correct result in most cases, but there are
+two cases where it may wrongly infer hidden LTO visibility.
+
+1. If a linkage unit is produced from a combination of LTO object files and
+ non-LTO object files, any classes defined in translation units from which
+ the non-LTO object files were built will require default LTO visibility.
+
+2. Some ABIs provide the ability to define an abstract base class without
+ visibility attributes in multiple linkage units and have virtual calls
+ to derived classes in other linkage units work correctly. One example of
+ this is COM on Windows platforms.
+
+Classes that fall into either of these categories can be marked up with
+the ``[[clang::lto_visibility_default]]`` attribute. To specifically
+handle the COM case, the ``__declspec(uuid())`` attribute implies
+``[[clang::lto_visibility_default]]``. On Windows platforms, the ``/MT`` and
+``/MTd`` flags link the program against a prebuilt static standard library;
+these flags imply default LTO visibility for every class declared in the
+``std`` and `stdext`` namespaces.
Index: docs/ControlFlowIntegrity.rst
===================================================================
--- docs/ControlFlowIntegrity.rst
+++ docs/ControlFlowIntegrity.rst
@@ -25,13 +25,25 @@
so it is required to specify ``-flto``, and the linker used must support LTO,
for example via the `gold plugin`_.
-To allow the checks to be implemented efficiently, the program must be
-structured such that certain object files are compiled with CFI
+To allow the checks to be implemented efficiently, the program must
+be structured such that certain object files are compiled with CFI
enabled, and are statically linked into the program. This may preclude
-the use of shared libraries in some cases. Experimental support for
-:ref:`cross-DSO control flow integrity <cfi-cross-dso>` exists that
-does not have these requirements. This cross-DSO support has unstable
-ABI at this time.
+the use of shared libraries in some cases.
+
+The compiler will only produce CFI checks for a class if it can infer hidden
+LTO visibility for that class. LTO visibility is a property of a class that
+is inferred from flags and attributes. For more details, see the documentation
+for :doc:`LTO visibility <LTOVisibility>`.
+
+The ``-fsanitize=cfi-{vcall,nvcall,derived-cast,unrelated-cast}`` flags
+require that a ``-fvisibility=`` flag also be specified. This is because the
+default visibility setting is ``-fvisibility=default``, which would disable
+CFI checks for classes without visibility attributes. Most users will want
+to specify ``-fvisibility=hidden``, which enables CFI checks for such classes.
+
+Experimental support for :ref:`cross-DSO control flow integrity
+<cfi-cross-dso>` exists that does not require classes to have hidden LTO
+visibility. This cross-DSO support has unstable ABI at this time.
.. _gold plugin: http://llvm.org/docs/GoldPlugin.html
@@ -233,11 +245,6 @@
source files, functions and types using the ``src``, ``fun`` and ``type``
entity types.
-In addition, if a type has a ``uuid`` attribute and the blacklist contains
-the type entry ``attr:uuid``, CFI checks are suppressed for that type. This
-allows all COM types to be easily blacklisted, which is useful as COM types
-are typically defined outside of the linked program.
-
.. code-block:: bash
# Suppress checking for code in a file.
@@ -247,8 +254,6 @@
fun:*MyFooBar*
# Ignore all types in the standard library.
type:std::*
- # Ignore all types with a uuid attribute.
- type:attr:uuid
.. _cfi-cross-dso:
@@ -260,6 +265,11 @@
apply across DSO boundaries. As in the regular CFI, each DSO must be
built with ``-flto``.
+Normally, the compiler will disable CFI checks for classes that do not
+have hidden LTO visibility. With this flag enabled, the compiler will emit
+cross-DSO CFI checks for all classes, except for those which appear in the
+CFI blacklist or which use a ``no_sanitize`` attribute.
+
Design
======
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits