diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -1229,3 +1229,5 @@ } def WebAssemblyExceptionSpec : DiagGroup<"wasm-exception-spec">; + +def RTTI : DiagGroup<"rtti">; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -7433,6 +7433,12 @@ "use of typeid requires -frtti">; def err_no_dynamic_cast_with_fno_rtti : Error< "use of dynamic_cast requires -frtti">; +def warn_no_dynamic_cast_with_rtti_disabled: Warning< + "dynamic_cast will not work since RTTI data is disabled by " + "%select{-fno-rtti-data|/GR-}0">, InGroup; +def warn_no_typeid_with_rtti_disabled: Warning< + "typeid will not work since RTTI data is disabled by " + "%select{-fno-rtti-data|/GR-}0">, InGroup; def err_cannot_form_pointer_to_member_of_reference_type : Error< "cannot form a pointer-to-member to member %0 of reference type %1">; diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp --- a/clang/lib/Sema/SemaCast.cpp +++ b/clang/lib/Sema/SemaCast.cpp @@ -890,6 +890,16 @@ return; } + // Warns when dynamic_cast is used with RTTI data disabled. + if (!Self.getLangOpts().RTTIData) { + bool isClangCL = Self.getDiagnostics().getDiagnosticOptions().getFormat() == + DiagnosticOptions::MSVC; + if (isClangCL || !DestPointee->isVoidType()) + Self.Diag(OpRange.getBegin(), + diag::warn_no_dynamic_cast_with_rtti_disabled) + << isClangCL; + } + // Done. Everything else is run-time checks. Kind = CK_Dynamic; } diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -646,6 +646,12 @@ return ExprError(Diag(OpLoc, diag::err_no_typeid_with_fno_rtti)); } + // Warns when typeid is used with RTTI data disabled. + if (!getLangOpts().RTTIData) + Diag(OpLoc, diag::warn_no_typeid_with_rtti_disabled) + << (getDiagnostics().getDiagnosticOptions().getFormat() == + DiagnosticOptions::MSVC); + QualType TypeInfoType = Context.getTypeDeclType(CXXTypeInfoDecl); if (isType) { diff --git a/clang/test/SemaCXX/ms_no_dynamic_cast.cpp b/clang/test/SemaCXX/ms_no_dynamic_cast.cpp new file mode 100644 --- /dev/null +++ b/clang/test/SemaCXX/ms_no_dynamic_cast.cpp @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 %s -fdiagnostics-format msvc -fno-rtti-data -fsyntax-only -verify + +namespace std { +struct type_info {}; +} // namespace std +class B { +public: + virtual ~B() = default; +}; + +class D1 : public B { +public: + ~D1() = default; +}; + +void f() { + B *b = new D1(); + auto d = dynamic_cast(b); // expected-warning{{dynamic_cast will not work since RTTI data is disabled by /GR-}} + (void)typeid(int); // expected-warning{{typeid will not work since RTTI data is disabled by /GR-}} +} diff --git a/clang/test/SemaCXX/no_dynamic_cast.cpp b/clang/test/SemaCXX/no_dynamic_cast.cpp new file mode 100644 --- /dev/null +++ b/clang/test/SemaCXX/no_dynamic_cast.cpp @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 %s -fno-rtti-data -fsyntax-only -verify + +namespace std { +struct type_info {}; +} // namespace std +class B { +public: + virtual ~B() = default; +}; + +class D1 : public B { +public: + ~D1() = default; +}; + +void f() { + B *b = new D1(); + auto d = dynamic_cast(b); // expected-warning{{dynamic_cast will not work since RTTI data is disabled by -fno-rtti-data}} + (void)typeid(int); // expected-warning{{typeid will not work since RTTI data is disabled by -fno-rtti-data}} +}