diff --git a/include/swift/AST/DiagnosticEngine.h b/include/swift/AST/DiagnosticEngine.h index 8f04b6f982eaf..ed59eb2ac44c5 100644 --- a/include/swift/AST/DiagnosticEngine.h +++ b/include/swift/AST/DiagnosticEngine.h @@ -616,6 +616,9 @@ namespace swift { /// Don't emit any warnings bool suppressWarnings = false; + + /// Don't emit any notes + bool suppressNotes = false; /// Don't emit any remarks bool suppressRemarks = false; @@ -663,6 +666,10 @@ namespace swift { void setSuppressWarnings(bool val) { suppressWarnings = val; } bool getSuppressWarnings() const { return suppressWarnings; } + /// Whether to skip emitting notes + void setSuppressNotes(bool val) { suppressNotes = val; } + bool getSuppressNotes() const { return suppressNotes; } + /// Whether to skip emitting remarks void setSuppressRemarks(bool val) { suppressRemarks = val; } bool getSuppressRemarks() const { return suppressRemarks; } @@ -708,6 +715,7 @@ namespace swift { void swap(DiagnosticState &other) { std::swap(showDiagnosticsAfterFatalError, other.showDiagnosticsAfterFatalError); std::swap(suppressWarnings, other.suppressWarnings); + std::swap(suppressNotes, other.suppressNotes); std::swap(suppressRemarks, other.suppressRemarks); std::swap(warningsAsErrors, other.warningsAsErrors); std::swap(fatalErrorOccurred, other.fatalErrorOccurred); @@ -904,6 +912,12 @@ namespace swift { return state.getSuppressWarnings(); } + /// Whether to skip emitting notes + void setSuppressNotes(bool val) { state.setSuppressNotes(val); } + bool getSuppressNotes() const { + return state.getSuppressNotes(); + } + /// Whether to skip emitting remarks void setSuppressRemarks(bool val) { state.setSuppressRemarks(val); } bool getSuppressRemarks() const { diff --git a/include/swift/Basic/DiagnosticOptions.h b/include/swift/Basic/DiagnosticOptions.h index 2be70d7e1a43a..e346e6199e61e 100644 --- a/include/swift/Basic/DiagnosticOptions.h +++ b/include/swift/Basic/DiagnosticOptions.h @@ -58,6 +58,9 @@ class DiagnosticOptions { /// Suppress all warnings bool SuppressWarnings = false; + /// Suppress all notes + bool SuppressNotes = false; + /// Suppress all remarks bool SuppressRemarks = false; diff --git a/include/swift/Frontend/ModuleInterfaceLoader.h b/include/swift/Frontend/ModuleInterfaceLoader.h index ad38919e56538..c1cbdb7ed7d85 100644 --- a/include/swift/Frontend/ModuleInterfaceLoader.h +++ b/include/swift/Frontend/ModuleInterfaceLoader.h @@ -643,7 +643,7 @@ struct InterfaceSubContextDelegateImpl : InterfaceSubContextDelegate { const LangOptions &LangOpts, const ClangImporterOptions &clangImporterOpts, const CASOptions &casOpts, - bool suppressRemarks); + bool suppressNotes, bool suppressRemarks); bool extractSwiftInterfaceVersionAndArgs(CompilerInvocation &subInvocation, DiagnosticEngine &subInstanceDiags, SwiftInterfaceInfo &interfaceInfo, diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td index b25c87080876c..10ffc1b2dc6e9 100644 --- a/include/swift/Option/Options.td +++ b/include/swift/Option/Options.td @@ -929,6 +929,10 @@ def Wwarning : Separate<["-"], "Wwarning">, MetaVarName<"">, HelpText<"Treat this warning group as warning">; +def suppress_notes : Flag<["-"], "suppress-notes">, + Flags<[FrontendOption]>, + HelpText<"Suppress all notes">; + def suppress_remarks : Flag<["-"], "suppress-remarks">, Flags<[FrontendOption]>, HelpText<"Suppress all remarks">; diff --git a/lib/AST/DiagnosticEngine.cpp b/lib/AST/DiagnosticEngine.cpp index cf926f713ea80..7d85c2607c3d2 100644 --- a/lib/AST/DiagnosticEngine.cpp +++ b/lib/AST/DiagnosticEngine.cpp @@ -1345,6 +1345,11 @@ DiagnosticState::determineBehavior(const Diagnostic &diag) const { if (suppressWarnings) lvl = DiagnosticBehavior::Ignore; } + + if (lvl == DiagnosticBehavior::Note) { + if (suppressNotes) + lvl = DiagnosticBehavior::Ignore; + } if (lvl == DiagnosticBehavior::Remark) { if (suppressRemarks) diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index 9d0bed0087c8d..33767624bcdbc 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -7300,10 +7300,8 @@ clang::FunctionDecl *ClangImporter::instantiateCXXFunctionTemplate( // Instantiate a specialization of this template using the substitution map. auto *templateArgList = clang::TemplateArgumentList::CreateCopy( func->getASTContext(), templateSubst); - auto &sema = getClangInstance().getSema(); - auto *spec = sema.InstantiateFunctionDeclaration(func, templateArgList, - clang::SourceLocation()); - if (!spec) { + + auto diagnoseSubstFail = [&]() { std::string templateParams; llvm::raw_string_ostream templateParamsStream(templateParams); llvm::interleaveComma(templateArgList->asArray(), templateParamsStream, @@ -7315,9 +7313,24 @@ clang::FunctionDecl *ClangImporter::instantiateCXXFunctionTemplate( Impl.diagnose(HeaderLoc(func->getBeginLoc()), diag::unable_to_substitute_cxx_function_template, getFuncName(), templateParams); + }; + + auto &sema = getClangInstance().getSema(); + auto *spec = sema.InstantiateFunctionDeclaration(func, templateArgList, + clang::SourceLocation()); + if (!spec || spec->isInvalidDecl()) { + diagnoseSubstFail(); return nullptr; } + sema.InstantiateFunctionDefinition(clang::SourceLocation(), spec); + // Even if the declaration can be instantiated, the definition may contain + // a substitution failure that renders spec invalid as a side-effect. + if (spec->isInvalidDecl()) { + diagnoseSubstFail(); + return nullptr; + } + return spec; } @@ -7714,6 +7727,12 @@ ClangImporter::getCXXFunctionTemplateSpecialization(SubstitutionMap subst, assert(isa(decl->getClangDecl()) && "This API should only be used with function templates."); + // If we hit some instantiation failure and expect the compiler to imminently + // terminate (with an error), return some reasonable-looking placeholder value + // in the meantime because callers expect this function to return some + // non-empty ConcreteDeclRef. + auto failurePlaceholder = [&]() { return ConcreteDeclRef(decl); }; + auto *newFn = decl->getASTContext() .getClangModuleLoader() @@ -7722,31 +7741,28 @@ ClangImporter::getCXXFunctionTemplateSpecialization(SubstitutionMap subst, const_cast( cast(decl->getClangDecl())), subst); - // We failed to specialize this function template. The compiler is going to - // exit soon. Return something valid in the meantime. if (!newFn) - return ConcreteDeclRef(decl); + return failurePlaceholder(); auto [fnIt, inserted] = Impl.specializedFunctionTemplates.try_emplace(newFn, nullptr); if (!inserted) return ConcreteDeclRef(fnIt->second); - auto newDecl = cast_or_null( - decl->getASTContext().getClangModuleLoader()->importDeclDirectly( - newFn)); + auto *newDecl = cast_or_null( + decl->getASTContext().getClangModuleLoader()->importDeclDirectly(newFn)); + if (!newDecl) + return failurePlaceholder(); - if (auto fn = dyn_cast(newDecl)) { + if (auto *fn = dyn_cast(newDecl)) { if (!subst.empty()) { newDecl = rewriteIntegerTypes(subst, decl, fn); } } - if (auto fn = dyn_cast(decl)) { + if (auto *fn = dyn_cast(decl)) { newDecl = addThunkForDependentTypes(fn, cast(newDecl)); - } - if (auto fn = dyn_cast(decl)) { if (newFn->getNumParams() != fn->getParameters()->size()) { newDecl = generateThunkForExtraMetatypes(subst, fn, cast(newDecl)); diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index ab67d57abfda6..db8b79bf2f813 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -2652,6 +2652,7 @@ static bool ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, } Opts.SuppressWarnings |= Args.hasArg(OPT_suppress_warnings); + Opts.SuppressNotes |= Args.hasArg(OPT_suppress_notes); Opts.SuppressRemarks |= Args.hasArg(OPT_suppress_remarks); for (const Arg *arg : Args.filtered(OPT_warning_treating_Group)) { Opts.WarningsAsErrorsRules.push_back([&] { @@ -2732,6 +2733,9 @@ static void configureDiagnosticEngine( if (Options.SuppressWarnings) { Diagnostics.setSuppressWarnings(true); } + if (Options.SuppressNotes) { + Diagnostics.setSuppressNotes(true); + } if (Options.SuppressRemarks) { Diagnostics.setSuppressRemarks(true); } diff --git a/lib/Frontend/ModuleInterfaceLoader.cpp b/lib/Frontend/ModuleInterfaceLoader.cpp index 27c3b70862dbb..a6dfdbe394a91 100644 --- a/lib/Frontend/ModuleInterfaceLoader.cpp +++ b/lib/Frontend/ModuleInterfaceLoader.cpp @@ -1663,7 +1663,7 @@ void InterfaceSubContextDelegateImpl::inheritOptionsForBuildingInterface( FrontendOptions::ActionType requestedAction, const SearchPathOptions &SearchPathOpts, const LangOptions &LangOpts, const ClangImporterOptions &clangImporterOpts, const CASOptions &casOpts, - bool suppressRemarks) { + bool suppressNotes, bool suppressRemarks) { GenericArgs.push_back("-frontend"); // Start with a genericSubInvocation that copies various state from our // invoking ASTContext. @@ -1752,6 +1752,12 @@ void InterfaceSubContextDelegateImpl::inheritOptionsForBuildingInterface( genericSubInvocation.getDiagnosticOptions().SuppressWarnings = true; GenericArgs.push_back("-suppress-warnings"); + // Inherit the parent invocation's setting on whether to suppress remarks + if (suppressNotes) { + genericSubInvocation.getDiagnosticOptions().SuppressNotes = true; + GenericArgs.push_back("-suppress-notes"); + } + // Inherit the parent invocation's setting on whether to suppress remarks if (suppressRemarks) { genericSubInvocation.getDiagnosticOptions().SuppressRemarks = true; @@ -1863,6 +1869,7 @@ InterfaceSubContextDelegateImpl::InterfaceSubContextDelegateImpl( genericSubInvocation.setMainExecutablePath(LoaderOpts.mainExecutablePath); inheritOptionsForBuildingInterface(LoaderOpts.requestedAction, searchPathOpts, langOpts, clangImporterOpts, casOpts, + Diags->getSuppressNotes(), Diags->getSuppressRemarks()); // Configure front-end input. auto &SubFEOpts = genericSubInvocation.getFrontendOptions(); diff --git a/test/Interop/Cxx/templates/static-cast-typecheck.swift b/test/Interop/Cxx/templates/static-cast-typecheck.swift new file mode 100644 index 0000000000000..fa6d4537c1735 --- /dev/null +++ b/test/Interop/Cxx/templates/static-cast-typecheck.swift @@ -0,0 +1,44 @@ +// RUN: split-file %s %t +// RUN: %target-swift-frontend -typecheck -verify -suppress-remarks -suppress-notes \ +// RUN: -cxx-interoperability-mode=default \ +// RUN: -I %t%{fs-sep}Inputs %t%{fs-sep}main.swift \ +// RUN: -verify-additional-file %t%{fs-sep}Inputs%{fs-sep}header.h + +//--- Inputs/module.modulemap +module CxxHeader { + header "header.h" + requires cplusplus +} + +//--- Inputs/header.h +#pragma once + +// TODO: the following diagnostics should be moved to main.swift at the call site +// that triggers the instantiation +// expected-error@+4 {{could not substitute parameters for C++ function template 'cxxCast': BaseT, UnrelatedT}} +// expected-error@+3 {{could not substitute parameters for C++ function template 'cxxCast': BaseT, SubClassT}} +// expected-error@+2 {{could not substitute parameters for C++ function template 'cxxCast': BaseT, SubProtectedT}} +// expected-error@+1 {{could not substitute parameters for C++ function template 'cxxCast': BaseT, SubPrivateT}} +template O cxxCast(I i) { return static_cast(i); } +// expected-error@-1 {{cannot cast 'const SubPrivateT' to its private base class 'const BaseT'}} +// expected-error@-2 {{cannot cast 'const SubProtectedT' to its protected base class 'const BaseT'}} +// expected-error@-3 {{cannot cast 'const SubClassT' to its private base class 'const BaseT'}} +// expected-error@-4 {{no matching conversion for static_cast from 'UnrelatedT' to 'BaseT'}} + +struct BaseT { }; + +struct SubT : BaseT { }; // publicly inherit from BaseT +struct SubPrivateT : private BaseT { }; // privately inherit from BaseT +struct SubProtectedT : protected BaseT { }; // privately inherit from BaseT +class SubClassT : BaseT { }; // privately inherit from BaseT +struct UnrelatedT { }; // does not inherit from BaseT + + +//--- main.swift +import CxxHeader + +let _: BaseT = cxxCast(SubT()) // valid: upcast to public base +let _: BaseT = cxxCast(SubPrivateT()) // invalid: upcast to non-public base +let _: BaseT = cxxCast(SubProtectedT()) // invalid: upcast to non-public base +let _: BaseT = cxxCast(SubClassT()) // invalid: upcast to non-public base +let _: BaseT = cxxCast(UnrelatedT()) // invalid: cast to unrelated type