diff --git a/.github/new-prs-labeler.yml b/.github/new-prs-labeler.yml index 30ff1a4cf4868e..8789495ec2fe9c 100644 --- a/.github/new-prs-labeler.yml +++ b/.github/new-prs-labeler.yml @@ -668,7 +668,7 @@ mlgo: - llvm/lib/CodeGen/ML* - llvm/unittests/CodeGen/ML* - llvm/test/CodeGen/MLRegAlloc/** - - llvm/utils/mlgo-utils/* + - llvm/utils/mlgo-utils/** tools:llvm-exegesis: - llvm/tools/llvm-exegesis/** diff --git a/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py b/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py index b702eece37002b..f1b934f7139e94 100755 --- a/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py +++ b/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py @@ -49,7 +49,7 @@ import time import traceback from types import ModuleType -from typing import Any, Awaitable, Callable, List, Optional, Tuple, TypeVar +from typing import Any, Awaitable, Callable, List, Optional, TypeVar yaml: Optional[ModuleType] = None @@ -621,4 +621,7 @@ async def main() -> None: if __name__ == "__main__": - asyncio.run(main()) + try: + asyncio.run(main()) + except KeyboardInterrupt: + pass diff --git a/clang-tools-extra/clangd/DumpAST.cpp b/clang-tools-extra/clangd/DumpAST.cpp index 9a525efb938e8d..e605f82e91fe41 100644 --- a/clang-tools-extra/clangd/DumpAST.cpp +++ b/clang-tools-extra/clangd/DumpAST.cpp @@ -187,6 +187,7 @@ class DumpVisitor : public RecursiveASTVisitor { TEMPLATE_KIND(SubstTemplateTemplateParm); TEMPLATE_KIND(SubstTemplateTemplateParmPack); TEMPLATE_KIND(UsingTemplate); + TEMPLATE_KIND(DeducedTemplate); #undef TEMPLATE_KIND } llvm_unreachable("Unhandled NameKind enum"); diff --git a/clang-tools-extra/clangd/SemanticHighlighting.cpp b/clang-tools-extra/clangd/SemanticHighlighting.cpp index a366f1331c2d3d..e6d16af2495fec 100644 --- a/clang-tools-extra/clangd/SemanticHighlighting.cpp +++ b/clang-tools-extra/clangd/SemanticHighlighting.cpp @@ -1120,6 +1120,7 @@ class CollectExtraHighlightings case TemplateName::SubstTemplateTemplateParm: case TemplateName::SubstTemplateTemplateParmPack: case TemplateName::UsingTemplate: + case TemplateName::DeducedTemplate: // Names that could be resolved to a TemplateDecl are handled elsewhere. break; } diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 8d028f8863cb7a..1ad8cedc902cb5 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -95,6 +95,9 @@ The improvements are... Improvements to clang-tidy -------------------------- +- Improved :program:`run-clang-tidy.py` script. Fixed minor shutdown noise + happening on certain platforms when interrupting the script. + New checks ^^^^^^^^^^ diff --git a/clang/docs/ExternalClangExamples.rst b/clang/docs/ExternalClangExamples.rst index 8e986b83fd065f..ec95106b4697d1 100644 --- a/clang/docs/ExternalClangExamples.rst +++ b/clang/docs/ExternalClangExamples.rst @@ -34,7 +34,7 @@ List of projects and tools etc." ``_ - "A C/C++ source code indexer and navigator" + "A C/C++ source code indexer and navigator." ``_ "qconnectlint is a Clang tool for statically verifying the consistency @@ -98,3 +98,6 @@ List of projects and tools uses of reserved identifiers to ensuring that code adheres to lifecycle protocols for certain LibreOffice-specific classes. They may serve as examples for writing RecursiveASTVisitor-based plugins." + +``_ + "A collection of out-of-tree Clang plugins for teaching and learning." diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 684484ccd298fb..250821a9f9c45c 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -160,6 +160,9 @@ Resolutions to C++ Defect Reports - Allow ``void{}`` as a prvalue of type ``void``. (`CWG2351: void{} `_). +- Clang now has improved resolution to CWG2398, allowing class templates to have + default arguments deduced when partial ordering. + - Clang now allows comparing unequal object pointers that have been cast to ``void *`` in constant expressions. These comparisons always worked in non-constant expressions. (`CWG2749: Treatment of "pointer to void" for relational comparisons `_). @@ -240,6 +243,9 @@ Attribute Changes in Clang instantiation by accidentally allowing it in C++ in some circumstances. (#GH106864) +- Introduced a new attribute ``[[clang::coro_await_elidable]]`` on coroutine return types + to express elideability at call sites where the coroutine is co_awaited as a prvalue. + Improvements to Clang's diagnostics ----------------------------------- @@ -370,8 +376,8 @@ Bug Fixes to C++ Support - Fixed a bug in the substitution of empty pack indexing types. (#GH105903) - Clang no longer tries to capture non-odr used default arguments of template parameters of generic lambdas (#GH107048) - Fixed a bug where defaulted comparison operators would remove ``const`` from base classes. (#GH102588) - - Fix a crash when using ``source_location`` in the trailing return type of a lambda expression. (#GH67134) +- A follow-up fix was added for (#GH61460), as the previous fix was not entirely correct. (#GH86361) Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/docs/tools/clang-formatted-files.txt b/clang/docs/tools/clang-formatted-files.txt index fc07357986d989..48ded9c7545547 100644 --- a/clang/docs/tools/clang-formatted-files.txt +++ b/clang/docs/tools/clang-formatted-files.txt @@ -5349,7 +5349,6 @@ llvm/include/llvm/IR/SSAContext.h llvm/include/llvm/IR/StructuralHash.h llvm/include/llvm/IR/TrackingMDRef.h llvm/include/llvm/IR/UseListOrder.h -llvm/include/llvm/LTO/SummaryBasedOptimizations.h llvm/include/llvm/MC/MCAsmInfoCOFF.h llvm/include/llvm/MC/MCAsmInfoDarwin.h llvm/include/llvm/MC/MCAsmInfoELF.h @@ -5586,7 +5585,6 @@ llvm/include/llvm/Transforms/IPO/SampleProfile.h llvm/include/llvm/Transforms/IPO/SampleProfileProbe.h llvm/include/llvm/Transforms/IPO/SCCP.h llvm/include/llvm/Transforms/IPO/StripSymbols.h -llvm/include/llvm/Transforms/IPO/SyntheticCountsPropagation.h llvm/include/llvm/Transforms/IPO/ThinLTOBitcodeWriter.h llvm/include/llvm/Transforms/IPO/WholeProgramDevirt.h llvm/include/llvm/Transforms/Scalar/ADCE.h @@ -6070,7 +6068,6 @@ llvm/lib/IR/SSAContext.cpp llvm/lib/IR/Statepoint.cpp llvm/lib/IR/StructuralHash.cpp llvm/lib/IR/ValueSymbolTable.cpp -llvm/lib/LTO/SummaryBasedOptimizations.cpp llvm/lib/MC/MCAsmInfoCOFF.cpp llvm/lib/MC/MCAsmInfoELF.cpp llvm/lib/MC/MCAsmInfoGOFF.cpp @@ -6861,7 +6858,6 @@ llvm/lib/Transforms/IPO/OpenMPOpt.cpp llvm/lib/Transforms/IPO/SampleContextTracker.cpp llvm/lib/Transforms/IPO/SampleProfileProbe.cpp llvm/lib/Transforms/IPO/StripDeadPrototypes.cpp -llvm/lib/Transforms/IPO/SyntheticCountsPropagation.cpp llvm/lib/Transforms/ObjCARC/BlotMapVector.h llvm/lib/Transforms/ObjCARC/ObjCARCExpand.cpp llvm/lib/Transforms/ObjCARC/ProvenanceAnalysis.h diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 89bb5768dbd40d..168bdca3c880b2 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -265,6 +265,8 @@ class ASTContext : public RefCountedBase { mutable llvm::ContextualFoldingSet SubstTemplateTemplateParmPacks; + mutable llvm::ContextualFoldingSet + DeducedTemplates; mutable llvm::ContextualFoldingSet ArrayParameterTypes; @@ -2304,6 +2306,15 @@ class ASTContext : public RefCountedBase { unsigned Index, bool Final) const; + /// Represents a TemplateName which had some of its default arguments + /// deduced. This both represents this default argument deduction as sugar, + /// and provides the support for it's equivalences through canonicalization. + /// For example DeducedTemplateNames which have the same set of default + /// arguments are equivalent, and are also equivalent to the underlying + /// template when the deduced template arguments are the same. + TemplateName getDeducedTemplateName(TemplateName Underlying, + DefaultArguments DefaultArgs) const; + enum GetBuiltinTypeError { /// No error GE_None, @@ -2787,11 +2798,13 @@ class ASTContext : public RefCountedBase { /// template name uses the shortest form of the dependent /// nested-name-specifier, which itself contains all canonical /// types, values, and templates. - TemplateName getCanonicalTemplateName(const TemplateName &Name) const; + TemplateName getCanonicalTemplateName(TemplateName Name, + bool IgnoreDeduced = false) const; /// Determine whether the given template names refer to the same /// template. - bool hasSameTemplateName(const TemplateName &X, const TemplateName &Y) const; + bool hasSameTemplateName(const TemplateName &X, const TemplateName &Y, + bool IgnoreDeduced = false) const; /// Determine whether the two declarations refer to the same entity. bool isSameEntity(const NamedDecl *X, const NamedDecl *Y) const; diff --git a/clang/include/clang/AST/ASTImporter.h b/clang/include/clang/AST/ASTImporter.h index f851decd0965ce..088a2bd0fdd407 100644 --- a/clang/include/clang/AST/ASTImporter.h +++ b/clang/include/clang/AST/ASTImporter.h @@ -484,6 +484,11 @@ class TypeSourceInfo; /// the declarations it contains. [[nodiscard]] llvm::Error ImportDefinition(Decl *From); + llvm::Error + ImportTemplateArguments(ArrayRef FromArgs, + SmallVectorImpl &ToArgs); + Expected Import(const TemplateArgument &From); + /// Cope with a name conflict when importing a declaration into the /// given context. /// diff --git a/clang/include/clang/AST/DependenceFlags.h b/clang/include/clang/AST/DependenceFlags.h index 3b3c1afb096add..bdcaabc143cc40 100644 --- a/clang/include/clang/AST/DependenceFlags.h +++ b/clang/include/clang/AST/DependenceFlags.h @@ -315,6 +315,11 @@ toTemplateNameDependence(NestedNameSpecifierDependence D) { return Dependence(D).templateName(); } +inline TemplateNameDependence +toTemplateNameDependence(TemplateArgumentDependence D) { + return Dependence(D).templateName(); +} + LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); } // namespace clang diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 65104acda93825..66c746cc25040f 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -2991,6 +2991,9 @@ class CallExpr : public Expr { bool hasStoredFPFeatures() const { return CallExprBits.HasFPFeatures; } + bool isCoroElideSafe() const { return CallExprBits.IsCoroElideSafe; } + void setCoroElideSafe(bool V = true) { CallExprBits.IsCoroElideSafe = V; } + Decl *getCalleeDecl() { return getCallee()->getReferencedDeclOfCallee(); } const Decl *getCalleeDecl() const { return getCallee()->getReferencedDeclOfCallee(); diff --git a/clang/include/clang/AST/PropertiesBase.td b/clang/include/clang/AST/PropertiesBase.td index 5f7d6195187623..9b934b20cf2559 100644 --- a/clang/include/clang/AST/PropertiesBase.td +++ b/clang/include/clang/AST/PropertiesBase.td @@ -752,6 +752,23 @@ let Class = PropertyTypeCase in { return ctx.getSubstTemplateTemplateParmPack(argumentPack, associatedDecl, index, final); }]>; } +let Class = PropertyTypeCase in { + def : ReadHelper<[{ + auto DTS = node.getAsDeducedTemplateName(); + }]>; + def : Property<"underlying", TemplateName> { + let Read = [{ DTS->getUnderlying() }]; + } + def : Property<"startPos", UInt32> { + let Read = [{ DTS->getDefaultArguments().StartPos }]; + } + def : Property<"defaultArgs", Array> { + let Read = [{ DTS->getDefaultArguments().Args }]; + } + def : Creator<[{ + return ctx.getDeducedTemplateName(underlying, {startPos, defaultArgs}); + }]>; +} // Type cases for TemplateArgument. def : PropertyTypeKind(this) + : nullptr; + } + SubstTemplateTemplateParmStorage *getAsSubstTemplateTemplateParm() { return Bits.Kind == SubstTemplateTemplateParm ? reinterpret_cast(this) @@ -172,6 +180,15 @@ class SubstTemplateTemplateParmPackStorage : public UncommonTemplateNameStorage, unsigned Index, bool Final); }; +struct DefaultArguments { + // The position in the template parameter list + // the first argument corresponds to. + unsigned StartPos; + ArrayRef Args; + + operator bool() const { return !Args.empty(); } +}; + /// Represents a C++ template name within the type system. /// /// A C++ template name refers to a template within the C++ type @@ -246,6 +263,10 @@ class TemplateName { /// A template name that refers to a template declaration found through a /// specific using shadow declaration. UsingTemplate, + + /// A template name that refers to another TemplateName with deduced default + /// arguments. + DeducedTemplate, }; TemplateName() = default; @@ -257,6 +278,7 @@ class TemplateName { explicit TemplateName(QualifiedTemplateName *Qual); explicit TemplateName(DependentTemplateName *Dep); explicit TemplateName(UsingShadowDecl *Using); + explicit TemplateName(DeducedTemplateStorage *Deduced); /// Determine whether this template name is NULL. bool isNull() const; @@ -271,7 +293,13 @@ class TemplateName { /// to, if any. If the template name does not refer to a specific /// declaration because it is a dependent name, or if it refers to a /// set of function templates, returns NULL. - TemplateDecl *getAsTemplateDecl() const; + TemplateDecl *getAsTemplateDecl(bool IgnoreDeduced = false) const; + + /// Retrieves the underlying template declaration that + /// this template name refers to, along with the + /// deduced default arguments, if any. + std::pair + getTemplateDeclAndDefaultArgs() const; /// Retrieve the underlying, overloaded function template /// declarations that this template name refers to, if known. @@ -313,6 +341,11 @@ class TemplateName { /// template declaration is introduced, if any. UsingShadowDecl *getAsUsingShadowDecl() const; + /// Retrieve the deduced template info, if any. + DeducedTemplateStorage *getAsDeducedTemplateName() const; + + std::optional desugar(bool IgnoreDeduced) const; + TemplateName getUnderlying() const; TemplateNameDependence getDependence() const; @@ -412,6 +445,30 @@ class SubstTemplateTemplateParmStorage std::optional PackIndex); }; +class DeducedTemplateStorage : public UncommonTemplateNameStorage, + public llvm::FoldingSetNode { + friend class ASTContext; + + TemplateName Underlying; + + DeducedTemplateStorage(TemplateName Underlying, + const DefaultArguments &DefArgs); + +public: + TemplateName getUnderlying() const { return Underlying; } + + DefaultArguments getDefaultArguments() const { + return {/*StartPos=*/Bits.Index, + /*Args=*/{reinterpret_cast(this + 1), + Bits.Data}}; + } + + void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) const; + + static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, + TemplateName Underlying, const DefaultArguments &DefArgs); +}; + inline TemplateName TemplateName::getUnderlying() const { if (SubstTemplateTemplateParmStorage *subst = getAsSubstTemplateTemplateParm()) diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 0c98f8e25a6fbb..9a7b163b2c6da8 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -1250,6 +1250,14 @@ def CoroDisableLifetimeBound : InheritableAttr { let SimpleHandler = 1; } +def CoroAwaitElidable : InheritableAttr { + let Spellings = [Clang<"coro_await_elidable">]; + let Subjects = SubjectList<[CXXRecord]>; + let LangOpts = [CPlusPlus]; + let Documentation = [CoroAwaitElidableDoc]; + let SimpleHandler = 1; +} + // OSObject-based attributes. def OSConsumed : InheritableParamAttr { let Spellings = [Clang<"os_consumed">]; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index ef077db298831f..546e5100b79dd9 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -8255,6 +8255,38 @@ but do not pass them to the underlying coroutine or pass them by value. }]; } +def CoroAwaitElidableDoc : Documentation { + let Category = DocCatDecl; + let Content = [{ +The ``[[clang::coro_await_elidable]]`` is a class attribute which can be applied +to a coroutine return type. + +When a coroutine function that returns such a type calls another coroutine function, +the compiler performs heap allocation elision when the call to the coroutine function +is immediately co_awaited as a prvalue. In this case, the coroutine frame for the +callee will be a local variable within the enclosing braces in the caller's stack +frame. And the local variable, like other variables in coroutines, may be collected +into the coroutine frame, which may be allocated on the heap. + +Example: + +.. code-block:: c++ + + class [[clang::coro_await_elidable]] Task { ... }; + + Task foo(); + Task bar() { + co_await foo(); // foo()'s coroutine frame on this line is elidable + auto t = foo(); // foo()'s coroutine frame on this line is NOT elidable + co_await t; + } + +The behavior is undefined if the caller coroutine is destroyed earlier than the +callee coroutine. + +}]; +} + def CountedByDocs : Documentation { let Category = DocCatField; let Content = [{ @@ -8414,4 +8446,3 @@ Declares that a function potentially allocates heap memory, and prevents any pot of ``nonallocating`` by the compiler. }]; } - diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 92118418d9d459..d9833b6559eab3 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -4763,6 +4763,12 @@ def HLSLSaturate : LangBuiltin<"HLSL_LANG"> { let Prototype = "void(...)"; } +def HLSLSelect : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_select"]; + let Attributes = [NoThrow, Const]; + let Prototype = "void(...)"; +} + // Builtins for XRay. def XRayCustomEvent : Builtin { let Spellings = ["__xray_customevent"]; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 58819a64813fce..b160fee827a750 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -9206,6 +9206,9 @@ def err_typecheck_expect_scalar_operand : Error< "operand of type %0 where arithmetic or pointer type is required">; def err_typecheck_cond_incompatible_operands : Error< "incompatible operand types%diff{ ($ and $)|}0,1">; +def err_typecheck_expect_scalar_or_vector : Error< + "invalid operand of type %0 where %1 or " + "a vector of such type is required">; def err_typecheck_expect_flt_or_vector : Error< "invalid operand of type %0 where floating, complex or " "a vector of such types is required">; diff --git a/clang/include/clang/Basic/OpenMPKinds.h b/clang/include/clang/Basic/OpenMPKinds.h index 16bb967f89d53e..1acdafa8572211 100644 --- a/clang/include/clang/Basic/OpenMPKinds.h +++ b/clang/include/clang/Basic/OpenMPKinds.h @@ -15,6 +15,7 @@ #define LLVM_CLANG_BASIC_OPENMPKINDS_H #include "clang/Basic/LangOptions.h" +#include "llvm/ADT/Sequence.h" #include "llvm/ADT/StringRef.h" #include "llvm/Frontend/OpenMP/OMPConstants.h" @@ -389,5 +390,9 @@ bool isOpenMPInformationalDirective(OpenMPDirectiveKind DKind); bool isOpenMPCapturingDirective(OpenMPDirectiveKind DKind); } +template <> +struct llvm::enum_iteration_traits { + static constexpr bool is_iterable = true; +}; #endif diff --git a/clang/include/clang/Basic/arm_neon.td b/clang/include/clang/Basic/arm_neon.td index 875ec6e90b685b..92f39744f3d084 100644 --- a/clang/include/clang/Basic/arm_neon.td +++ b/clang/include/clang/Basic/arm_neon.td @@ -2120,4 +2120,9 @@ let ArchGuard = "defined(__aarch64__)", TargetGuard = "lut" in { def VLUTI4_BF_X2_Q : SInst<"vluti4_laneq_x2", ".2(]>; } -} \ No newline at end of file +} + +let ArchGuard = "defined(__aarch64__)", TargetGuard = "neon,faminmax" in { + def FAMIN : WInst<"vamin", "...", "fhQdQfQh">; + def FAMAX : WInst<"vamax", "...", "fhQdQfQh">; +} diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 37e80c24be3214..f78032255f036f 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1051,6 +1051,7 @@ def z : Separate<["-"], "z">, Flags<[LinkerInput]>, def offload_link : Flag<["--"], "offload-link">, Group, HelpText<"Use the new offloading linker to perform the link job.">; def Xlinker : Separate<["-"], "Xlinker">, Flags<[LinkerInput, RenderAsInput]>, + Visibility<[ClangOption, CLOption, FlangOption, DXCOption]>, HelpText<"Pass to the linker">, MetaVarName<"">, Group; def Xoffload_linker : JoinedAndSeparate<["-"], "Xoffload-linker">, @@ -5986,7 +5987,9 @@ def _no_line_commands : Flag<["--"], "no-line-commands">, Alias

; def _no_standard_includes : Flag<["--"], "no-standard-includes">, Alias; def _no_standard_libraries : Flag<["--"], "no-standard-libraries">, Alias; def _no_undefined : Flag<["--"], "no-undefined">, Flags<[LinkerInput]>; -def _no_warnings : Flag<["--"], "no-warnings">, Alias; +def _no_warnings : Flag<["--"], "no-warnings">, + Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>, + Alias; def _optimize_EQ : Joined<["--"], "optimize=">, Alias; def _optimize : Flag<["--"], "optimize">, Alias; def _output_class_directory_EQ : Joined<["--"], "output-class-directory=">, Alias; diff --git a/clang/include/clang/Driver/Types.def b/clang/include/clang/Driver/Types.def index 0e0cae5fb7068d..af186c5df69201 100644 --- a/clang/include/clang/Driver/Types.def +++ b/clang/include/clang/Driver/Types.def @@ -79,7 +79,17 @@ TYPE("c++-module-cpp-output", PP_CXXModule, INVALID, "iim", phases TYPE("ada", Ada, INVALID, nullptr, phases::Compile, phases::Backend, phases::Assemble, phases::Link) TYPE("assembler", PP_Asm, INVALID, "s", phases::Assemble, phases::Link) TYPE("assembler-with-cpp", Asm, PP_Asm, "S", phases::Preprocess, phases::Assemble, phases::Link) -TYPE("f95", PP_Fortran, INVALID, "i", phases::Compile, phases::Backend, phases::Assemble, phases::Link) + +// Note: The `phases::Preprocess` phase is added to ".i" (i.e. Fortran +// pre-processed) files. The reason is that the pre-processor "phase" has to be +// re-run to make sure that e.g. the include flags (i.e. `-I

`) are +// preserved. That's because these include paths will contain module files and, +// unlike C header files, these module files wouldn't be included in the +// pre-processed file. In particular, we need to add the search paths for these +// modules when Flang needs to emit pre-processed files. Therefore, the +// `PP_TYPE` is set to `PP_Fortran` so that the driver is fine with +// "pre-processing a pre-processed file". +TYPE("f95", PP_Fortran, PP_Fortran, "i", phases::Preprocess, phases::Compile, phases::Backend, phases::Assemble, phases::Link) TYPE("f95-cpp-input", Fortran, PP_Fortran, nullptr, phases::Preprocess, phases::Compile, phases::Backend, phases::Assemble, phases::Link) TYPE("java", Java, INVALID, nullptr, phases::Compile, phases::Backend, phases::Assemble, phases::Link) diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index a7513069ff5da0..47f72135c97cff 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -2943,6 +2943,9 @@ class Parser : public CodeCompletionHandler { return false; } + bool ParseSingleGNUAttribute(ParsedAttributes &Attrs, SourceLocation &EndLoc, + LateParsedAttrList *LateAttrs = nullptr, + Declarator *D = nullptr); void ParseGNUAttributes(ParsedAttributes &Attrs, LateParsedAttrList *LateAttrs = nullptr, Declarator *D = nullptr); diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h index d6a6cee62a7528..c716a25bb673b8 100644 --- a/clang/include/clang/Sema/Overload.h +++ b/clang/include/clang/Sema/Overload.h @@ -225,9 +225,6 @@ class Sema; /// HLSL Scalar Widening with promotion ICR_HLSL_Scalar_Widening_Promotion, - /// HLSL Matching Dimension Reduction - ICR_HLSL_Dimension_Reduction, - /// Conversion ICR_Conversion, @@ -250,6 +247,9 @@ class Sema; /// extension anyway. ICR_C_Conversion_Extension, + /// HLSL Matching Dimension Reduction + ICR_HLSL_Dimension_Reduction, + /// HLSL Dimension reduction with promotion ICR_HLSL_Dimension_Reduction_Promotion, diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 0358259945c796..68c782a15c6f1b 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -11733,6 +11733,9 @@ class Sema final : public SemaBase { /// receive true if the cause for the error is the associated constraints of /// the template not being satisfied by the template arguments. /// + /// \param DefaultArgs any default arguments from template specialization + /// deduction. + /// /// \param PartialOrderingTTP If true, assume these template arguments are /// the injected template arguments for a template template parameter. /// This will relax the requirement that all its possible uses are valid: @@ -11742,7 +11745,8 @@ class Sema final : public SemaBase { /// \returns true if an error occurred, false otherwise. bool CheckTemplateArgumentList( TemplateDecl *Template, SourceLocation TemplateLoc, - TemplateArgumentListInfo &TemplateArgs, bool PartialTemplateArgs, + TemplateArgumentListInfo &TemplateArgs, + const DefaultArguments &DefaultArgs, bool PartialTemplateArgs, SmallVectorImpl &SugaredConverted, SmallVectorImpl &CanonicalConverted, bool UpdateArgsWithConversions = true, @@ -12479,8 +12483,8 @@ class Sema final : public SemaBase { sema::TemplateDeductionInfo &Info); bool isTemplateTemplateParameterAtLeastAsSpecializedAs( - TemplateParameterList *PParam, TemplateDecl *AArg, SourceLocation Loc, - bool IsDeduced); + TemplateParameterList *PParam, TemplateDecl *AArg, + const DefaultArguments &DefaultArgs, SourceLocation Loc, bool IsDeduced); /// Mark which template parameters are used in a given expression. /// diff --git a/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h b/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h index ad25d18f280700..24c5b66fd58220 100644 --- a/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h +++ b/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h @@ -164,8 +164,6 @@ class CheckerManager { bool hasPathSensitiveCheckers() const; - void finishedCheckerRegistration(); - const LangOptions &getLangOpts() const { return LangOpts; } const AnalyzerOptions &getAnalyzerOptions() const { return AOptions; } const Preprocessor &getPreprocessor() const { diff --git a/clang/include/clang/Tooling/Inclusions/StandardLibrary.h b/clang/include/clang/Tooling/Inclusions/StandardLibrary.h index a39ceb520dcf8a..147f505ade0584 100644 --- a/clang/include/clang/Tooling/Inclusions/StandardLibrary.h +++ b/clang/include/clang/Tooling/Inclusions/StandardLibrary.h @@ -21,6 +21,7 @@ #include "llvm/Support/raw_ostream.h" #include #include +#include namespace clang { class Decl; diff --git a/clang/lib/APINotes/APINotesWriter.cpp b/clang/lib/APINotes/APINotesWriter.cpp index c452677983bb36..2f4e5e803f6a2b 100644 --- a/clang/lib/APINotes/APINotesWriter.cpp +++ b/clang/lib/APINotes/APINotesWriter.cpp @@ -147,14 +147,8 @@ class APINotesWriter::Implementation { for (auto piece : SelectorRef.Identifiers) Selector.Identifiers.push_back(getIdentifier(piece)); - // Look for the stored selector. - auto Known = SelectorIDs.find(Selector); - if (Known != SelectorIDs.end()) - return Known->second; - - // Add to the selector table. - Known = SelectorIDs.insert({Selector, SelectorIDs.size()}).first; - return Known->second; + // Look for the stored selector. Add to the selector table if missing. + return SelectorIDs.try_emplace(Selector, SelectorIDs.size()).first->second; } private: diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 341ea98a1b1490..fa9cc38efc4662 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -881,8 +881,8 @@ ASTContext::ASTContext(LangOptions &LOpts, SourceManager &SM, TemplateSpecializationTypes(this_()), DependentTemplateSpecializationTypes(this_()), AutoTypes(this_()), DependentBitIntTypes(this_()), SubstTemplateTemplateParmPacks(this_()), - ArrayParameterTypes(this_()), CanonTemplateTemplateParms(this_()), - SourceMgr(SM), LangOpts(LOpts), + DeducedTemplates(this_()), ArrayParameterTypes(this_()), + CanonTemplateTemplateParms(this_()), SourceMgr(SM), LangOpts(LOpts), NoSanitizeL(new NoSanitizeList(LangOpts.NoSanitizeFiles, SM)), XRayFilter(new XRayFunctionFilter(LangOpts.XRayAlwaysInstrumentFiles, LangOpts.XRayNeverInstrumentFiles, @@ -5411,7 +5411,7 @@ ASTContext::getTemplateSpecializationType(TemplateName Template, assert(!Template.getAsDependentTemplateName() && "No dependent template names here!"); - const auto *TD = Template.getAsTemplateDecl(); + const auto *TD = Template.getAsTemplateDecl(/*IgnoreDeduced=*/true); bool IsTypeAlias = TD && TD->isTypeAlias(); QualType CanonType; if (!Underlying.isNull()) @@ -5446,7 +5446,12 @@ QualType ASTContext::getCanonicalTemplateSpecializationType( "No dependent template names here!"); // Build the canonical template specialization type. - TemplateName CanonTemplate = getCanonicalTemplateName(Template); + // Any DeducedTemplateNames are ignored, because the effective name of a TST + // accounts for the TST arguments laid over any default arguments contained in + // its name. + TemplateName CanonTemplate = + getCanonicalTemplateName(Template, /*IgnoreDeduced=*/true); + bool AnyNonCanonArgs = false; auto CanonArgs = ::getCanonicalTemplateArguments(*this, Args, AnyNonCanonArgs); @@ -6753,16 +6758,41 @@ ASTContext::getNameForTemplate(TemplateName Name, case TemplateName::UsingTemplate: return DeclarationNameInfo(Name.getAsUsingShadowDecl()->getDeclName(), NameLoc); + case TemplateName::DeducedTemplate: { + DeducedTemplateStorage *DTS = Name.getAsDeducedTemplateName(); + return getNameForTemplate(DTS->getUnderlying(), NameLoc); + } } llvm_unreachable("bad template name kind!"); } -TemplateName -ASTContext::getCanonicalTemplateName(const TemplateName &Name) const { +static const TemplateArgument * +getDefaultTemplateArgumentOrNone(const NamedDecl *P) { + auto handleParam = [](auto *TP) -> const TemplateArgument * { + if (!TP->hasDefaultArgument()) + return nullptr; + return &TP->getDefaultArgument().getArgument(); + }; + switch (P->getKind()) { + case NamedDecl::TemplateTypeParm: + return handleParam(cast(P)); + case NamedDecl::NonTypeTemplateParm: + return handleParam(cast(P)); + case NamedDecl::TemplateTemplateParm: + return handleParam(cast(P)); + default: + llvm_unreachable("Unexpected template parameter kind"); + } +} + +TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name, + bool IgnoreDeduced) const { + while (std::optional UnderlyingOrNone = + Name.desugar(IgnoreDeduced)) + Name = *UnderlyingOrNone; + switch (Name.getKind()) { - case TemplateName::UsingTemplate: - case TemplateName::QualifiedTemplate: case TemplateName::Template: { TemplateDecl *Template = Name.getAsTemplateDecl(); if (auto *TTP = dyn_cast(Template)) @@ -6782,12 +6812,6 @@ ASTContext::getCanonicalTemplateName(const TemplateName &Name) const { return DTN->CanonicalTemplateName; } - case TemplateName::SubstTemplateTemplateParm: { - SubstTemplateTemplateParmStorage *subst - = Name.getAsSubstTemplateTemplateParm(); - return getCanonicalTemplateName(subst->getReplacement()); - } - case TemplateName::SubstTemplateTemplateParmPack: { SubstTemplateTemplateParmPackStorage *subst = Name.getAsSubstTemplateTemplateParmPack(); @@ -6797,15 +6821,58 @@ ASTContext::getCanonicalTemplateName(const TemplateName &Name) const { canonArgPack, subst->getAssociatedDecl()->getCanonicalDecl(), subst->getFinal(), subst->getIndex()); } + case TemplateName::DeducedTemplate: { + assert(IgnoreDeduced == false); + DeducedTemplateStorage *DTS = Name.getAsDeducedTemplateName(); + DefaultArguments DefArgs = DTS->getDefaultArguments(); + TemplateName Underlying = DTS->getUnderlying(); + + TemplateName CanonUnderlying = + getCanonicalTemplateName(Underlying, /*IgnoreDeduced=*/true); + bool NonCanonical = CanonUnderlying != Underlying; + auto CanonArgs = + getCanonicalTemplateArguments(*this, DefArgs.Args, NonCanonical); + + ArrayRef Params = + CanonUnderlying.getAsTemplateDecl()->getTemplateParameters()->asArray(); + assert(CanonArgs.size() <= Params.size()); + // A deduced template name which deduces the same default arguments already + // declared in the underlying template is the same template as the + // underlying template. We need need to note any arguments which differ from + // the corresponding declaration. If any argument differs, we must build a + // deduced template name. + for (int I = CanonArgs.size() - 1; I >= 0; --I) { + const TemplateArgument *A = getDefaultTemplateArgumentOrNone(Params[I]); + if (!A) + break; + auto CanonParamDefArg = getCanonicalTemplateArgument(*A); + TemplateArgument &CanonDefArg = CanonArgs[I]; + if (CanonDefArg.structurallyEquals(CanonParamDefArg)) + continue; + // Keep popping from the back any deault arguments which are the same. + if (I == int(CanonArgs.size() - 1)) + CanonArgs.pop_back(); + NonCanonical = true; + } + return NonCanonical ? getDeducedTemplateName( + CanonUnderlying, + /*DefaultArgs=*/{DefArgs.StartPos, CanonArgs}) + : Name; + } + case TemplateName::UsingTemplate: + case TemplateName::QualifiedTemplate: + case TemplateName::SubstTemplateTemplateParm: + llvm_unreachable("always sugar node"); } llvm_unreachable("bad template name!"); } bool ASTContext::hasSameTemplateName(const TemplateName &X, - const TemplateName &Y) const { - return getCanonicalTemplateName(X).getAsVoidPointer() == - getCanonicalTemplateName(Y).getAsVoidPointer(); + const TemplateName &Y, + bool IgnoreDeduced) const { + return getCanonicalTemplateName(X, IgnoreDeduced) == + getCanonicalTemplateName(Y, IgnoreDeduced); } bool ASTContext::isSameConstraintExpr(const Expr *XCE, const Expr *YCE) const { @@ -7294,7 +7361,7 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) const { case TemplateArgument::StructuralValue: return TemplateArgument(*this, getCanonicalType(Arg.getStructuralValueType()), - Arg.getAsStructuralValue()); + Arg.getAsStructuralValue(), Arg.getIsDefaulted()); case TemplateArgument::Type: return TemplateArgument(getCanonicalType(Arg.getAsType()), @@ -7306,8 +7373,10 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) const { *this, Arg.pack_elements(), AnyNonCanonArgs); if (!AnyNonCanonArgs) return Arg; - return TemplateArgument::CreatePackCopy(const_cast(*this), - CanonArgs); + auto NewArg = TemplateArgument::CreatePackCopy( + const_cast(*this), CanonArgs); + NewArg.setIsDefaulted(Arg.getIsDefaulted()); + return NewArg; } } @@ -9864,6 +9933,30 @@ ASTContext::getSubstTemplateTemplateParmPack(const TemplateArgument &ArgPack, return TemplateName(Subst); } +/// Retrieve the template name that represents a template name +/// deduced from a specialization. +TemplateName +ASTContext::getDeducedTemplateName(TemplateName Underlying, + DefaultArguments DefaultArgs) const { + if (!DefaultArgs) + return Underlying; + + llvm::FoldingSetNodeID ID; + DeducedTemplateStorage::Profile(ID, *this, Underlying, DefaultArgs); + + void *InsertPos = nullptr; + DeducedTemplateStorage *DTS = + DeducedTemplates.FindNodeOrInsertPos(ID, InsertPos); + if (!DTS) { + void *Mem = Allocate(sizeof(DeducedTemplateStorage) + + sizeof(TemplateArgument) * DefaultArgs.Args.size(), + alignof(DeducedTemplateStorage)); + DTS = new (Mem) DeducedTemplateStorage(Underlying, DefaultArgs); + DeducedTemplates.InsertNode(DTS, InsertPos); + } + return TemplateName(DTS); +} + /// getFromTargetType - Given one of the integer types provided by /// TargetInfo, produce the corresponding type. The unsigned @p Type /// is actually a value of type @c TargetInfo::IntType. @@ -13020,22 +13113,24 @@ static T *getCommonDeclChecked(T *X, T *Y) { } static TemplateName getCommonTemplateName(ASTContext &Ctx, TemplateName X, - TemplateName Y) { + TemplateName Y, + bool IgnoreDeduced = false) { if (X.getAsVoidPointer() == Y.getAsVoidPointer()) return X; // FIXME: There are cases here where we could find a common template name // with more sugar. For example one could be a SubstTemplateTemplate* // replacing the other. - TemplateName CX = Ctx.getCanonicalTemplateName(X); + TemplateName CX = Ctx.getCanonicalTemplateName(X, IgnoreDeduced); if (CX.getAsVoidPointer() != Ctx.getCanonicalTemplateName(Y).getAsVoidPointer()) return TemplateName(); return CX; } -static TemplateName -getCommonTemplateNameChecked(ASTContext &Ctx, TemplateName X, TemplateName Y) { - TemplateName R = getCommonTemplateName(Ctx, X, Y); +static TemplateName getCommonTemplateNameChecked(ASTContext &Ctx, + TemplateName X, TemplateName Y, + bool IgnoreDeduced) { + TemplateName R = getCommonTemplateName(Ctx, X, Y, IgnoreDeduced); assert(R.getAsVoidPointer() != nullptr); return R; } @@ -13522,7 +13617,8 @@ static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X, TY->template_arguments()); return Ctx.getTemplateSpecializationType( ::getCommonTemplateNameChecked(Ctx, TX->getTemplateName(), - TY->getTemplateName()), + TY->getTemplateName(), + /*IgnoreDeduced=*/true), As, X->getCanonicalTypeInternal()); } case Type::Decltype: { @@ -13751,8 +13847,9 @@ static QualType getCommonSugarTypeNode(ASTContext &Ctx, const Type *X, case Type::TemplateSpecialization: { const auto *TX = cast(X), *TY = cast(Y); - TemplateName CTN = ::getCommonTemplateName(Ctx, TX->getTemplateName(), - TY->getTemplateName()); + TemplateName CTN = + ::getCommonTemplateName(Ctx, TX->getTemplateName(), + TY->getTemplateName(), /*IgnoreDeduced=*/true); if (!CTN.getAsVoidPointer()) return QualType(); SmallVector Args; diff --git a/clang/lib/AST/ASTDiagnostic.cpp b/clang/lib/AST/ASTDiagnostic.cpp index 0680ff5e3a3851..15c3efe4212719 100644 --- a/clang/lib/AST/ASTDiagnostic.cpp +++ b/clang/lib/AST/ASTDiagnostic.cpp @@ -1114,8 +1114,8 @@ class TemplateDiff { // These functions build up the template diff tree, including functions to // retrieve and compare template arguments. - static const TemplateSpecializationType *GetTemplateSpecializationType( - ASTContext &Context, QualType Ty) { + static const TemplateSpecializationType * + GetTemplateSpecializationType(ASTContext &Context, QualType Ty) { if (const TemplateSpecializationType *TST = Ty->getAs()) return TST; @@ -1159,7 +1159,7 @@ class TemplateDiff { if (!FromArgTST || !ToArgTST) return true; - if (!hasSameTemplate(FromArgTST, ToArgTST)) + if (!hasSameTemplate(Context, FromArgTST, ToArgTST)) return true; return false; @@ -1371,11 +1371,17 @@ class TemplateDiff { /// argument info into a tree. void DiffTemplate(const TemplateSpecializationType *FromTST, const TemplateSpecializationType *ToTST) { + // FIXME: With P3310R0, A TST formed from a DeducedTemplateName might + // differ in template arguments which were not written. // Begin descent into diffing template tree. TemplateParameterList *ParamsFrom = - FromTST->getTemplateName().getAsTemplateDecl()->getTemplateParameters(); + FromTST->getTemplateName() + .getAsTemplateDecl(/*IgnoreDeduced=*/true) + ->getTemplateParameters(); TemplateParameterList *ParamsTo = - ToTST->getTemplateName().getAsTemplateDecl()->getTemplateParameters(); + ToTST->getTemplateName() + .getAsTemplateDecl(/*IgnoreDeduced=*/true) + ->getTemplateParameters(); unsigned TotalArgs = 0; for (TSTiterator FromIter(Context, FromTST), ToIter(Context, ToTST); !FromIter.isEnd() || !ToIter.isEnd(); ++TotalArgs) { @@ -1427,20 +1433,24 @@ class TemplateDiff { /// hasSameBaseTemplate - Returns true when the base templates are the same, /// even if the template arguments are not. - static bool hasSameBaseTemplate(const TemplateSpecializationType *FromTST, + static bool hasSameBaseTemplate(ASTContext &Context, + const TemplateSpecializationType *FromTST, const TemplateSpecializationType *ToTST) { - return FromTST->getTemplateName().getAsTemplateDecl()->getCanonicalDecl() == - ToTST->getTemplateName().getAsTemplateDecl()->getCanonicalDecl(); + return Context.getCanonicalTemplateName(FromTST->getTemplateName(), + /*IgnoreDeduced=*/true) == + Context.getCanonicalTemplateName(ToTST->getTemplateName(), + /*IgnoreDeduced=*/true); } /// hasSameTemplate - Returns true if both types are specialized from the /// same template declaration. If they come from different template aliases, /// do a parallel ascension search to determine the highest template alias in /// common and set the arguments to them. - static bool hasSameTemplate(const TemplateSpecializationType *&FromTST, + static bool hasSameTemplate(ASTContext &Context, + const TemplateSpecializationType *&FromTST, const TemplateSpecializationType *&ToTST) { // Check the top templates if they are the same. - if (hasSameBaseTemplate(FromTST, ToTST)) + if (hasSameBaseTemplate(Context, FromTST, ToTST)) return true; // Create vectors of template aliases. @@ -1455,14 +1465,14 @@ class TemplateDiff { ToIter = ToTemplateList.rbegin(), ToEnd = ToTemplateList.rend(); // Check if the lowest template types are the same. If not, return. - if (!hasSameBaseTemplate(*FromIter, *ToIter)) + if (!hasSameBaseTemplate(Context, *FromIter, *ToIter)) return false; // Begin searching up the template aliases. The bottom most template // matches so move up until one pair does not match. Use the template // right before that one. for (; FromIter != FromEnd && ToIter != ToEnd; ++FromIter, ++ToIter) { - if (!hasSameBaseTemplate(*FromIter, *ToIter)) + if (!hasSameBaseTemplate(Context, *FromIter, *ToIter)) break; } @@ -2123,7 +2133,7 @@ class TemplateDiff { return; // Different base templates. - if (!hasSameTemplate(FromOrigTST, ToOrigTST)) { + if (!hasSameTemplate(Context, FromOrigTST, ToOrigTST)) { return; } @@ -2131,10 +2141,11 @@ class TemplateDiff { ToQual -= QualType(ToOrigTST, 0).getQualifiers(); // Same base template, but different arguments. - Tree.SetTemplateDiff(FromOrigTST->getTemplateName().getAsTemplateDecl(), - ToOrigTST->getTemplateName().getAsTemplateDecl(), - FromQual, ToQual, false /*FromDefault*/, - false /*ToDefault*/); + Tree.SetTemplateDiff( + FromOrigTST->getTemplateName().getAsTemplateDecl( + /*IgnoreDeduced=*/true), + ToOrigTST->getTemplateName().getAsTemplateDecl(/*IgnoreDeduced=*/true), + FromQual, ToQual, false /*FromDefault*/, false /*ToDefault*/); DiffTemplate(FromOrigTST, ToOrigTST); } diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index e854dbfb7bf2e5..c2fb7dddcfc637 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -9935,6 +9935,8 @@ Expected ASTImporter::Import(TemplateName From) { return UsingOrError.takeError(); return TemplateName(cast(*UsingOrError)); } + case TemplateName::DeducedTemplate: + llvm_unreachable("Unexpected DeducedTemplate"); } llvm_unreachable("Invalid template name kind"); diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp index 0b791700aa48dd..f13ca2d08d769f 100644 --- a/clang/lib/AST/ASTStructuralEquivalence.cpp +++ b/clang/lib/AST/ASTStructuralEquivalence.cpp @@ -645,6 +645,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, // It is sufficient to check value of getAsTemplateDecl. break; + case TemplateName::DeducedTemplate: + // FIXME: We can't reach here. + llvm_unreachable("unimplemented"); } return true; diff --git a/clang/lib/AST/ByteCode/ByteCodeEmitter.h b/clang/lib/AST/ByteCode/ByteCodeEmitter.h index 7cbbe651699b34..ac728830527a26 100644 --- a/clang/lib/AST/ByteCode/ByteCodeEmitter.h +++ b/clang/lib/AST/ByteCode/ByteCodeEmitter.h @@ -46,7 +46,7 @@ class ByteCodeEmitter { /// Methods implemented by the compiler. virtual bool visitFunc(const FunctionDecl *E) = 0; - virtual bool visitExpr(const Expr *E) = 0; + virtual bool visitExpr(const Expr *E, bool DestroyToplevelScope) = 0; virtual bool visitDeclAndReturn(const VarDecl *E, bool ConstantContext) = 0; /// Emits jumps. diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index eea77c2f0a9bb4..fddd6db4f4814c 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -114,19 +114,23 @@ template class LoopScope final : public LabelScope { LoopScope(Compiler *Ctx, LabelTy BreakLabel, LabelTy ContinueLabel) : LabelScope(Ctx), OldBreakLabel(Ctx->BreakLabel), - OldContinueLabel(Ctx->ContinueLabel) { + OldContinueLabel(Ctx->ContinueLabel), + OldLabelVarScope(Ctx->LabelVarScope) { this->Ctx->BreakLabel = BreakLabel; this->Ctx->ContinueLabel = ContinueLabel; + this->Ctx->LabelVarScope = this->Ctx->VarScope; } ~LoopScope() { this->Ctx->BreakLabel = OldBreakLabel; this->Ctx->ContinueLabel = OldContinueLabel; + this->Ctx->LabelVarScope = OldLabelVarScope; } private: OptLabelTy OldBreakLabel; OptLabelTy OldContinueLabel; + VariableScope *OldLabelVarScope; }; // Sets the context for a switch scope, mapping labels. @@ -140,22 +144,26 @@ template class SwitchScope final : public LabelScope { OptLabelTy DefaultLabel) : LabelScope(Ctx), OldBreakLabel(Ctx->BreakLabel), OldDefaultLabel(this->Ctx->DefaultLabel), - OldCaseLabels(std::move(this->Ctx->CaseLabels)) { + OldCaseLabels(std::move(this->Ctx->CaseLabels)), + OldLabelVarScope(Ctx->LabelVarScope) { this->Ctx->BreakLabel = BreakLabel; this->Ctx->DefaultLabel = DefaultLabel; this->Ctx->CaseLabels = std::move(CaseLabels); + this->Ctx->LabelVarScope = this->Ctx->VarScope; } ~SwitchScope() { this->Ctx->BreakLabel = OldBreakLabel; this->Ctx->DefaultLabel = OldDefaultLabel; this->Ctx->CaseLabels = std::move(OldCaseLabels); + this->Ctx->LabelVarScope = OldLabelVarScope; } private: OptLabelTy OldBreakLabel; OptLabelTy OldDefaultLabel; CaseMap OldCaseLabels; + VariableScope *OldLabelVarScope; }; template class StmtExprScope final { @@ -1232,7 +1240,7 @@ bool Compiler::VisitVectorBinOp(const BinaryOperator *E) { // FIXME: Current only support comparison binary operator, add support for // other binary operator. - if (!E->isComparisonOp()) + if (!E->isComparisonOp() && !E->isLogicalOp()) return this->emitInvalid(E); // Prepare storage for result. if (!Initializing) { @@ -1267,7 +1275,15 @@ bool Compiler::VisitVectorBinOp(const BinaryOperator *E) { auto getElem = [=](unsigned Offset, unsigned Index) { if (!this->emitGetLocal(PT_Ptr, Offset, E)) return false; - return this->emitArrayElemPop(ElemT, Index, E); + if (!this->emitArrayElemPop(ElemT, Index, E)) + return false; + if (E->isLogicalOp()) { + if (!this->emitPrimCast(ElemT, PT_Bool, Ctx.getASTContext().BoolTy, E)) + return false; + if (!this->emitPrimCast(PT_Bool, ResultElemT, VecTy->getElementType(), E)) + return false; + } + return true; }; for (unsigned I = 0; I != VecTy->getNumElements(); ++I) { @@ -1300,6 +1316,16 @@ bool Compiler::VisitVectorBinOp(const BinaryOperator *E) { if (!this->emitGT(ElemT, E)) return false; break; + case BO_LAnd: + // a && b is equivalent to a!=0 & b!=0 + if (!this->emitBitAnd(ResultElemT, E)) + return false; + break; + case BO_LOr: + // a || b is equivalent to a!=0 | b!=0 + if (!this->emitBitOr(ResultElemT, E)) + return false; + break; default: llvm_unreachable("Unsupported binary operator"); } @@ -1874,8 +1900,12 @@ bool Compiler::VisitMemberExpr(const MemberExpr *E) { return false; } - if (!isa(Member)) - return this->discard(Base) && this->visitDeclRef(Member, E); + if (!isa(Member)) { + if (!this->discard(Base) && !this->emitSideEffect(E)) + return false; + + return this->visitDeclRef(Member, E); + } if (Initializing) { if (!this->delegate(Base)) @@ -2579,8 +2609,15 @@ bool Compiler::VisitCXXReinterpretCastExpr( const CXXReinterpretCastExpr *E) { const Expr *SubExpr = E->getSubExpr(); - bool TypesMatch = classify(E) == classify(SubExpr); - if (!this->emitInvalidCast(CastKind::Reinterpret, /*Fatal=*/!TypesMatch, E)) + bool Fatal = false; + std::optional FromT = classify(SubExpr); + std::optional ToT = classify(E); + if (!FromT || !ToT) + Fatal = true; + else + Fatal = (ToT != FromT); + + if (!this->emitInvalidCast(CastKind::Reinterpret, Fatal, E)) return false; return this->delegate(SubExpr); @@ -2666,8 +2703,14 @@ bool Compiler::VisitCXXConstructExpr(const CXXConstructExpr *E) { if (!this->emitCallVar(Func, VarArgSize, E)) return false; } else { - if (!this->emitCall(Func, 0, E)) + if (!this->emitCall(Func, 0, E)) { + // When discarding, we don't need the result anyway, so clean up + // the instance dup we did earlier in case surrounding code wants + // to keep evaluating. + if (DiscardResult) + (void)this->emitPopPtr(E); return false; + } } if (DiscardResult) @@ -3303,6 +3346,10 @@ bool Compiler::VisitCXXStdInitializerListExpr( if (!this->visit(SubExpr)) return false; + if (!this->emitConstUint8(0, E)) + return false; + if (!this->emitArrayElemPtrPopUint8(E)) + return false; if (!this->emitInitFieldPtr(R->getField(0u)->Offset, E)) return false; @@ -3317,6 +3364,8 @@ bool Compiler::VisitCXXStdInitializerListExpr( if (!this->emitGetFieldPtr(R->getField(0u)->Offset, E)) return false; + if (!this->emitExpandPtr(E)) + return false; if (!this->emitConst(static_cast(ArrayType->getSize()), PT_Uint64, E)) return false; if (!this->emitArrayElemPtrPop(PT_Uint64, E)) @@ -3716,20 +3765,29 @@ const Function *Compiler::getFunction(const FunctionDecl *FD) { return Ctx.getOrCreateFunction(FD); } -template bool Compiler::visitExpr(const Expr *E) { +template +bool Compiler::visitExpr(const Expr *E, bool DestroyToplevelScope) { LocalScope RootScope(this); + + auto maybeDestroyLocals = [&]() -> bool { + if (DestroyToplevelScope) + return RootScope.destroyLocals(); + return true; + }; + // Void expressions. if (E->getType()->isVoidType()) { if (!visit(E)) return false; - return this->emitRetVoid(E) && RootScope.destroyLocals(); + return this->emitRetVoid(E) && maybeDestroyLocals(); } // Expressions with a primitive return type. if (std::optional T = classify(E)) { if (!visit(E)) return false; - return this->emitRet(*T, E) && RootScope.destroyLocals(); + + return this->emitRet(*T, E) && maybeDestroyLocals(); } // Expressions with a composite return type. @@ -3747,10 +3805,10 @@ template bool Compiler::visitExpr(const Expr *E) { // We are destroying the locals AFTER the Ret op. // The Ret op needs to copy the (alive) values, but the // destructors may still turn the entire expression invalid. - return this->emitRetValue(E) && RootScope.destroyLocals(); + return this->emitRetValue(E) && maybeDestroyLocals(); } - RootScope.destroyLocals(); + (void)maybeDestroyLocals(); return false; } @@ -4044,18 +4102,18 @@ bool Compiler::visitAPValueInitializer(const APValue &Val, } template -bool Compiler::VisitBuiltinCallExpr(const CallExpr *E) { +bool Compiler::VisitBuiltinCallExpr(const CallExpr *E, + unsigned BuiltinID) { const Function *Func = getFunction(E->getDirectCallee()); if (!Func) return false; // For these, we're expected to ultimately return an APValue pointing // to the CallExpr. This is needed to get the correct codegen. - unsigned Builtin = E->getBuiltinCallee(); - if (Builtin == Builtin::BI__builtin___CFStringMakeConstantString || - Builtin == Builtin::BI__builtin___NSStringMakeConstantString || - Builtin == Builtin::BI__builtin_ptrauth_sign_constant || - Builtin == Builtin::BI__builtin_function_start) { + if (BuiltinID == Builtin::BI__builtin___CFStringMakeConstantString || + BuiltinID == Builtin::BI__builtin___NSStringMakeConstantString || + BuiltinID == Builtin::BI__builtin_ptrauth_sign_constant || + BuiltinID == Builtin::BI__builtin_function_start) { if (std::optional GlobalOffset = P.createGlobal(E)) { if (!this->emitGetPtrGlobal(*GlobalOffset, E)) return false; @@ -4087,7 +4145,7 @@ bool Compiler::VisitBuiltinCallExpr(const CallExpr *E) { } } - if (!this->emitCallBI(Func, E, E)) + if (!this->emitCallBI(Func, E, BuiltinID, E)) return false; if (DiscardResult && !ReturnType->isVoidType()) { @@ -4100,13 +4158,24 @@ bool Compiler::VisitBuiltinCallExpr(const CallExpr *E) { template bool Compiler::VisitCallExpr(const CallExpr *E) { - if (E->getBuiltinCallee()) - return VisitBuiltinCallExpr(E); + if (unsigned BuiltinID = E->getBuiltinCallee()) + return VisitBuiltinCallExpr(E, BuiltinID); + + const FunctionDecl *FuncDecl = E->getDirectCallee(); + // Calls to replaceable operator new/operator delete. + if (FuncDecl && FuncDecl->isReplaceableGlobalAllocationFunction()) { + if (FuncDecl->getDeclName().getCXXOverloadedOperator() == OO_New || + FuncDecl->getDeclName().getCXXOverloadedOperator() == OO_Array_New) { + return VisitBuiltinCallExpr(E, Builtin::BI__builtin_operator_new); + } else { + assert(FuncDecl->getDeclName().getCXXOverloadedOperator() == OO_Delete); + return VisitBuiltinCallExpr(E, Builtin::BI__builtin_operator_delete); + } + } QualType ReturnType = E->getCallReturnType(Ctx.getASTContext()); std::optional T = classify(ReturnType); bool HasRVO = !ReturnType->isVoidType() && !T; - const FunctionDecl *FuncDecl = E->getDirectCallee(); if (HasRVO) { if (DiscardResult) { @@ -4691,7 +4760,9 @@ bool Compiler::visitBreakStmt(const BreakStmt *S) { if (!BreakLabel) return false; - this->emitCleanup(); + for (VariableScope *C = VarScope; C != LabelVarScope; + C = C->getParent()) + C->emitDestruction(); return this->jump(*BreakLabel); } @@ -4700,7 +4771,9 @@ bool Compiler::visitContinueStmt(const ContinueStmt *S) { if (!ContinueLabel) return false; - this->emitCleanup(); + for (VariableScope *C = VarScope; C != LabelVarScope; + C = C->getParent()) + C->emitDestruction(); return this->jump(*ContinueLabel); } @@ -5608,11 +5681,18 @@ bool Compiler::visitDeclRef(const ValueDecl *D, const Expr *E) { if (isa(VD)) return revisit(VD); - // Visit local const variables like normal. - if ((VD->hasGlobalStorage() || VD->isLocalVarDecl() || - VD->isStaticDataMember()) && + if ((VD->hasGlobalStorage() || VD->isStaticDataMember()) && typeShouldBeVisited(VD->getType())) return revisit(VD); + + // FIXME: The evaluateValue() check here is a little ridiculous, since + // it will ultimately call into Context::evaluateAsInitializer(). In + // other words, we're evaluating the initializer, just to know if we can + // evaluate the initializer. + if (VD->isLocalVarDecl() && typeShouldBeVisited(VD->getType()) && + VD->getInit() && !VD->getInit()->isValueDependent() && + VD->evaluateValue()) + return revisit(VD); } } else { if (const auto *VD = dyn_cast(D); diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h index e6f54fe05427b7..ac4c08c4d0ffb6 100644 --- a/clang/lib/AST/ByteCode/Compiler.h +++ b/clang/lib/AST/ByteCode/Compiler.h @@ -133,7 +133,7 @@ class Compiler : public ConstStmtVisitor, bool>, bool VisitVectorBinOp(const BinaryOperator *E); bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E); bool VisitCallExpr(const CallExpr *E); - bool VisitBuiltinCallExpr(const CallExpr *E); + bool VisitBuiltinCallExpr(const CallExpr *E, unsigned BuiltinID); bool VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E); bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E); bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E); @@ -222,7 +222,7 @@ class Compiler : public ConstStmtVisitor, bool>, protected: bool visitStmt(const Stmt *S); - bool visitExpr(const Expr *E) override; + bool visitExpr(const Expr *E, bool DestroyToplevelScope) override; bool visitFunc(const FunctionDecl *F) override; bool visitDeclAndReturn(const VarDecl *VD, bool ConstantContext) override; @@ -409,6 +409,8 @@ class Compiler : public ConstStmtVisitor, bool>, /// Switch case mapping. CaseMap CaseLabels; + /// Scope to cleanup until when chumping to one of the labels. + VariableScope *LabelVarScope = nullptr; /// Point to break to. OptLabelTy BreakLabel; /// Point to continue to. diff --git a/clang/lib/AST/ByteCode/Context.cpp b/clang/lib/AST/ByteCode/Context.cpp index e682d87b703ad7..8661acf536658f 100644 --- a/clang/lib/AST/ByteCode/Context.cpp +++ b/clang/lib/AST/ByteCode/Context.cpp @@ -44,13 +44,14 @@ bool Context::isPotentialConstantExpr(State &Parent, const FunctionDecl *FD) { bool Context::evaluateAsRValue(State &Parent, const Expr *E, APValue &Result) { ++EvalID; bool Recursing = !Stk.empty(); + size_t StackSizeBefore = Stk.size(); Compiler C(*this, *P, Parent, Stk); auto Res = C.interpretExpr(E, /*ConvertResultToRValue=*/E->isGLValue()); if (Res.isInvalid()) { C.cleanup(); - Stk.clear(); + Stk.clearTo(StackSizeBefore); return false; } @@ -60,7 +61,7 @@ bool Context::evaluateAsRValue(State &Parent, const Expr *E, APValue &Result) { #ifndef NDEBUG // Make sure we don't rely on some value being still alive in // InterpStack memory. - Stk.clear(); + Stk.clearTo(StackSizeBefore); #endif } @@ -69,15 +70,19 @@ bool Context::evaluateAsRValue(State &Parent, const Expr *E, APValue &Result) { return true; } -bool Context::evaluate(State &Parent, const Expr *E, APValue &Result) { +bool Context::evaluate(State &Parent, const Expr *E, APValue &Result, + ConstantExprKind Kind) { ++EvalID; bool Recursing = !Stk.empty(); + size_t StackSizeBefore = Stk.size(); Compiler C(*this, *P, Parent, Stk); - auto Res = C.interpretExpr(E); + auto Res = C.interpretExpr(E, /*ConvertResultToRValue=*/false, + /*DestroyToplevelScope=*/Kind == + ConstantExprKind::ClassTemplateArgument); if (Res.isInvalid()) { C.cleanup(); - Stk.clear(); + Stk.clearTo(StackSizeBefore); return false; } @@ -87,7 +92,7 @@ bool Context::evaluate(State &Parent, const Expr *E, APValue &Result) { #ifndef NDEBUG // Make sure we don't rely on some value being still alive in // InterpStack memory. - Stk.clear(); + Stk.clearTo(StackSizeBefore); #endif } @@ -99,6 +104,7 @@ bool Context::evaluateAsInitializer(State &Parent, const VarDecl *VD, APValue &Result) { ++EvalID; bool Recursing = !Stk.empty(); + size_t StackSizeBefore = Stk.size(); Compiler C(*this, *P, Parent, Stk); bool CheckGlobalInitialized = @@ -107,7 +113,8 @@ bool Context::evaluateAsInitializer(State &Parent, const VarDecl *VD, auto Res = C.interpretDecl(VD, CheckGlobalInitialized); if (Res.isInvalid()) { C.cleanup(); - Stk.clear(); + Stk.clearTo(StackSizeBefore); + return false; } @@ -117,7 +124,7 @@ bool Context::evaluateAsInitializer(State &Parent, const VarDecl *VD, #ifndef NDEBUG // Make sure we don't rely on some value being still alive in // InterpStack memory. - Stk.clear(); + Stk.clearTo(StackSizeBefore); #endif } diff --git a/clang/lib/AST/ByteCode/Context.h b/clang/lib/AST/ByteCode/Context.h index b8ea4ad6b3b447..e0d4bafdebaf2b 100644 --- a/clang/lib/AST/ByteCode/Context.h +++ b/clang/lib/AST/ByteCode/Context.h @@ -52,7 +52,8 @@ class Context final { bool evaluateAsRValue(State &Parent, const Expr *E, APValue &Result); /// Like evaluateAsRvalue(), but does no implicit lvalue-to-rvalue conversion. - bool evaluate(State &Parent, const Expr *E, APValue &Result); + bool evaluate(State &Parent, const Expr *E, APValue &Result, + ConstantExprKind Kind); /// Evaluates a toplevel initializer. bool evaluateAsInitializer(State &Parent, const VarDecl *VD, APValue &Result); diff --git a/clang/lib/AST/ByteCode/DynamicAllocator.cpp b/clang/lib/AST/ByteCode/DynamicAllocator.cpp index a5159977407805..819fbdb8b070bf 100644 --- a/clang/lib/AST/ByteCode/DynamicAllocator.cpp +++ b/clang/lib/AST/ByteCode/DynamicAllocator.cpp @@ -40,27 +40,30 @@ void DynamicAllocator::cleanup() { } Block *DynamicAllocator::allocate(const Expr *Source, PrimType T, - size_t NumElements, unsigned EvalID) { + size_t NumElements, unsigned EvalID, + Form AllocForm) { // Create a new descriptor for an array of the specified size and // element type. const Descriptor *D = allocateDescriptor( Source, T, Descriptor::InlineDescMD, NumElements, /*IsConst=*/false, /*IsTemporary=*/false, /*IsMutable=*/false); - return allocate(D, EvalID); + return allocate(D, EvalID, AllocForm); } Block *DynamicAllocator::allocate(const Descriptor *ElementDesc, - size_t NumElements, unsigned EvalID) { + size_t NumElements, unsigned EvalID, + Form AllocForm) { // Create a new descriptor for an array of the specified size and // element type. const Descriptor *D = allocateDescriptor( ElementDesc->asExpr(), ElementDesc, Descriptor::InlineDescMD, NumElements, /*IsConst=*/false, /*IsTemporary=*/false, /*IsMutable=*/false); - return allocate(D, EvalID); + return allocate(D, EvalID, AllocForm); } -Block *DynamicAllocator::allocate(const Descriptor *D, unsigned EvalID) { +Block *DynamicAllocator::allocate(const Descriptor *D, unsigned EvalID, + Form AllocForm) { assert(D); assert(D->asExpr()); @@ -84,7 +87,7 @@ Block *DynamicAllocator::allocate(const Descriptor *D, unsigned EvalID) { It->second.Allocations.emplace_back(std::move(Memory)); else AllocationSites.insert( - {D->asExpr(), AllocationSite(std::move(Memory), D->isArray())}); + {D->asExpr(), AllocationSite(std::move(Memory), AllocForm)}); return B; } diff --git a/clang/lib/AST/ByteCode/DynamicAllocator.h b/clang/lib/AST/ByteCode/DynamicAllocator.h index a84600aa54cc56..1ed5dc843e4c8c 100644 --- a/clang/lib/AST/ByteCode/DynamicAllocator.h +++ b/clang/lib/AST/ByteCode/DynamicAllocator.h @@ -31,6 +31,14 @@ class InterpState; /// For all array allocations, we need to allocate new Descriptor instances, /// so the DynamicAllocator has a llvm::BumpPtrAllocator similar to Program. class DynamicAllocator final { +public: + enum class Form : uint8_t { + NonArray, + Array, + Operator, + }; + +private: struct Allocation { std::unique_ptr Memory; Allocation(std::unique_ptr Memory) @@ -39,10 +47,10 @@ class DynamicAllocator final { struct AllocationSite { llvm::SmallVector Allocations; - bool IsArrayAllocation = false; + Form AllocForm; - AllocationSite(std::unique_ptr Memory, bool Array) - : IsArrayAllocation(Array) { + AllocationSite(std::unique_ptr Memory, Form AllocForm) + : AllocForm(AllocForm) { Allocations.push_back({std::move(Memory)}); } @@ -58,12 +66,13 @@ class DynamicAllocator final { unsigned getNumAllocations() const { return AllocationSites.size(); } /// Allocate ONE element of the given descriptor. - Block *allocate(const Descriptor *D, unsigned EvalID); + Block *allocate(const Descriptor *D, unsigned EvalID, Form AllocForm); /// Allocate \p NumElements primitive elements of the given type. Block *allocate(const Expr *Source, PrimType T, size_t NumElements, - unsigned EvalID); + unsigned EvalID, Form AllocForm); /// Allocate \p NumElements elements of the given descriptor. - Block *allocate(const Descriptor *D, size_t NumElements, unsigned EvalID); + Block *allocate(const Descriptor *D, size_t NumElements, unsigned EvalID, + Form AllocForm); /// Deallocate the given source+block combination. /// Returns \c true if anything has been deallocatd, \c false otherwise. @@ -72,10 +81,10 @@ class DynamicAllocator final { /// Checks whether the allocation done at the given source is an array /// allocation. - bool isArrayAllocation(const Expr *Source) const { + std::optional
getAllocationForm(const Expr *Source) const { if (auto It = AllocationSites.find(Source); It != AllocationSites.end()) - return It->second.IsArrayAllocation; - return false; + return It->second.AllocForm; + return std::nullopt; } /// Allocation site iterator. diff --git a/clang/lib/AST/ByteCode/EvalEmitter.cpp b/clang/lib/AST/ByteCode/EvalEmitter.cpp index 3b9e5f9f9f69cd..7eecee25bb3c1e 100644 --- a/clang/lib/AST/ByteCode/EvalEmitter.cpp +++ b/clang/lib/AST/ByteCode/EvalEmitter.cpp @@ -38,13 +38,14 @@ EvalEmitter::~EvalEmitter() { void EvalEmitter::cleanup() { S.cleanup(); } EvaluationResult EvalEmitter::interpretExpr(const Expr *E, - bool ConvertResultToRValue) { + bool ConvertResultToRValue, + bool DestroyToplevelScope) { S.setEvalLocation(E->getExprLoc()); this->ConvertResultToRValue = ConvertResultToRValue && !isa(E); this->CheckFullyInitialized = isa(E); EvalResult.setSource(E); - if (!this->visitExpr(E)) { + if (!this->visitExpr(E, DestroyToplevelScope)) { // EvalResult may already have a result set, but something failed // after that (e.g. evaluating destructors). EvalResult.setInvalid(); diff --git a/clang/lib/AST/ByteCode/EvalEmitter.h b/clang/lib/AST/ByteCode/EvalEmitter.h index 338786d3dea91c..e7c9e80d75d934 100644 --- a/clang/lib/AST/ByteCode/EvalEmitter.h +++ b/clang/lib/AST/ByteCode/EvalEmitter.h @@ -35,7 +35,8 @@ class EvalEmitter : public SourceMapper { using Local = Scope::Local; EvaluationResult interpretExpr(const Expr *E, - bool ConvertResultToRValue = false); + bool ConvertResultToRValue = false, + bool DestroyToplevelScope = false); EvaluationResult interpretDecl(const VarDecl *VD, bool CheckFullyInitialized); /// Clean up all resources. @@ -54,7 +55,7 @@ class EvalEmitter : public SourceMapper { LabelTy getLabel(); /// Methods implemented by the compiler. - virtual bool visitExpr(const Expr *E) = 0; + virtual bool visitExpr(const Expr *E, bool DestroyToplevelScope) = 0; virtual bool visitDeclAndReturn(const VarDecl *VD, bool ConstantContext) = 0; virtual bool visitFunc(const FunctionDecl *F) = 0; diff --git a/clang/lib/AST/ByteCode/Function.h b/clang/lib/AST/ByteCode/Function.h index b21fa8497130ea..640bfa65644f0f 100644 --- a/clang/lib/AST/ByteCode/Function.h +++ b/clang/lib/AST/ByteCode/Function.h @@ -103,10 +103,10 @@ class Function final { /// Returns the name of the function decl this code /// was generated for. const std::string getName() const { - if (!Source) + if (!Source || !getDecl()) return "<>"; - return Source.get()->getQualifiedNameAsString(); + return getDecl()->getQualifiedNameAsString(); } /// Returns a parameter descriptor. diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index 6777ac150abf4f..ac02bd6d033487 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -221,17 +221,17 @@ static void popArg(InterpState &S, const Expr *Arg) { TYPE_SWITCH(Ty, S.Stk.discard()); } -void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC) { +void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC, + const Function *Func) { assert(S.Current); - const Function *CurFunc = S.Current->getFunction(); - assert(CurFunc); + assert(Func); - if (CurFunc->isUnevaluatedBuiltin()) + if (Func->isUnevaluatedBuiltin()) return; // Some builtin functions require us to only look at the call site, since // the classified parameter types do not match. - if (unsigned BID = CurFunc->getBuiltinID(); + if (unsigned BID = Func->getBuiltinID(); BID && S.getASTContext().BuiltinInfo.hasCustomTypechecking(BID)) { const auto *CE = cast(S.Current->Caller->getExpr(S.Current->getRetPC())); @@ -242,7 +242,7 @@ void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC) { return; } - if (S.Current->Caller && CurFunc->isVariadic()) { + if (S.Current->Caller && Func->isVariadic()) { // CallExpr we're look for is at the return PC of the current function, i.e. // in the caller. // This code path should be executed very rarely. @@ -259,8 +259,8 @@ void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC) { } else assert(false && "Can't get arguments from that expression type"); - assert(NumArgs >= CurFunc->getNumWrittenParams()); - NumVarArgs = NumArgs - (CurFunc->getNumWrittenParams() + + assert(NumArgs >= Func->getNumWrittenParams()); + NumVarArgs = NumArgs - (Func->getNumWrittenParams() + isa(CallSite)); for (unsigned I = 0; I != NumVarArgs; ++I) { const Expr *A = Args[NumArgs - 1 - I]; @@ -270,7 +270,8 @@ void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC) { // And in any case, remove the fixed parameters (the non-variadic ones) // at the end. - S.Current->popArgs(); + for (PrimType Ty : Func->args_reverse()) + TYPE_SWITCH(Ty, S.Stk.discard()); } bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { @@ -811,10 +812,11 @@ bool CheckDynamicMemoryAllocation(InterpState &S, CodePtr OpPC) { return true; } -bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC, bool NewWasArray, - bool DeleteIsArray, const Descriptor *D, +bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC, + DynamicAllocator::Form AllocForm, + DynamicAllocator::Form DeleteForm, const Descriptor *D, const Expr *NewExpr) { - if (NewWasArray == DeleteIsArray) + if (AllocForm == DeleteForm) return true; QualType TypeToDiagnose; @@ -831,7 +833,8 @@ bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC, bool NewWasArray, const SourceInfo &E = S.Current->getSource(OpPC); S.FFDiag(E, diag::note_constexpr_new_delete_mismatch) - << DeleteIsArray << 0 << TypeToDiagnose; + << static_cast(DeleteForm) << static_cast(AllocForm) + << TypeToDiagnose; S.Note(NewExpr->getExprLoc(), diag::note_constexpr_dynamic_alloc_here) << NewExpr->getSourceRange(); return false; @@ -839,7 +842,12 @@ bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC, bool NewWasArray, bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const Expr *Source, const Pointer &Ptr) { - if (Source && isa(Source)) + // The two sources we currently allow are new expressions and + // __builtin_operator_new calls. + if (isa_and_nonnull(Source)) + return true; + if (const CallExpr *CE = dyn_cast_if_present(Source); + CE && CE->getBuiltinCallee() == Builtin::BI__builtin_operator_new) return true; // Whatever this is, we didn't heap allocate it. @@ -1036,6 +1044,12 @@ bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func, bool Call(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize) { + assert(Func); + auto cleanup = [&]() -> bool { + cleanupAfterFunctionCall(S, OpPC, Func); + return false; + }; + if (Func->hasThisPointer()) { size_t ArgSize = Func->getArgSize() + VarArgSize; size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0); @@ -1052,22 +1066,22 @@ bool Call(InterpState &S, CodePtr OpPC, const Function *Func, assert(ThisPtr.isZero()); } else { if (!CheckInvoke(S, OpPC, ThisPtr)) - return false; + return cleanup(); } } if (!CheckCallable(S, OpPC, Func)) - return false; + return cleanup(); // FIXME: The isConstructor() check here is not always right. The current // constant evaluator is somewhat inconsistent in when it allows a function // call when checking for a constant expression. if (Func->hasThisPointer() && S.checkingPotentialConstantExpression() && !Func->isConstructor()) - return false; + return cleanup(); if (!CheckCallDepth(S, OpPC)) - return false; + return cleanup(); auto NewFrame = std::make_unique(S, Func, OpPC, VarArgSize); InterpFrame *FrameBefore = S.Current; @@ -1164,13 +1178,15 @@ bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func, } bool CallBI(InterpState &S, CodePtr &PC, const Function *Func, - const CallExpr *CE) { + const CallExpr *CE, uint32_t BuiltinID) { + if (S.checkingPotentialConstantExpression()) + return false; auto NewFrame = std::make_unique(S, Func, PC); InterpFrame *FrameBefore = S.Current; S.Current = NewFrame.get(); - if (InterpretBuiltin(S, PC, Func, CE)) { + if (InterpretBuiltin(S, PC, Func, CE, BuiltinID)) { NewFrame.release(); return true; } diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index be900769f25845..e345b9ead967ce 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -130,8 +130,9 @@ bool CheckNonNullArgs(InterpState &S, CodePtr OpPC, const Function *F, bool CheckDynamicMemoryAllocation(InterpState &S, CodePtr OpPC); /// Diagnose mismatched new[]/delete or new/delete[] pairs. -bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC, bool NewWasArray, - bool DeleteIsArray, const Descriptor *D, +bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC, + DynamicAllocator::Form AllocForm, + DynamicAllocator::Form DeleteForm, const Descriptor *D, const Expr *NewExpr); /// Check the source of the pointer passed to delete/delete[] has actually @@ -154,7 +155,7 @@ bool Call(InterpState &S, CodePtr OpPC, const Function *Func, bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize); bool CallBI(InterpState &S, CodePtr &PC, const Function *Func, - const CallExpr *CE); + const CallExpr *CE, uint32_t BuiltinID); bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize, const CallExpr *CE); @@ -267,7 +268,7 @@ bool Interpret(InterpState &S, APValue &Result); /// Interpret a builtin function. bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, - const CallExpr *Call); + const CallExpr *Call, uint32_t BuiltinID); /// Interpret an offsetof operation. bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E, @@ -281,7 +282,8 @@ enum class ArithOp { Add, Sub }; // Returning values //===----------------------------------------------------------------------===// -void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC); +void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC, + const Function *Func); template ::T> bool Ret(InterpState &S, CodePtr &PC, APValue &Result) { @@ -302,7 +304,7 @@ bool Ret(InterpState &S, CodePtr &PC, APValue &Result) { assert(S.Current); assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame"); if (!S.checkingPotentialConstantExpression() || S.Current->Caller) - cleanupAfterFunctionCall(S, PC); + cleanupAfterFunctionCall(S, PC, S.Current->getFunction()); if (InterpFrame *Caller = S.Current->Caller) { PC = S.Current->getRetPC(); @@ -322,7 +324,7 @@ inline bool RetVoid(InterpState &S, CodePtr &PC, APValue &Result) { assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame"); if (!S.checkingPotentialConstantExpression() || S.Current->Caller) - cleanupAfterFunctionCall(S, PC); + cleanupAfterFunctionCall(S, PC, S.Current->getFunction()); if (InterpFrame *Caller = S.Current->Caller) { PC = S.Current->getRetPC(); @@ -1991,7 +1993,9 @@ bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset, template ::T> bool AddOffset(InterpState &S, CodePtr OpPC) { const T &Offset = S.Stk.pop(); - const Pointer &Ptr = S.Stk.pop(); + Pointer Ptr = S.Stk.pop(); + if (Ptr.isBlockPointer()) + Ptr = Ptr.expand(); return OffsetHelper(S, OpPC, Offset, Ptr); } @@ -2658,6 +2662,9 @@ inline bool Unsupported(InterpState &S, CodePtr OpPC) { /// Do nothing and just abort execution. inline bool Error(InterpState &S, CodePtr OpPC) { return false; } +inline bool SideEffect(InterpState &S, CodePtr OpPC) { + return S.noteSideEffect(); +} /// Same here, but only for casts. inline bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind, @@ -2793,10 +2800,11 @@ inline bool Alloc(InterpState &S, CodePtr OpPC, const Descriptor *Desc) { return false; DynamicAllocator &Allocator = S.getAllocator(); - Block *B = Allocator.allocate(Desc, S.Ctx.getEvalID()); + Block *B = Allocator.allocate(Desc, S.Ctx.getEvalID(), + DynamicAllocator::Form::NonArray); assert(B); - S.Stk.push(B, sizeof(InlineDescriptor)); + S.Stk.push(B); return true; } @@ -2818,8 +2826,9 @@ inline bool AllocN(InterpState &S, CodePtr OpPC, PrimType T, const Expr *Source, } DynamicAllocator &Allocator = S.getAllocator(); - Block *B = Allocator.allocate(Source, T, static_cast(NumElements), - S.Ctx.getEvalID()); + Block *B = + Allocator.allocate(Source, T, static_cast(NumElements), + S.Ctx.getEvalID(), DynamicAllocator::Form::Array); assert(B); S.Stk.push(B, sizeof(InlineDescriptor)); @@ -2844,8 +2853,9 @@ inline bool AllocCN(InterpState &S, CodePtr OpPC, const Descriptor *ElementDesc, } DynamicAllocator &Allocator = S.getAllocator(); - Block *B = Allocator.allocate(ElementDesc, static_cast(NumElements), - S.Ctx.getEvalID()); + Block *B = + Allocator.allocate(ElementDesc, static_cast(NumElements), + S.Ctx.getEvalID(), DynamicAllocator::Form::Array); assert(B); S.Stk.push(B, sizeof(InlineDescriptor)); @@ -2890,8 +2900,9 @@ static inline bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm) { return false; DynamicAllocator &Allocator = S.getAllocator(); - bool WasArrayAlloc = Allocator.isArrayAllocation(Source); const Descriptor *BlockDesc = BlockToDelete->getDescriptor(); + std::optional AllocForm = + Allocator.getAllocationForm(Source); if (!Allocator.deallocate(Source, BlockToDelete, S)) { // Nothing has been deallocated, this must be a double-delete. @@ -2899,8 +2910,13 @@ static inline bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm) { S.FFDiag(Loc, diag::note_constexpr_double_delete); return false; } - return CheckNewDeleteForms(S, OpPC, WasArrayAlloc, DeleteIsArrayForm, - BlockDesc, Source); + + assert(AllocForm); + DynamicAllocator::Form DeleteForm = DeleteIsArrayForm + ? DynamicAllocator::Form::Array + : DynamicAllocator::Form::NonArray; + return CheckNewDeleteForms(S, OpPC, *AllocForm, DeleteForm, BlockDesc, + Source); } static inline bool IsConstantContext(InterpState &S, CodePtr OpPC) { diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index 81e49f203524b7..51c77b7da1a655 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -1244,14 +1244,164 @@ static bool interp__builtin_constant_p(InterpState &S, CodePtr OpPC, return returnInt(false); } +static bool interp__builtin_operator_new(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, + const Function *Func, + const CallExpr *Call) { + // A call to __operator_new is only valid within std::allocate<>::allocate. + // Walk up the call stack to find the appropriate caller and get the + // element type from it. + QualType ElemType; + + for (const InterpFrame *F = Frame; F; F = F->Caller) { + const Function *Func = F->getFunction(); + if (!Func) + continue; + const auto *MD = dyn_cast_if_present(Func->getDecl()); + if (!MD) + continue; + const IdentifierInfo *FnII = MD->getIdentifier(); + if (!FnII || !FnII->isStr("allocate")) + continue; + + const auto *CTSD = + dyn_cast(MD->getParent()); + if (!CTSD) + continue; + + const IdentifierInfo *ClassII = CTSD->getIdentifier(); + const TemplateArgumentList &TAL = CTSD->getTemplateArgs(); + if (CTSD->isInStdNamespace() && ClassII && ClassII->isStr("allocator") && + TAL.size() >= 1 && TAL[0].getKind() == TemplateArgument::Type) { + ElemType = TAL[0].getAsType(); + break; + } + } + + if (ElemType.isNull()) { + S.FFDiag(Call, S.getLangOpts().CPlusPlus20 + ? diag::note_constexpr_new_untyped + : diag::note_constexpr_new); + return false; + } + + if (ElemType->isIncompleteType() || ElemType->isFunctionType()) { + S.FFDiag(Call, diag::note_constexpr_new_not_complete_object_type) + << (ElemType->isIncompleteType() ? 0 : 1) << ElemType; + return false; + } + + APSInt Bytes = peekToAPSInt(S.Stk, *S.getContext().classify(Call->getArg(0))); + CharUnits ElemSize = S.getASTContext().getTypeSizeInChars(ElemType); + assert(!ElemSize.isZero()); + // Divide the number of bytes by sizeof(ElemType), so we get the number of + // elements we should allocate. + APInt NumElems, Remainder; + APInt ElemSizeAP(Bytes.getBitWidth(), ElemSize.getQuantity()); + APInt::udivrem(Bytes, ElemSizeAP, NumElems, Remainder); + if (Remainder != 0) { + // This likely indicates a bug in the implementation of 'std::allocator'. + S.FFDiag(Call, diag::note_constexpr_operator_new_bad_size) + << Bytes << APSInt(ElemSizeAP, true) << ElemType; + return false; + } + + // FIXME: CheckArraySize for NumElems? + + std::optional ElemT = S.getContext().classify(ElemType); + DynamicAllocator &Allocator = S.getAllocator(); + if (ElemT) { + if (NumElems.ule(1)) { + const Descriptor *Desc = + S.P.createDescriptor(Call, *ElemT, Descriptor::InlineDescMD, + /*IsConst=*/false, /*IsTemporary=*/false, + /*IsMutable=*/false); + Block *B = Allocator.allocate(Desc, S.getContext().getEvalID(), + DynamicAllocator::Form::Operator); + assert(B); + + S.Stk.push(B); + return true; + } + assert(NumElems.ugt(1)); + + Block *B = + Allocator.allocate(Call, *ElemT, NumElems.getZExtValue(), + S.Ctx.getEvalID(), DynamicAllocator::Form::Operator); + assert(B); + S.Stk.push(B); + return true; + } + + assert(!ElemT); + // Structs etc. + const Descriptor *Desc = S.P.createDescriptor( + Call, ElemType.getTypePtr(), + NumElems.ule(1) ? std::nullopt : Descriptor::InlineDescMD, + /*IsConst=*/false, /*IsTemporary=*/false, /*IsMutable=*/false, + /*Init=*/nullptr); + + if (NumElems.ule(1)) { + Block *B = Allocator.allocate(Desc, S.getContext().getEvalID(), + DynamicAllocator::Form::Operator); + assert(B); + S.Stk.push(B); + return true; + } + + Block *B = + Allocator.allocate(Desc, NumElems.getZExtValue(), S.Ctx.getEvalID(), + DynamicAllocator::Form::Operator); + assert(B); + S.Stk.push(B); + return true; +} + +static bool interp__builtin_operator_delete(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, + const Function *Func, + const CallExpr *Call) { + const Expr *Source = nullptr; + const Block *BlockToDelete = nullptr; + + { + const Pointer &Ptr = S.Stk.peek(); + + if (Ptr.isZero()) { + S.CCEDiag(Call, diag::note_constexpr_deallocate_null); + return true; + } + + Source = Ptr.getDeclDesc()->asExpr(); + BlockToDelete = Ptr.block(); + } + assert(BlockToDelete); + + DynamicAllocator &Allocator = S.getAllocator(); + const Descriptor *BlockDesc = BlockToDelete->getDescriptor(); + std::optional AllocForm = + Allocator.getAllocationForm(Source); + + if (!Allocator.deallocate(Source, BlockToDelete, S)) { + // Nothing has been deallocated, this must be a double-delete. + const SourceInfo &Loc = S.Current->getSource(OpPC); + S.FFDiag(Loc, diag::note_constexpr_double_delete); + return false; + } + assert(AllocForm); + + return CheckNewDeleteForms( + S, OpPC, *AllocForm, DynamicAllocator::Form::Operator, BlockDesc, Source); +} + bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, - const CallExpr *Call) { + const CallExpr *Call, uint32_t BuiltinID) { const InterpFrame *Frame = S.Current; APValue Dummy; std::optional ReturnT = S.getContext().classify(Call); - switch (F->getBuiltinID()) { + switch (BuiltinID) { case Builtin::BI__builtin_is_constant_evaluated: if (!interp__builtin_is_constant_evaluated(S, OpPC, Frame, Call)) return false; @@ -1597,6 +1747,16 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, pushInteger(S, 0, Call->getType()); break; + case Builtin::BI__builtin_operator_new: + if (!interp__builtin_operator_new(S, OpPC, Frame, F, Call)) + return false; + break; + + case Builtin::BI__builtin_operator_delete: + if (!interp__builtin_operator_delete(S, OpPC, Frame, F, Call)) + return false; + break; + default: S.FFDiag(S.Current->getLocation(OpPC), diag::note_invalid_subexpr_in_const_expr) diff --git a/clang/lib/AST/ByteCode/InterpFrame.cpp b/clang/lib/AST/ByteCode/InterpFrame.cpp index c75386eaeb4c7e..6830a7b37f1da5 100644 --- a/clang/lib/AST/ByteCode/InterpFrame.cpp +++ b/clang/lib/AST/ByteCode/InterpFrame.cpp @@ -96,11 +96,6 @@ void InterpFrame::destroy(unsigned Idx) { } } -void InterpFrame::popArgs() { - for (PrimType Ty : Func->args_reverse()) - TYPE_SWITCH(Ty, S.Stk.discard()); -} - template static void print(llvm::raw_ostream &OS, const T &V, ASTContext &ASTCtx, QualType Ty) { diff --git a/clang/lib/AST/ByteCode/InterpFrame.h b/clang/lib/AST/ByteCode/InterpFrame.h index 1e0d2b1d4424b1..802777a523d9b3 100644 --- a/clang/lib/AST/ByteCode/InterpFrame.h +++ b/clang/lib/AST/ByteCode/InterpFrame.h @@ -46,9 +46,6 @@ class InterpFrame final : public Frame { void destroy(unsigned Idx); void initScope(unsigned Idx); - /// Pops the arguments off the stack. - void popArgs(); - /// Describes the frame with arguments for diagnostic purposes. void describe(llvm::raw_ostream &OS) const override; diff --git a/clang/lib/AST/ByteCode/InterpStack.cpp b/clang/lib/AST/ByteCode/InterpStack.cpp index b8cdaeee72166c..ae3721e983741d 100644 --- a/clang/lib/AST/ByteCode/InterpStack.cpp +++ b/clang/lib/AST/ByteCode/InterpStack.cpp @@ -32,6 +32,16 @@ void InterpStack::clear() { #endif } +void InterpStack::clearTo(size_t NewSize) { + assert(NewSize <= size()); + size_t ToShrink = size() - NewSize; + if (ToShrink == 0) + return; + + shrink(ToShrink); + assert(size() == NewSize); +} + void *InterpStack::grow(size_t Size) { assert(Size < ChunkSize - sizeof(StackChunk) && "Object too large"); @@ -81,6 +91,21 @@ void InterpStack::shrink(size_t Size) { Chunk->End -= Size; StackSize -= Size; + +#ifndef NDEBUG + size_t TypesSize = 0; + for (PrimType T : ItemTypes) + TYPE_SWITCH(T, { TypesSize += aligned_size(); }); + + size_t StackSize = size(); + while (TypesSize > StackSize) { + TYPE_SWITCH(ItemTypes.back(), { + TypesSize -= aligned_size(); + ItemTypes.pop_back(); + }); + } + assert(TypesSize == StackSize); +#endif } void InterpStack::dump() const { diff --git a/clang/lib/AST/ByteCode/InterpStack.h b/clang/lib/AST/ByteCode/InterpStack.h index 153d17f0d70e1b..43988bb680d1c6 100644 --- a/clang/lib/AST/ByteCode/InterpStack.h +++ b/clang/lib/AST/ByteCode/InterpStack.h @@ -86,6 +86,7 @@ class InterpStack final { /// Clears the stack without calling any destructors. void clear(); + void clearTo(size_t NewSize); /// Returns whether the stack is empty. bool empty() const { return StackSize == 0; } diff --git a/clang/lib/AST/ByteCode/InterpState.h b/clang/lib/AST/ByteCode/InterpState.h index 961ba5f5c28a09..4b7371450cc98e 100644 --- a/clang/lib/AST/ByteCode/InterpState.h +++ b/clang/lib/AST/ByteCode/InterpState.h @@ -68,6 +68,9 @@ class InterpState final : public State, public SourceMapper { bool keepEvaluatingAfterFailure() const override { return Parent.keepEvaluatingAfterFailure(); } + bool keepEvaluatingAfterSideEffect() const override { + return Parent.keepEvaluatingAfterSideEffect(); + } bool checkingPotentialConstantExpression() const override { return Parent.checkingPotentialConstantExpression(); } @@ -83,6 +86,7 @@ class InterpState final : public State, public SourceMapper { Parent.setFoldFailureDiagnostic(Flag); } bool hasPriorDiagnostic() override { return Parent.hasPriorDiagnostic(); } + bool noteSideEffect() override { return Parent.noteSideEffect(); } /// Reports overflow and return true if evaluation should continue. bool reportOverflow(const Expr *E, const llvm::APSInt &Value); diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td index 67350abe5401e1..e3a88c069847b8 100644 --- a/clang/lib/AST/ByteCode/Opcodes.td +++ b/clang/lib/AST/ByteCode/Opcodes.td @@ -202,7 +202,7 @@ def CallVirt : Opcode { } def CallBI : Opcode { - let Args = [ArgFunction, ArgCallExpr]; + let Args = [ArgFunction, ArgCallExpr, ArgUint32]; } def CallPtr : Opcode { @@ -732,6 +732,7 @@ def Flip : Opcode { def Invalid : Opcode {} def Unsupported : Opcode {} def Error : Opcode {} +def SideEffect : Opcode {} def InvalidCast : Opcode { let Args = [ArgCastKind, ArgBool]; } diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h index d05d8e9bc1f388..acbef437752388 100644 --- a/clang/lib/AST/ByteCode/Pointer.h +++ b/clang/lib/AST/ByteCode/Pointer.h @@ -241,9 +241,8 @@ class Pointer { if (asBlockPointer().Base != Offset) return *this; - // If at base, point to an array of base types. if (isRoot()) - return Pointer(Pointee, RootPtrMark, 0); + return Pointer(Pointee, asBlockPointer().Base, asBlockPointer().Base); // Step into the containing array, if inside one. unsigned Next = asBlockPointer().Base - getInlineDesc()->Offset; @@ -711,8 +710,10 @@ class Pointer { /// Returns the embedded descriptor preceding a field. InlineDescriptor *getInlineDesc() const { + assert(isBlockPointer()); assert(asBlockPointer().Base != sizeof(GlobalInlineDescriptor)); assert(asBlockPointer().Base <= asBlockPointer().Pointee->getSize()); + assert(asBlockPointer().Base >= sizeof(InlineDescriptor)); return getDescriptor(asBlockPointer().Base); } diff --git a/clang/lib/AST/ByteCode/State.h b/clang/lib/AST/ByteCode/State.h index 3248e2d8be697f..9a81fa6b7d2204 100644 --- a/clang/lib/AST/ByteCode/State.h +++ b/clang/lib/AST/ByteCode/State.h @@ -62,6 +62,7 @@ class State { virtual bool checkingPotentialConstantExpression() const = 0; virtual bool noteUndefinedBehavior() = 0; virtual bool keepEvaluatingAfterFailure() const = 0; + virtual bool keepEvaluatingAfterSideEffect() const = 0; virtual Frame *getCurrentFrame() = 0; virtual const Frame *getBottomFrame() const = 0; virtual bool hasActiveDiagnostic() = 0; @@ -71,6 +72,7 @@ class State { virtual ASTContext &getASTContext() const = 0; virtual bool hasPriorDiagnostic() = 0; virtual unsigned getCallStackDepth() = 0; + virtual bool noteSideEffect() = 0; public: State() = default; diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 1a07125815832e..a14b1b33d35efc 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -350,7 +350,8 @@ LinkageComputer::getLVForTemplateArgumentList(ArrayRef Args, case TemplateArgument::Template: case TemplateArgument::TemplateExpansion: if (TemplateDecl *Template = - Arg.getAsTemplateOrTemplatePattern().getAsTemplateDecl()) + Arg.getAsTemplateOrTemplatePattern().getAsTemplateDecl( + /*IgnoreDeduced=*/true)) LV.merge(getLVForDecl(Template, computation)); continue; diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 27930db019a172..6545912ed160d9 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -1475,6 +1475,7 @@ CallExpr::CallExpr(StmtClass SC, Expr *Fn, ArrayRef PreArgs, this->computeDependence(); CallExprBits.HasFPFeatures = FPFeatures.requiresTrailingStorage(); + CallExprBits.IsCoroElideSafe = false; if (hasStoredFPFeatures()) setStoredFPFeatures(FPFeatures); } @@ -1490,6 +1491,7 @@ CallExpr::CallExpr(StmtClass SC, unsigned NumPreArgs, unsigned NumArgs, assert((CallExprBits.OffsetToTrailingObjects == OffsetToTrailingObjects) && "OffsetToTrailingObjects overflow!"); CallExprBits.HasFPFeatures = HasFPFeatures; + CallExprBits.IsCoroElideSafe = false; } CallExpr *CallExpr::Create(const ASTContext &Ctx, Expr *Fn, diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 0ad3577d4e1026..78d25006360042 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -1222,7 +1222,7 @@ namespace { public: /// Should we continue evaluation after encountering a side-effect that we /// couldn't model? - bool keepEvaluatingAfterSideEffect() { + bool keepEvaluatingAfterSideEffect() const override { switch (EvalMode) { case EM_IgnoreSideEffects: return true; @@ -1240,7 +1240,7 @@ namespace { /// Note that we have had a side-effect, and determine whether we should /// keep evaluating. - bool noteSideEffect() { + bool noteSideEffect() override { EvalStatus.HasSideEffects = true; return keepEvaluatingAfterSideEffect(); } @@ -16281,7 +16281,7 @@ bool Expr::EvaluateAsConstantExpr(EvalResult &Result, const ASTContext &Ctx, Info.InConstantContext = true; if (Info.EnableNewConstInterp) { - if (!Info.Ctx.getInterpContext().evaluate(Info, this, Result.Val)) + if (!Info.Ctx.getInterpContext().evaluate(Info, this, Result.Val, Kind)) return false; return CheckConstantExpression(Info, getExprLoc(), getStorageType(Ctx, this), Result.Val, Kind); diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 1a47caac5a503c..7d638befcbd3f1 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -2384,6 +2384,8 @@ void CXXNameMangler::mangleType(TemplateName TN) { Out << "_SUBSTPACK_"; break; } + case TemplateName::DeducedTemplate: + llvm_unreachable("Unexpected DeducedTemplate"); } addSubstitution(TN); @@ -2502,6 +2504,7 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty, case TemplateName::OverloadedTemplate: case TemplateName::AssumedTemplate: case TemplateName::DependentTemplate: + case TemplateName::DeducedTemplate: llvm_unreachable("invalid base for a template specialization type"); case TemplateName::SubstTemplateTemplateParm: { @@ -5936,7 +5939,10 @@ struct CXXNameMangler::TemplateArgManglingInfo { // that of the template. auto *TTP = cast(Param); TemplateName ArgTemplateName = Arg.getAsTemplateOrTemplatePattern(); - const TemplateDecl *ArgTemplate = ArgTemplateName.getAsTemplateDecl(); + assert(!ArgTemplateName.getTemplateDeclAndDefaultArgs().second && + "A DeducedTemplateName shouldn't escape partial ordering"); + const TemplateDecl *ArgTemplate = + ArgTemplateName.getAsTemplateDecl(/*IgnoreDeduced=*/true); if (!ArgTemplate) return true; diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp index b748093831e3f5..1929314363817a 100644 --- a/clang/lib/AST/ODRHash.cpp +++ b/clang/lib/AST/ODRHash.cpp @@ -162,6 +162,8 @@ void ODRHash::AddTemplateName(TemplateName Name) { case TemplateName::SubstTemplateTemplateParmPack: case TemplateName::UsingTemplate: break; + case TemplateName::DeducedTemplate: + llvm_unreachable("Unexpected DeducedTemplate"); } } diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp index 7e73c076239410..eb15aa84406901 100644 --- a/clang/lib/AST/OpenMPClause.cpp +++ b/clang/lib/AST/OpenMPClause.cpp @@ -1125,16 +1125,12 @@ unsigned OMPClauseMappableExprCommon::getComponentsTotalNumber( unsigned OMPClauseMappableExprCommon::getUniqueDeclarationsTotalNumber( ArrayRef Declarations) { - unsigned TotalNum = 0u; - llvm::SmallPtrSet Cache; + llvm::SmallPtrSet UniqueDecls; for (const ValueDecl *D : Declarations) { const ValueDecl *VD = D ? cast(D->getCanonicalDecl()) : nullptr; - if (Cache.count(VD)) - continue; - ++TotalNum; - Cache.insert(VD); + UniqueDecls.insert(VD); } - return TotalNum; + return UniqueDecls.size(); } OMPMapClause *OMPMapClause::Create( diff --git a/clang/lib/AST/TemplateName.cpp b/clang/lib/AST/TemplateName.cpp index d4e8a8971a971a..044a1a92469aca 100644 --- a/clang/lib/AST/TemplateName.cpp +++ b/clang/lib/AST/TemplateName.cpp @@ -34,6 +34,30 @@ using namespace clang; +DeducedTemplateStorage::DeducedTemplateStorage(TemplateName Underlying, + const DefaultArguments &DefArgs) + : UncommonTemplateNameStorage(Deduced, /*Index=*/DefArgs.StartPos, + DefArgs.Args.size()), + Underlying(Underlying) { + llvm::copy(DefArgs.Args, reinterpret_cast(this + 1)); +} + +void DeducedTemplateStorage::Profile(llvm::FoldingSetNodeID &ID, + const ASTContext &Context) const { + Profile(ID, Context, Underlying, getDefaultArguments()); +} + +void DeducedTemplateStorage::Profile(llvm::FoldingSetNodeID &ID, + const ASTContext &Context, + TemplateName Underlying, + const DefaultArguments &DefArgs) { + Underlying.Profile(ID); + ID.AddInteger(DefArgs.StartPos); + ID.AddInteger(DefArgs.Args.size()); + for (const TemplateArgument &Arg : DefArgs.Args) + Arg.Profile(ID, Context); +} + TemplateArgument SubstTemplateTemplateParmPackStorage::getArgumentPack() const { return TemplateArgument(llvm::ArrayRef(Arguments, Bits.Data)); @@ -115,6 +139,8 @@ TemplateName::TemplateName(SubstTemplateTemplateParmPackStorage *Storage) TemplateName::TemplateName(QualifiedTemplateName *Qual) : Storage(Qual) {} TemplateName::TemplateName(DependentTemplateName *Dep) : Storage(Dep) {} TemplateName::TemplateName(UsingShadowDecl *Using) : Storage(Using) {} +TemplateName::TemplateName(DeducedTemplateStorage *Deduced) + : Storage(Deduced) {} bool TemplateName::isNull() const { return Storage.isNull(); } @@ -139,28 +165,63 @@ TemplateName::NameKind TemplateName::getKind() const { return AssumedTemplate; if (uncommon->getAsSubstTemplateTemplateParm()) return SubstTemplateTemplateParm; + if (uncommon->getAsDeducedTemplateName()) + return DeducedTemplate; + + assert(uncommon->getAsSubstTemplateTemplateParmPack() != nullptr); return SubstTemplateTemplateParmPack; } -TemplateDecl *TemplateName::getAsTemplateDecl() const { - if (Decl *TemplateOrUsing = Storage.dyn_cast()) { - if (UsingShadowDecl *USD = dyn_cast(TemplateOrUsing)) - return cast(USD->getTargetDecl()); - - assert(isa(TemplateOrUsing)); - return cast(TemplateOrUsing); - } +TemplateDecl *TemplateName::getAsTemplateDecl(bool IgnoreDeduced) const { + TemplateName Name = *this; + while (std::optional UnderlyingOrNone = + Name.desugar(IgnoreDeduced)) + Name = *UnderlyingOrNone; - if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) - return QTN->getUnderlyingTemplate().getAsTemplateDecl(); + if (!IgnoreDeduced) + assert(Name.getAsDeducedTemplateName() == nullptr && + "Unexpected canonical DeducedTemplateName; Did you mean to use " + "getTemplateDeclAndDefaultArgs instead?"); - if (SubstTemplateTemplateParmStorage *sub = getAsSubstTemplateTemplateParm()) - return sub->getReplacement().getAsTemplateDecl(); + return cast_if_present(Name.Storage.dyn_cast()); +} - if (UsingShadowDecl *USD = getAsUsingShadowDecl()) - return cast(USD->getTargetDecl()); +std::pair +TemplateName::getTemplateDeclAndDefaultArgs() const { + for (TemplateName Name = *this; /**/; /**/) { + if (Name.getKind() == TemplateName::DeducedTemplate) { + DeducedTemplateStorage *DTS = Name.getAsDeducedTemplateName(); + TemplateDecl *TD = + DTS->getUnderlying().getAsTemplateDecl(/*IgnoreDeduced=*/true); + DefaultArguments DefArgs = DTS->getDefaultArguments(); + if (TD && DefArgs) + assert(DefArgs.StartPos + DefArgs.Args.size() <= + TD->getTemplateParameters()->size()); + return {TD, DTS->getDefaultArguments()}; + } + if (std::optional UnderlyingOrNone = + Name.desugar(/*IgnoreDeduced=*/false)) { + Name = *UnderlyingOrNone; + continue; + } + return {cast_if_present(Name.Storage.dyn_cast()), {}}; + } +} - return nullptr; +std::optional TemplateName::desugar(bool IgnoreDeduced) const { + if (Decl *D = Storage.dyn_cast()) { + if (auto *USD = dyn_cast(D)) + return TemplateName(USD->getTargetDecl()); + return std::nullopt; + } + if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) + return QTN->getUnderlyingTemplate(); + if (SubstTemplateTemplateParmStorage *S = getAsSubstTemplateTemplateParm()) + return S->getReplacement(); + if (IgnoreDeduced) + if (DeducedTemplateStorage *S = getAsDeducedTemplateName()) + return S->getUnderlying(); + return std::nullopt; } OverloadedTemplateStorage *TemplateName::getAsOverloadedTemplate() const { @@ -214,26 +275,20 @@ UsingShadowDecl *TemplateName::getAsUsingShadowDecl() const { return nullptr; } +DeducedTemplateStorage *TemplateName::getAsDeducedTemplateName() const { + if (UncommonTemplateNameStorage *Uncommon = + Storage.dyn_cast()) + return Uncommon->getAsDeducedTemplateName(); + + return nullptr; +} + TemplateNameDependence TemplateName::getDependence() const { - auto D = TemplateNameDependence::None; switch (getKind()) { - case TemplateName::NameKind::QualifiedTemplate: - if (NestedNameSpecifier *NNS = getAsQualifiedTemplateName()->getQualifier()) - D |= toTemplateNameDependence(NNS->getDependence()); - break; - case TemplateName::NameKind::DependentTemplate: - D |= toTemplateNameDependence( - getAsDependentTemplateName()->getQualifier()->getDependence()); - break; - case TemplateName::NameKind::SubstTemplateTemplateParmPack: - D |= TemplateNameDependence::UnexpandedPack; - break; - case TemplateName::NameKind::OverloadedTemplate: - llvm_unreachable("overloaded templates shouldn't survive to here."); - default: - break; - } - if (TemplateDecl *Template = getAsTemplateDecl()) { + case NameKind::Template: + case NameKind::UsingTemplate: { + TemplateDecl *Template = getAsTemplateDecl(); + auto D = TemplateNameDependence::None; if (auto *TTP = dyn_cast(Template)) { D |= TemplateNameDependence::DependentInstantiation; if (TTP->isParameterPack()) @@ -246,10 +301,41 @@ TemplateNameDependence TemplateName::getDependence() const { if (Template->getDeclContext() && Template->getDeclContext()->isDependentContext()) D |= TemplateNameDependence::DependentInstantiation; - } else { - D |= TemplateNameDependence::DependentInstantiation; + return D; + } + case NameKind::QualifiedTemplate: { + QualifiedTemplateName *S = getAsQualifiedTemplateName(); + TemplateNameDependence D = S->getUnderlyingTemplate().getDependence(); + if (NestedNameSpecifier *NNS = S->getQualifier()) + D |= toTemplateNameDependence(NNS->getDependence()); + return D; + } + case NameKind::DependentTemplate: { + DependentTemplateName *S = getAsDependentTemplateName(); + auto D = TemplateNameDependence::DependentInstantiation; + D |= toTemplateNameDependence(S->getQualifier()->getDependence()); + return D; + } + case NameKind::SubstTemplateTemplateParm: { + auto *S = getAsSubstTemplateTemplateParm(); + return S->getReplacement().getDependence(); + } + case NameKind::SubstTemplateTemplateParmPack: + return TemplateNameDependence::UnexpandedPack | + TemplateNameDependence::DependentInstantiation; + case NameKind::DeducedTemplate: { + DeducedTemplateStorage *DTS = getAsDeducedTemplateName(); + TemplateNameDependence D = DTS->getUnderlying().getDependence(); + for (const TemplateArgument &Arg : DTS->getDefaultArguments().Args) + D |= toTemplateNameDependence(Arg.getDependence()); + return D; + } + case NameKind::AssumedTemplate: + return TemplateNameDependence::DependentInstantiation; + case NameKind::OverloadedTemplate: + llvm_unreachable("overloaded templates shouldn't survive to here."); } - return D; + llvm_unreachable("Unknown TemplateName kind"); } bool TemplateName::isDependent() const { @@ -331,6 +417,11 @@ void TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy, OS << *SubstPack->getParameterPack(); else if (AssumedTemplateStorage *Assumed = getAsAssumedTemplateName()) { Assumed->getDeclName().print(OS, Policy); + } else if (DeducedTemplateStorage *Deduced = getAsDeducedTemplateName()) { + Deduced->getUnderlying().print(OS, Policy); + DefaultArguments DefArgs = Deduced->getDefaultArguments(); + OS << ":" << DefArgs.StartPos; + printTemplateArgumentList(OS, DefArgs.Args, Policy); } else { assert(getKind() == TemplateName::OverloadedTemplate); OverloadedTemplateStorage *OTS = getAsOverloadedTemplate(); diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index c6b1b44206b24d..3c51c746471829 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -1198,6 +1198,18 @@ void TextNodeDumper::dumpBareTemplateName(TemplateName TN) { dumpTemplateName(STS->getReplacement(), "replacement"); return; } + case TemplateName::DeducedTemplate: { + OS << " deduced"; + const DeducedTemplateStorage *DTS = TN.getAsDeducedTemplateName(); + dumpTemplateName(DTS->getUnderlying(), "underlying"); + AddChild("defaults", [=] { + auto [StartPos, Args] = DTS->getDefaultArguments(); + OS << " start " << StartPos; + for (const TemplateArgument &Arg : Args) + AddChild([=] { Visit(Arg, SourceRange()); }); + }); + return; + } // FIXME: Implement these. case TemplateName::OverloadedTemplate: OS << " overloaded"; diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index b976d1a0ee60ae..a55e6c8bf02611 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -4303,7 +4303,8 @@ TemplateSpecializationType::TemplateSpecializationType( T.getKind() == TemplateName::SubstTemplateTemplateParm || T.getKind() == TemplateName::SubstTemplateTemplateParmPack || T.getKind() == TemplateName::UsingTemplate || - T.getKind() == TemplateName::QualifiedTemplate) && + T.getKind() == TemplateName::QualifiedTemplate || + T.getKind() == TemplateName::DeducedTemplate) && "Unexpected template name for TemplateSpecializationType"); auto *TemplateArgs = reinterpret_cast(this + 1); diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index 3bef9370e621ce..add6a5d10d61f7 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -1635,7 +1635,8 @@ void TypePrinter::printTemplateId(const TemplateSpecializationType *T, raw_ostream &OS, bool FullyQualify) { IncludeStrongLifetimeRAII Strong(Policy); - TemplateDecl *TD = T->getTemplateName().getAsTemplateDecl(); + TemplateDecl *TD = + T->getTemplateName().getAsTemplateDecl(/*IgnoreDeduced=*/true); // FIXME: Null TD never exercised in test suite. if (FullyQualify && TD) { if (!Policy.SuppressScope) diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp index b89109e7725d44..6f9d050fc71a90 100644 --- a/clang/lib/Basic/Targets/RISCV.cpp +++ b/clang/lib/Basic/Targets/RISCV.cpp @@ -388,7 +388,7 @@ static void handleFullArchString(StringRef FullArchStr, FullArchStr, /* EnableExperimentalExtension */ true); if (llvm::errorToBool(RII.takeError())) { // Forward the invalid FullArchStr. - Features.push_back("+" + FullArchStr.str()); + Features.push_back(FullArchStr.str()); } else { // Append a full list of features, including any negative extensions so that // we override the CPU's features. @@ -478,3 +478,7 @@ bool RISCVTargetInfo::validateCpuSupports(StringRef Feature) const { // __riscv_feature_bits structure. return -1 != llvm::RISCVISAInfo::getRISCVFeaturesBitsInfo(Feature).second; } + +bool RISCVTargetInfo::isValidFeatureName(StringRef Name) const { + return llvm::RISCVISAInfo::isSupportedExtensionFeature(Name); +} diff --git a/clang/lib/Basic/Targets/RISCV.h b/clang/lib/Basic/Targets/RISCV.h index 626274b8fc437c..b808ccc8e9cfe9 100644 --- a/clang/lib/Basic/Targets/RISCV.h +++ b/clang/lib/Basic/Targets/RISCV.h @@ -130,6 +130,7 @@ class RISCVTargetInfo : public TargetInfo { bool supportsCpuSupports() const override { return getTriple().isOSLinux(); } bool supportsCpuInit() const override { return getTriple().isOSLinux(); } bool validateCpuSupports(StringRef Feature) const override; + bool isValidFeatureName(StringRef Name) const override; }; class LLVM_LIBRARY_VISIBILITY RISCV32TargetInfo : public RISCVTargetInfo { public: diff --git a/clang/lib/Basic/Targets/SystemZ.h b/clang/lib/Basic/Targets/SystemZ.h index 7390f25d6efb1d..f05ea473017bec 100644 --- a/clang/lib/Basic/Targets/SystemZ.h +++ b/clang/lib/Basic/Targets/SystemZ.h @@ -48,7 +48,6 @@ static const unsigned ZOSAddressMap[] = { class LLVM_LIBRARY_VISIBILITY SystemZTargetInfo : public TargetInfo { static const char *const GCCRegNames[]; - std::string CPU; int ISARevision; bool HasTransactionalExecution; bool HasVector; @@ -58,7 +57,7 @@ class LLVM_LIBRARY_VISIBILITY SystemZTargetInfo : public TargetInfo { public: SystemZTargetInfo(const llvm::Triple &Triple, const TargetOptions &) - : TargetInfo(Triple), CPU("z10"), ISARevision(8), + : TargetInfo(Triple), ISARevision(getISARevision("z10")), HasTransactionalExecution(false), HasVector(false), SoftFloat(false), UnalignedSymbols(false) { IntMaxType = SignedLong; @@ -168,8 +167,7 @@ class LLVM_LIBRARY_VISIBILITY SystemZTargetInfo : public TargetInfo { } bool setCPU(const std::string &Name) override { - CPU = Name; - ISARevision = getISARevision(CPU); + ISARevision = getISARevision(Name); return ISARevision != -1; } diff --git a/clang/lib/CodeGen/CGBlocks.cpp b/clang/lib/CodeGen/CGBlocks.cpp index 066139b1c78c7f..684fda74407313 100644 --- a/clang/lib/CodeGen/CGBlocks.cpp +++ b/clang/lib/CodeGen/CGBlocks.cpp @@ -1163,7 +1163,8 @@ llvm::Type *CodeGenModule::getGenericBlockLiteralType() { } RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr *E, - ReturnValueSlot ReturnValue) { + ReturnValueSlot ReturnValue, + llvm::CallBase **CallOrInvoke) { const auto *BPT = E->getCallee()->getType()->castAs(); llvm::Value *BlockPtr = EmitScalarExpr(E->getCallee()); llvm::Type *GenBlockTy = CGM.getGenericBlockLiteralType(); @@ -1220,7 +1221,7 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr *E, CGCallee Callee(CGCalleeInfo(), Func); // And call the block. - return EmitCall(FnInfo, Callee, ReturnValue, Args); + return EmitCall(FnInfo, Callee, ReturnValue, Args, CallOrInvoke); } Address CodeGenFunction::GetAddrOfBlockDecl(const VarDecl *variable) { diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index da7a1a55da5313..0078ceb7e892af 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -6244,8 +6244,20 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, } // EmitHLSLBuiltinExpr will check getLangOpts().HLSL - if (Value *V = EmitHLSLBuiltinExpr(BuiltinID, E)) - return RValue::get(V); + if (Value *V = EmitHLSLBuiltinExpr(BuiltinID, E, ReturnValue)) { + switch (EvalKind) { + case TEK_Scalar: + if (V->getType()->isVoidTy()) + return RValue::get(nullptr); + return RValue::get(V); + case TEK_Aggregate: + return RValue::getAggregate(ReturnValue.getAddress(), + ReturnValue.isVolatile()); + case TEK_Complex: + llvm_unreachable("No current hlsl builtin returns complex"); + } + llvm_unreachable("Bad evaluation kind in EmitBuiltinExpr"); + } if (getLangOpts().HIPStdPar && getLangOpts().CUDAIsDevice) return EmitHipStdParUnsupportedBuiltin(this, FD); @@ -13573,6 +13585,23 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, Int = Intrinsic::aarch64_neon_vluti4q_laneq_x2; return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vluti4q_laneq_x2"); } + + case NEON::BI__builtin_neon_vamin_f16: + case NEON::BI__builtin_neon_vaminq_f16: + case NEON::BI__builtin_neon_vamin_f32: + case NEON::BI__builtin_neon_vaminq_f32: + case NEON::BI__builtin_neon_vaminq_f64: { + Int = Intrinsic::aarch64_neon_famin; + return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "famin"); + } + case NEON::BI__builtin_neon_vamax_f16: + case NEON::BI__builtin_neon_vamaxq_f16: + case NEON::BI__builtin_neon_vamax_f32: + case NEON::BI__builtin_neon_vamaxq_f32: + case NEON::BI__builtin_neon_vamaxq_f64: { + Int = Intrinsic::aarch64_neon_famax; + return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "famax"); + } } } @@ -18623,7 +18652,8 @@ Intrinsic::ID getDotProductIntrinsic(CGHLSLRuntime &RT, QualType QT) { } Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, - const CallExpr *E) { + const CallExpr *E, + ReturnValueSlot ReturnValue) { if (!getLangOpts().HLSL) return nullptr; @@ -18810,6 +18840,27 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: { CGM.getHLSLRuntime().getSaturateIntrinsic(), ArrayRef{Op0}, nullptr, "hlsl.saturate"); } + case Builtin::BI__builtin_hlsl_select: { + Value *OpCond = EmitScalarExpr(E->getArg(0)); + RValue RValTrue = EmitAnyExpr(E->getArg(1)); + Value *OpTrue = + RValTrue.isScalar() + ? RValTrue.getScalarVal() + : RValTrue.getAggregatePointer(E->getArg(1)->getType(), *this); + RValue RValFalse = EmitAnyExpr(E->getArg(2)); + Value *OpFalse = + RValFalse.isScalar() + ? RValFalse.getScalarVal() + : RValFalse.getAggregatePointer(E->getArg(2)->getType(), *this); + + Value *SelectVal = + Builder.CreateSelect(OpCond, OpTrue, OpFalse, "hlsl.select"); + if (!RValTrue.isScalar()) + Builder.CreateStore(SelectVal, ReturnValue.getAddress(), + ReturnValue.isVolatile()); + + return SelectVal; + } case Builtin::BI__builtin_hlsl_wave_get_lane_index: { return EmitRuntimeCall(CGM.CreateRuntimeFunction( llvm::FunctionType::get(IntTy, {}, false), "__hlsl_wave_get_lane_index", diff --git a/clang/lib/CodeGen/CGCUDARuntime.cpp b/clang/lib/CodeGen/CGCUDARuntime.cpp index c14a9d3f2bbbcf..1e1da1e2411a76 100644 --- a/clang/lib/CodeGen/CGCUDARuntime.cpp +++ b/clang/lib/CodeGen/CGCUDARuntime.cpp @@ -25,7 +25,8 @@ CGCUDARuntime::~CGCUDARuntime() {} RValue CGCUDARuntime::EmitCUDAKernelCallExpr(CodeGenFunction &CGF, const CUDAKernelCallExpr *E, - ReturnValueSlot ReturnValue) { + ReturnValueSlot ReturnValue, + llvm::CallBase **CallOrInvoke) { llvm::BasicBlock *ConfigOKBlock = CGF.createBasicBlock("kcall.configok"); llvm::BasicBlock *ContBlock = CGF.createBasicBlock("kcall.end"); @@ -35,7 +36,7 @@ RValue CGCUDARuntime::EmitCUDAKernelCallExpr(CodeGenFunction &CGF, eval.begin(CGF); CGF.EmitBlock(ConfigOKBlock); - CGF.EmitSimpleCallExpr(E, ReturnValue); + CGF.EmitSimpleCallExpr(E, ReturnValue, CallOrInvoke); CGF.EmitBranch(ContBlock); CGF.EmitBlock(ContBlock); diff --git a/clang/lib/CodeGen/CGCUDARuntime.h b/clang/lib/CodeGen/CGCUDARuntime.h index 8030d632cc3d28..86f776004ee7c1 100644 --- a/clang/lib/CodeGen/CGCUDARuntime.h +++ b/clang/lib/CodeGen/CGCUDARuntime.h @@ -21,6 +21,7 @@ #include "llvm/IR/GlobalValue.h" namespace llvm { +class CallBase; class Function; class GlobalVariable; } @@ -82,9 +83,10 @@ class CGCUDARuntime { CGCUDARuntime(CodeGenModule &CGM) : CGM(CGM) {} virtual ~CGCUDARuntime(); - virtual RValue EmitCUDAKernelCallExpr(CodeGenFunction &CGF, - const CUDAKernelCallExpr *E, - ReturnValueSlot ReturnValue); + virtual RValue + EmitCUDAKernelCallExpr(CodeGenFunction &CGF, const CUDAKernelCallExpr *E, + ReturnValueSlot ReturnValue, + llvm::CallBase **CallOrInvoke = nullptr); /// Emits a kernel launch stub. virtual void emitDeviceStub(CodeGenFunction &CGF, FunctionArgList &Args) = 0; diff --git a/clang/lib/CodeGen/CGCXXABI.h b/clang/lib/CodeGen/CGCXXABI.h index 7dcc539111996b..687ff7fb844445 100644 --- a/clang/lib/CodeGen/CGCXXABI.h +++ b/clang/lib/CodeGen/CGCXXABI.h @@ -485,11 +485,11 @@ class CGCXXABI { llvm::PointerUnion; /// Emit the ABI-specific virtual destructor call. - virtual llvm::Value *EmitVirtualDestructorCall(CodeGenFunction &CGF, - const CXXDestructorDecl *Dtor, - CXXDtorType DtorType, - Address This, - DeleteOrMemberCallExpr E) = 0; + virtual llvm::Value * + EmitVirtualDestructorCall(CodeGenFunction &CGF, const CXXDestructorDecl *Dtor, + CXXDtorType DtorType, Address This, + DeleteOrMemberCallExpr E, + llvm::CallBase **CallOrInvoke) = 0; virtual void adjustCallArgsForDestructorThunk(CodeGenFunction &CGF, GlobalDecl GD, diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp index e5ba50de3462da..352955749a6332 100644 --- a/clang/lib/CodeGen/CGClass.cpp +++ b/clang/lib/CodeGen/CGClass.cpp @@ -2192,15 +2192,11 @@ static bool canEmitDelegateCallArgs(CodeGenFunction &CGF, return true; } -void CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D, - CXXCtorType Type, - bool ForVirtualBase, - bool Delegating, - Address This, - CallArgList &Args, - AggValueSlot::Overlap_t Overlap, - SourceLocation Loc, - bool NewPointerIsChecked) { +void CodeGenFunction::EmitCXXConstructorCall( + const CXXConstructorDecl *D, CXXCtorType Type, bool ForVirtualBase, + bool Delegating, Address This, CallArgList &Args, + AggValueSlot::Overlap_t Overlap, SourceLocation Loc, + bool NewPointerIsChecked, llvm::CallBase **CallOrInvoke) { const CXXRecordDecl *ClassDecl = D->getParent(); if (!NewPointerIsChecked) @@ -2248,7 +2244,7 @@ void CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D, const CGFunctionInfo &Info = CGM.getTypes().arrangeCXXConstructorCall( Args, D, Type, ExtraArgs.Prefix, ExtraArgs.Suffix, PassPrototypeArgs); CGCallee Callee = CGCallee::forDirect(CalleePtr, GlobalDecl(D, Type)); - EmitCall(Info, Callee, ReturnValueSlot(), Args, nullptr, false, Loc); + EmitCall(Info, Callee, ReturnValueSlot(), Args, CallOrInvoke, false, Loc); // Generate vtable assumptions if we're constructing a complete object // with a vtable. We don't do this for base subobjects for two reasons: diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 99cd61b9e78953..35b5daaf6d4b55 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -33,6 +33,7 @@ #include "clang/Basic/SourceManager.h" #include "llvm/ADT/Hashing.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/StringExtras.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Intrinsics.h" @@ -5544,16 +5545,30 @@ RValue CodeGenFunction::EmitRValueForField(LValue LV, //===--------------------------------------------------------------------===// RValue CodeGenFunction::EmitCallExpr(const CallExpr *E, - ReturnValueSlot ReturnValue) { + ReturnValueSlot ReturnValue, + llvm::CallBase **CallOrInvoke) { + llvm::CallBase *CallOrInvokeStorage; + if (!CallOrInvoke) { + CallOrInvoke = &CallOrInvokeStorage; + } + + auto AddCoroElideSafeOnExit = llvm::make_scope_exit([&] { + if (E->isCoroElideSafe()) { + auto *I = *CallOrInvoke; + if (I) + I->addFnAttr(llvm::Attribute::CoroElideSafe); + } + }); + // Builtins never have block type. if (E->getCallee()->getType()->isBlockPointerType()) - return EmitBlockCallExpr(E, ReturnValue); + return EmitBlockCallExpr(E, ReturnValue, CallOrInvoke); if (const auto *CE = dyn_cast(E)) - return EmitCXXMemberCallExpr(CE, ReturnValue); + return EmitCXXMemberCallExpr(CE, ReturnValue, CallOrInvoke); if (const auto *CE = dyn_cast(E)) - return EmitCUDAKernelCallExpr(CE, ReturnValue); + return EmitCUDAKernelCallExpr(CE, ReturnValue, CallOrInvoke); // A CXXOperatorCallExpr is created even for explicit object methods, but // these should be treated like static function call. @@ -5561,7 +5576,7 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E, if (const auto *MD = dyn_cast_if_present(CE->getCalleeDecl()); MD && MD->isImplicitObjectMemberFunction()) - return EmitCXXOperatorMemberCallExpr(CE, MD, ReturnValue); + return EmitCXXOperatorMemberCallExpr(CE, MD, ReturnValue, CallOrInvoke); CGCallee callee = EmitCallee(E->getCallee()); @@ -5574,14 +5589,17 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E, return EmitCXXPseudoDestructorExpr(callee.getPseudoDestructorExpr()); } - return EmitCall(E->getCallee()->getType(), callee, E, ReturnValue); + return EmitCall(E->getCallee()->getType(), callee, E, ReturnValue, + /*Chain=*/nullptr, CallOrInvoke); } /// Emit a CallExpr without considering whether it might be a subclass. RValue CodeGenFunction::EmitSimpleCallExpr(const CallExpr *E, - ReturnValueSlot ReturnValue) { + ReturnValueSlot ReturnValue, + llvm::CallBase **CallOrInvoke) { CGCallee Callee = EmitCallee(E->getCallee()); - return EmitCall(E->getCallee()->getType(), Callee, E, ReturnValue); + return EmitCall(E->getCallee()->getType(), Callee, E, ReturnValue, + /*Chain=*/nullptr, CallOrInvoke); } // Detect the unusual situation where an inline version is shadowed by a @@ -5785,8 +5803,9 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) { llvm_unreachable("bad evaluation kind"); } -LValue CodeGenFunction::EmitCallExprLValue(const CallExpr *E) { - RValue RV = EmitCallExpr(E); +LValue CodeGenFunction::EmitCallExprLValue(const CallExpr *E, + llvm::CallBase **CallOrInvoke) { + RValue RV = EmitCallExpr(E, ReturnValueSlot(), CallOrInvoke); if (!RV.isScalar()) return MakeAddrLValue(RV.getAggregateAddress(), E->getType(), @@ -5909,9 +5928,11 @@ LValue CodeGenFunction::EmitStmtExprLValue(const StmtExpr *E) { AlignmentSource::Decl); } -RValue CodeGenFunction::EmitCall(QualType CalleeType, const CGCallee &OrigCallee, - const CallExpr *E, ReturnValueSlot ReturnValue, - llvm::Value *Chain) { +RValue CodeGenFunction::EmitCall(QualType CalleeType, + const CGCallee &OrigCallee, const CallExpr *E, + ReturnValueSlot ReturnValue, + llvm::Value *Chain, + llvm::CallBase **CallOrInvoke) { // Get the actual function type. The callee type will always be a pointer to // function type or a block pointer type. assert(CalleeType->isFunctionPointerType() && @@ -6131,8 +6152,8 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, const CGCallee &OrigCallee Address(Handle, Handle->getType(), CGM.getPointerAlign())); Callee.setFunctionPointer(Stub); } - llvm::CallBase *CallOrInvoke = nullptr; - RValue Call = EmitCall(FnInfo, Callee, ReturnValue, Args, &CallOrInvoke, + llvm::CallBase *LocalCallOrInvoke = nullptr; + RValue Call = EmitCall(FnInfo, Callee, ReturnValue, Args, &LocalCallOrInvoke, E == MustTailCall, E->getExprLoc()); // Generate function declaration DISuprogram in order to be used @@ -6141,11 +6162,13 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, const CGCallee &OrigCallee if (auto *CalleeDecl = dyn_cast_or_null(TargetDecl)) { FunctionArgList Args; QualType ResTy = BuildFunctionArgList(CalleeDecl, Args); - DI->EmitFuncDeclForCallSite(CallOrInvoke, + DI->EmitFuncDeclForCallSite(LocalCallOrInvoke, DI->getFunctionType(CalleeDecl, ResTy, Args), CalleeDecl); } } + if (CallOrInvoke) + *CallOrInvoke = LocalCallOrInvoke; return Call; } diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp index 8eb6ab7381acbc..1214bb054fb8df 100644 --- a/clang/lib/CodeGen/CGExprCXX.cpp +++ b/clang/lib/CodeGen/CGExprCXX.cpp @@ -84,23 +84,24 @@ commonEmitCXXMemberOrOperatorCall(CodeGenFunction &CGF, GlobalDecl GD, RValue CodeGenFunction::EmitCXXMemberOrOperatorCall( const CXXMethodDecl *MD, const CGCallee &Callee, - ReturnValueSlot ReturnValue, - llvm::Value *This, llvm::Value *ImplicitParam, QualType ImplicitParamTy, - const CallExpr *CE, CallArgList *RtlArgs) { + ReturnValueSlot ReturnValue, llvm::Value *This, llvm::Value *ImplicitParam, + QualType ImplicitParamTy, const CallExpr *CE, CallArgList *RtlArgs, + llvm::CallBase **CallOrInvoke) { const FunctionProtoType *FPT = MD->getType()->castAs(); CallArgList Args; MemberCallInfo CallInfo = commonEmitCXXMemberOrOperatorCall( *this, MD, This, ImplicitParam, ImplicitParamTy, CE, Args, RtlArgs); auto &FnInfo = CGM.getTypes().arrangeCXXMethodCall( Args, FPT, CallInfo.ReqArgs, CallInfo.PrefixSize); - return EmitCall(FnInfo, Callee, ReturnValue, Args, nullptr, + return EmitCall(FnInfo, Callee, ReturnValue, Args, CallOrInvoke, CE && CE == MustTailCall, CE ? CE->getExprLoc() : SourceLocation()); } RValue CodeGenFunction::EmitCXXDestructorCall( GlobalDecl Dtor, const CGCallee &Callee, llvm::Value *This, QualType ThisTy, - llvm::Value *ImplicitParam, QualType ImplicitParamTy, const CallExpr *CE) { + llvm::Value *ImplicitParam, QualType ImplicitParamTy, const CallExpr *CE, + llvm::CallBase **CallOrInvoke) { const CXXMethodDecl *DtorDecl = cast(Dtor.getDecl()); assert(!ThisTy.isNull()); @@ -120,7 +121,8 @@ RValue CodeGenFunction::EmitCXXDestructorCall( commonEmitCXXMemberOrOperatorCall(*this, Dtor, This, ImplicitParam, ImplicitParamTy, CE, Args, nullptr); return EmitCall(CGM.getTypes().arrangeCXXStructorDeclaration(Dtor), Callee, - ReturnValueSlot(), Args, nullptr, CE && CE == MustTailCall, + ReturnValueSlot(), Args, CallOrInvoke, + CE && CE == MustTailCall, CE ? CE->getExprLoc() : SourceLocation{}); } @@ -186,11 +188,12 @@ static CXXRecordDecl *getCXXRecord(const Expr *E) { // Note: This function also emit constructor calls to support a MSVC // extensions allowing explicit constructor function call. RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE, - ReturnValueSlot ReturnValue) { + ReturnValueSlot ReturnValue, + llvm::CallBase **CallOrInvoke) { const Expr *callee = CE->getCallee()->IgnoreParens(); if (isa(callee)) - return EmitCXXMemberPointerCallExpr(CE, ReturnValue); + return EmitCXXMemberPointerCallExpr(CE, ReturnValue, CallOrInvoke); const MemberExpr *ME = cast(callee); const CXXMethodDecl *MD = cast(ME->getMemberDecl()); @@ -200,7 +203,7 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE, CGCallee callee = CGCallee::forDirect(CGM.GetAddrOfFunction(MD), GlobalDecl(MD)); return EmitCall(getContext().getPointerType(MD->getType()), callee, CE, - ReturnValue); + ReturnValue, /*Chain=*/nullptr, CallOrInvoke); } bool HasQualifier = ME->hasQualifier(); @@ -208,14 +211,15 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE, bool IsArrow = ME->isArrow(); const Expr *Base = ME->getBase(); - return EmitCXXMemberOrOperatorMemberCallExpr( - CE, MD, ReturnValue, HasQualifier, Qualifier, IsArrow, Base); + return EmitCXXMemberOrOperatorMemberCallExpr(CE, MD, ReturnValue, + HasQualifier, Qualifier, IsArrow, + Base, CallOrInvoke); } RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr( const CallExpr *CE, const CXXMethodDecl *MD, ReturnValueSlot ReturnValue, bool HasQualifier, NestedNameSpecifier *Qualifier, bool IsArrow, - const Expr *Base) { + const Expr *Base, llvm::CallBase **CallOrInvoke) { assert(isa(CE) || isa(CE)); // Compute the object pointer. @@ -300,7 +304,7 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr( EmitCXXConstructorCall(Ctor, Ctor_Complete, /*ForVirtualBase=*/false, /*Delegating=*/false, This.getAddress(), Args, AggValueSlot::DoesNotOverlap, CE->getExprLoc(), - /*NewPointerIsChecked=*/false); + /*NewPointerIsChecked=*/false, CallOrInvoke); return RValue::get(nullptr); } @@ -374,9 +378,9 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr( "Destructor shouldn't have explicit parameters"); assert(ReturnValue.isNull() && "Destructor shouldn't have return value"); if (UseVirtualCall) { - CGM.getCXXABI().EmitVirtualDestructorCall(*this, Dtor, Dtor_Complete, - This.getAddress(), - cast(CE)); + CGM.getCXXABI().EmitVirtualDestructorCall( + *this, Dtor, Dtor_Complete, This.getAddress(), + cast(CE), CallOrInvoke); } else { GlobalDecl GD(Dtor, Dtor_Complete); CGCallee Callee; @@ -393,7 +397,7 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr( IsArrow ? Base->getType()->getPointeeType() : Base->getType(); EmitCXXDestructorCall(GD, Callee, This.getPointer(*this), ThisTy, /*ImplicitParam=*/nullptr, - /*ImplicitParamTy=*/QualType(), CE); + /*ImplicitParamTy=*/QualType(), CE, CallOrInvoke); } return RValue::get(nullptr); } @@ -435,12 +439,13 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr( return EmitCXXMemberOrOperatorCall( CalleeDecl, Callee, ReturnValue, This.getPointer(*this), - /*ImplicitParam=*/nullptr, QualType(), CE, RtlArgs); + /*ImplicitParam=*/nullptr, QualType(), CE, RtlArgs, CallOrInvoke); } RValue CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E, - ReturnValueSlot ReturnValue) { + ReturnValueSlot ReturnValue, + llvm::CallBase **CallOrInvoke) { const BinaryOperator *BO = cast(E->getCallee()->IgnoreParens()); const Expr *BaseExpr = BO->getLHS(); @@ -484,24 +489,25 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E, EmitCallArgs(Args, FPT, E->arguments()); return EmitCall(CGM.getTypes().arrangeCXXMethodCall(Args, FPT, required, /*PrefixSize=*/0), - Callee, ReturnValue, Args, nullptr, E == MustTailCall, + Callee, ReturnValue, Args, CallOrInvoke, E == MustTailCall, E->getExprLoc()); } -RValue -CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E, - const CXXMethodDecl *MD, - ReturnValueSlot ReturnValue) { +RValue CodeGenFunction::EmitCXXOperatorMemberCallExpr( + const CXXOperatorCallExpr *E, const CXXMethodDecl *MD, + ReturnValueSlot ReturnValue, llvm::CallBase **CallOrInvoke) { assert(MD->isImplicitObjectMemberFunction() && "Trying to emit a member call expr on a static method!"); return EmitCXXMemberOrOperatorMemberCallExpr( E, MD, ReturnValue, /*HasQualifier=*/false, /*Qualifier=*/nullptr, - /*IsArrow=*/false, E->getArg(0)); + /*IsArrow=*/false, E->getArg(0), CallOrInvoke); } RValue CodeGenFunction::EmitCUDAKernelCallExpr(const CUDAKernelCallExpr *E, - ReturnValueSlot ReturnValue) { - return CGM.getCUDARuntime().EmitCUDAKernelCallExpr(*this, E, ReturnValue); + ReturnValueSlot ReturnValue, + llvm::CallBase **CallOrInvoke) { + return CGM.getCUDARuntime().EmitCUDAKernelCallExpr(*this, E, ReturnValue, + CallOrInvoke); } static void EmitNullBaseClassInitialization(CodeGenFunction &CGF, diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 368fc112187ffc..4eca770ca35d85 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -1143,17 +1143,11 @@ class CodeGenFunction : public CodeGenTypeCache { /// Copy all the entries in the source map over the corresponding /// entries in the destination, which must exist. static void copyInto(const DeclMapTy &Src, DeclMapTy &Dest) { - for (auto &Pair : Src) { - if (!Pair.second.isValid()) { - Dest.erase(Pair.first); - continue; - } - - auto I = Dest.find(Pair.first); - if (I != Dest.end()) - I->second = Pair.second; + for (auto &[Decl, Addr] : Src) { + if (!Addr.isValid()) + Dest.erase(Decl); else - Dest.insert(Pair); + Dest.insert_or_assign(Decl, Addr); } } }; @@ -3155,7 +3149,8 @@ class CodeGenFunction : public CodeGenTypeCache { bool ForVirtualBase, bool Delegating, Address This, CallArgList &Args, AggValueSlot::Overlap_t Overlap, - SourceLocation Loc, bool NewPointerIsChecked); + SourceLocation Loc, bool NewPointerIsChecked, + llvm::CallBase **CallOrInvoke = nullptr); /// Emit assumption load for all bases. Requires to be called only on /// most-derived class and not under construction of the object. @@ -4275,7 +4270,8 @@ class CodeGenFunction : public CodeGenTypeCache { LValue EmitBinaryOperatorLValue(const BinaryOperator *E); LValue EmitCompoundAssignmentLValue(const CompoundAssignOperator *E); // Note: only available for agg return types - LValue EmitCallExprLValue(const CallExpr *E); + LValue EmitCallExprLValue(const CallExpr *E, + llvm::CallBase **CallOrInvoke = nullptr); // Note: only available for agg return types LValue EmitVAArgExprLValue(const VAArgExpr *E); LValue EmitDeclRefLValue(const DeclRefExpr *E); @@ -4388,21 +4384,27 @@ class CodeGenFunction : public CodeGenTypeCache { /// LLVM arguments and the types they were derived from. RValue EmitCall(const CGFunctionInfo &CallInfo, const CGCallee &Callee, ReturnValueSlot ReturnValue, const CallArgList &Args, - llvm::CallBase **callOrInvoke, bool IsMustTail, + llvm::CallBase **CallOrInvoke, bool IsMustTail, SourceLocation Loc, bool IsVirtualFunctionPointerThunk = false); RValue EmitCall(const CGFunctionInfo &CallInfo, const CGCallee &Callee, ReturnValueSlot ReturnValue, const CallArgList &Args, - llvm::CallBase **callOrInvoke = nullptr, + llvm::CallBase **CallOrInvoke = nullptr, bool IsMustTail = false) { - return EmitCall(CallInfo, Callee, ReturnValue, Args, callOrInvoke, + return EmitCall(CallInfo, Callee, ReturnValue, Args, CallOrInvoke, IsMustTail, SourceLocation()); } RValue EmitCall(QualType FnType, const CGCallee &Callee, const CallExpr *E, - ReturnValueSlot ReturnValue, llvm::Value *Chain = nullptr); + ReturnValueSlot ReturnValue, llvm::Value *Chain = nullptr, + llvm::CallBase **CallOrInvoke = nullptr); + + // If a Call or Invoke instruction was emitted for this CallExpr, this method + // writes the pointer to `CallOrInvoke` if it's not null. RValue EmitCallExpr(const CallExpr *E, - ReturnValueSlot ReturnValue = ReturnValueSlot()); - RValue EmitSimpleCallExpr(const CallExpr *E, ReturnValueSlot ReturnValue); + ReturnValueSlot ReturnValue = ReturnValueSlot(), + llvm::CallBase **CallOrInvoke = nullptr); + RValue EmitSimpleCallExpr(const CallExpr *E, ReturnValueSlot ReturnValue, + llvm::CallBase **CallOrInvoke = nullptr); CGCallee EmitCallee(const Expr *E); void checkTargetFeatures(const CallExpr *E, const FunctionDecl *TargetDecl); @@ -4506,25 +4508,23 @@ class CodeGenFunction : public CodeGenTypeCache { void callCStructCopyAssignmentOperator(LValue Dst, LValue Src); void callCStructMoveAssignmentOperator(LValue Dst, LValue Src); - RValue - EmitCXXMemberOrOperatorCall(const CXXMethodDecl *Method, - const CGCallee &Callee, - ReturnValueSlot ReturnValue, llvm::Value *This, - llvm::Value *ImplicitParam, - QualType ImplicitParamTy, const CallExpr *E, - CallArgList *RtlArgs); + RValue EmitCXXMemberOrOperatorCall( + const CXXMethodDecl *Method, const CGCallee &Callee, + ReturnValueSlot ReturnValue, llvm::Value *This, + llvm::Value *ImplicitParam, QualType ImplicitParamTy, const CallExpr *E, + CallArgList *RtlArgs, llvm::CallBase **CallOrInvoke); RValue EmitCXXDestructorCall(GlobalDecl Dtor, const CGCallee &Callee, llvm::Value *This, QualType ThisTy, llvm::Value *ImplicitParam, - QualType ImplicitParamTy, const CallExpr *E); + QualType ImplicitParamTy, const CallExpr *E, + llvm::CallBase **CallOrInvoke = nullptr); RValue EmitCXXMemberCallExpr(const CXXMemberCallExpr *E, - ReturnValueSlot ReturnValue); - RValue EmitCXXMemberOrOperatorMemberCallExpr(const CallExpr *CE, - const CXXMethodDecl *MD, - ReturnValueSlot ReturnValue, - bool HasQualifier, - NestedNameSpecifier *Qualifier, - bool IsArrow, const Expr *Base); + ReturnValueSlot ReturnValue, + llvm::CallBase **CallOrInvoke = nullptr); + RValue EmitCXXMemberOrOperatorMemberCallExpr( + const CallExpr *CE, const CXXMethodDecl *MD, ReturnValueSlot ReturnValue, + bool HasQualifier, NestedNameSpecifier *Qualifier, bool IsArrow, + const Expr *Base, llvm::CallBase **CallOrInvoke); // Compute the object pointer. Address EmitCXXMemberDataPointerAddress(const Expr *E, Address base, llvm::Value *memberPtr, @@ -4532,15 +4532,18 @@ class CodeGenFunction : public CodeGenTypeCache { LValueBaseInfo *BaseInfo = nullptr, TBAAAccessInfo *TBAAInfo = nullptr); RValue EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E, - ReturnValueSlot ReturnValue); + ReturnValueSlot ReturnValue, + llvm::CallBase **CallOrInvoke); RValue EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E, const CXXMethodDecl *MD, - ReturnValueSlot ReturnValue); + ReturnValueSlot ReturnValue, + llvm::CallBase **CallOrInvoke); RValue EmitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *E); RValue EmitCUDAKernelCallExpr(const CUDAKernelCallExpr *E, - ReturnValueSlot ReturnValue); + ReturnValueSlot ReturnValue, + llvm::CallBase **CallOrInvoke); RValue EmitNVPTXDevicePrintfCallExpr(const CallExpr *E); RValue EmitAMDGPUDevicePrintfCallExpr(const CallExpr *E); @@ -4562,7 +4565,8 @@ class CodeGenFunction : public CodeGenTypeCache { const analyze_os_log::OSLogBufferLayout &Layout, CharUnits BufferAlignment); - RValue EmitBlockCallExpr(const CallExpr *E, ReturnValueSlot ReturnValue); + RValue EmitBlockCallExpr(const CallExpr *E, ReturnValueSlot ReturnValue, + llvm::CallBase **CallOrInvoke); /// EmitTargetBuiltinExpr - Emit the given builtin call. Returns 0 if the call /// is unhandled by the current target. @@ -4700,7 +4704,8 @@ class CodeGenFunction : public CodeGenTypeCache { llvm::Value *EmitX86BuiltinExpr(unsigned BuiltinID, const CallExpr *E); llvm::Value *EmitPPCBuiltinExpr(unsigned BuiltinID, const CallExpr *E); llvm::Value *EmitAMDGPUBuiltinExpr(unsigned BuiltinID, const CallExpr *E); - llvm::Value *EmitHLSLBuiltinExpr(unsigned BuiltinID, const CallExpr *E); + llvm::Value *EmitHLSLBuiltinExpr(unsigned BuiltinID, const CallExpr *E, + ReturnValueSlot ReturnValue); llvm::Value *EmitScalarOrConstFoldImmArg(unsigned ICEArguments, unsigned Idx, const CallExpr *E); llvm::Value *EmitSystemZBuiltinExpr(unsigned BuiltinID, const CallExpr *E); diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp index 67a9caf8b4ec4b..07015834bc84f3 100644 --- a/clang/lib/CodeGen/CoverageMappingGen.cpp +++ b/clang/lib/CodeGen/CoverageMappingGen.cpp @@ -2595,12 +2595,7 @@ void CoverageMappingModuleGen::emit() { } unsigned CoverageMappingModuleGen::getFileID(FileEntryRef File) { - auto It = FileEntries.find(File); - if (It != FileEntries.end()) - return It->second; - unsigned FileID = FileEntries.size() + 1; - FileEntries.insert(std::make_pair(File, FileID)); - return FileID; + return FileEntries.try_emplace(File, FileEntries.size() + 1).first->second; } void CoverageMappingGen::emitCounterMapping(const Decl *D, diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index fb1eb72d9f3404..dcc35d5689831e 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -315,10 +315,11 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI { Address This, llvm::Type *Ty, SourceLocation Loc) override; - llvm::Value *EmitVirtualDestructorCall(CodeGenFunction &CGF, - const CXXDestructorDecl *Dtor, - CXXDtorType DtorType, Address This, - DeleteOrMemberCallExpr E) override; + llvm::Value * + EmitVirtualDestructorCall(CodeGenFunction &CGF, const CXXDestructorDecl *Dtor, + CXXDtorType DtorType, Address This, + DeleteOrMemberCallExpr E, + llvm::CallBase **CallOrInvoke) override; void emitVirtualInheritanceTables(const CXXRecordDecl *RD) override; @@ -1399,7 +1400,8 @@ void ItaniumCXXABI::emitVirtualObjectDelete(CodeGenFunction &CGF, // FIXME: Provide a source location here even though there's no // CXXMemberCallExpr for dtor call. CXXDtorType DtorType = UseGlobalDelete ? Dtor_Complete : Dtor_Deleting; - EmitVirtualDestructorCall(CGF, Dtor, DtorType, Ptr, DE); + EmitVirtualDestructorCall(CGF, Dtor, DtorType, Ptr, DE, + /*CallOrInvoke=*/nullptr); if (UseGlobalDelete) CGF.PopCleanupBlock(); @@ -2236,7 +2238,7 @@ CGCallee ItaniumCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF, llvm::Value *ItaniumCXXABI::EmitVirtualDestructorCall( CodeGenFunction &CGF, const CXXDestructorDecl *Dtor, CXXDtorType DtorType, - Address This, DeleteOrMemberCallExpr E) { + Address This, DeleteOrMemberCallExpr E, llvm::CallBase **CallOrInvoke) { auto *CE = E.dyn_cast(); auto *D = E.dyn_cast(); assert((CE != nullptr) ^ (D != nullptr)); @@ -2257,7 +2259,7 @@ llvm::Value *ItaniumCXXABI::EmitVirtualDestructorCall( } CGF.EmitCXXDestructorCall(GD, Callee, This.emitRawPointer(CGF), ThisTy, - nullptr, QualType(), nullptr); + nullptr, QualType(), nullptr, CallOrInvoke); return nullptr; } diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp index 76d0191a7e63ad..79dcdc04b0996f 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -334,10 +334,11 @@ class MicrosoftCXXABI : public CGCXXABI { Address This, llvm::Type *Ty, SourceLocation Loc) override; - llvm::Value *EmitVirtualDestructorCall(CodeGenFunction &CGF, - const CXXDestructorDecl *Dtor, - CXXDtorType DtorType, Address This, - DeleteOrMemberCallExpr E) override; + llvm::Value * + EmitVirtualDestructorCall(CodeGenFunction &CGF, const CXXDestructorDecl *Dtor, + CXXDtorType DtorType, Address This, + DeleteOrMemberCallExpr E, + llvm::CallBase **CallOrInvoke) override; void adjustCallArgsForDestructorThunk(CodeGenFunction &CGF, GlobalDecl GD, CallArgList &CallArgs) override { @@ -901,7 +902,8 @@ void MicrosoftCXXABI::emitVirtualObjectDelete(CodeGenFunction &CGF, // CXXMemberCallExpr for dtor call. bool UseGlobalDelete = DE->isGlobalDelete(); CXXDtorType DtorType = UseGlobalDelete ? Dtor_Complete : Dtor_Deleting; - llvm::Value *MDThis = EmitVirtualDestructorCall(CGF, Dtor, DtorType, Ptr, DE); + llvm::Value *MDThis = EmitVirtualDestructorCall(CGF, Dtor, DtorType, Ptr, DE, + /*CallOrInvoke=*/nullptr); if (UseGlobalDelete) CGF.EmitDeleteCall(DE->getOperatorDelete(), MDThis, ElementType); } @@ -1685,7 +1687,7 @@ void MicrosoftCXXABI::EmitDestructorCall(CodeGenFunction &CGF, CGF.EmitCXXDestructorCall(GD, Callee, CGF.getAsNaturalPointerTo(This, ThisTy), ThisTy, /*ImplicitParam=*/Implicit, - /*ImplicitParamTy=*/QualType(), nullptr); + /*ImplicitParamTy=*/QualType(), /*E=*/nullptr); if (BaseDtorEndBB) { // Complete object handler should continue to be the remaining CGF.Builder.CreateBr(BaseDtorEndBB); @@ -2001,7 +2003,7 @@ CGCallee MicrosoftCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF, llvm::Value *MicrosoftCXXABI::EmitVirtualDestructorCall( CodeGenFunction &CGF, const CXXDestructorDecl *Dtor, CXXDtorType DtorType, - Address This, DeleteOrMemberCallExpr E) { + Address This, DeleteOrMemberCallExpr E, llvm::CallBase **CallOrInvoke) { auto *CE = E.dyn_cast(); auto *D = E.dyn_cast(); assert((CE != nullptr) ^ (D != nullptr)); @@ -2031,7 +2033,7 @@ llvm::Value *MicrosoftCXXABI::EmitVirtualDestructorCall( This = adjustThisArgumentForVirtualFunctionCall(CGF, GD, This, true); RValue RV = CGF.EmitCXXDestructorCall(GD, Callee, This.emitRawPointer(CGF), ThisTy, - ImplicitParam, Context.IntTy, CE); + ImplicitParam, Context.IntTy, CE, CallOrInvoke); return RV.getScalarVal(); } diff --git a/clang/lib/CodeGen/Targets/AArch64.cpp b/clang/lib/CodeGen/Targets/AArch64.cpp index 97381f673c2849..2f119feb93aaf3 100644 --- a/clang/lib/CodeGen/Targets/AArch64.cpp +++ b/clang/lib/CodeGen/Targets/AArch64.cpp @@ -304,7 +304,7 @@ AArch64ABIInfo::classifyArgumentType(QualType Ty, bool IsVariadic, return getNaturalAlignIndirect(Ty, false); return (isPromotableIntegerTypeForABI(Ty) && isDarwinPCS() - ? ABIArgInfo::getExtend(Ty) + ? ABIArgInfo::getExtend(Ty, CGT.ConvertType(Ty)) : ABIArgInfo::getDirect()); } diff --git a/clang/lib/CodeGen/Targets/ARM.cpp b/clang/lib/CodeGen/Targets/ARM.cpp index d032b88d7683cd..f7d7471d386b21 100644 --- a/clang/lib/CodeGen/Targets/ARM.cpp +++ b/clang/lib/CodeGen/Targets/ARM.cpp @@ -354,8 +354,9 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, bool isVariadic, if (EIT->getNumBits() > 64) return getNaturalAlignIndirect(Ty, /*ByVal=*/true); - return (isPromotableIntegerTypeForABI(Ty) ? ABIArgInfo::getExtend(Ty) - : ABIArgInfo::getDirect()); + return (isPromotableIntegerTypeForABI(Ty) + ? ABIArgInfo::getExtend(Ty, CGT.ConvertType(Ty)) + : ABIArgInfo::getDirect()); } if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) { diff --git a/clang/lib/CodeGen/Targets/RISCV.cpp b/clang/lib/CodeGen/Targets/RISCV.cpp index 826a1ec2c9d386..57b09f1a3d7632 100644 --- a/clang/lib/CodeGen/Targets/RISCV.cpp +++ b/clang/lib/CodeGen/Targets/RISCV.cpp @@ -51,7 +51,7 @@ class RISCVABIInfo : public DefaultABIInfo { RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty, AggValueSlot Slot) const override; - ABIArgInfo extendType(QualType Ty) const; + ABIArgInfo extendType(QualType Ty, llvm::Type *CoerceTy = nullptr) const; bool detectFPCCEligibleStruct(QualType Ty, llvm::Type *&Field1Ty, CharUnits &Field1Off, llvm::Type *&Field2Ty, @@ -439,12 +439,12 @@ ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed, // All integral types are promoted to XLen width if (Size < XLen && Ty->isIntegralOrEnumerationType()) { - return extendType(Ty); + return extendType(Ty, CGT.ConvertType(Ty)); } if (const auto *EIT = Ty->getAs()) { if (EIT->getNumBits() < XLen) - return extendType(Ty); + return extendType(Ty, CGT.ConvertType(Ty)); if (EIT->getNumBits() > 128 || (!getContext().getTargetInfo().hasInt128Type() && EIT->getNumBits() > 64)) @@ -526,12 +526,12 @@ RValue RISCVABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, /*AllowHigherAlign=*/true, Slot); } -ABIArgInfo RISCVABIInfo::extendType(QualType Ty) const { +ABIArgInfo RISCVABIInfo::extendType(QualType Ty, llvm::Type *CoerceTy) const { int TySize = getContext().getTypeSize(Ty); // RV64 ABI requires unsigned 32 bit integers to be sign extended. if (XLen == 64 && Ty->isUnsignedIntegerOrEnumerationType() && TySize == 32) - return ABIArgInfo::getSignExtend(Ty); - return ABIArgInfo::getExtend(Ty); + return ABIArgInfo::getSignExtend(Ty, CoerceTy); + return ABIArgInfo::getExtend(Ty, CoerceTy); } namespace { diff --git a/clang/lib/CodeGen/Targets/X86.cpp b/clang/lib/CodeGen/Targets/X86.cpp index f71872e77fe823..7e051e475f9d08 100644 --- a/clang/lib/CodeGen/Targets/X86.cpp +++ b/clang/lib/CodeGen/Targets/X86.cpp @@ -881,8 +881,8 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, CCState &State, if (isPromotableIntegerTypeForABI(Ty)) { if (InReg) - return ABIArgInfo::getExtendInReg(Ty); - return ABIArgInfo::getExtend(Ty); + return ABIArgInfo::getExtendInReg(Ty, CGT.ConvertType(Ty)); + return ABIArgInfo::getExtend(Ty, CGT.ConvertType(Ty)); } if (const auto *EIT = Ty->getAs()) { @@ -2756,7 +2756,7 @@ X86_64ABIInfo::classifyArgumentType(QualType Ty, unsigned freeIntRegs, if (Ty->isIntegralOrEnumerationType() && isPromotableIntegerTypeForABI(Ty)) - return ABIArgInfo::getExtend(Ty); + return ABIArgInfo::getExtend(Ty, CGT.ConvertType(Ty)); } break; diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 5b3783e20eabba..efe398dd531da7 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -3026,12 +3026,6 @@ class OffloadingActionBuilder final { // Set the flag to true, so that the builder acts on the current input. IsActive = true; - if (CompileHostOnly) - return ABRT_Success; - - // Replicate inputs for each GPU architecture. - auto Ty = IA->getType() == types::TY_HIP ? types::TY_HIP_DEVICE - : types::TY_CUDA_DEVICE; std::string CUID = FixedCUID.str(); if (CUID.empty()) { if (UseCUID == CUID_Random) @@ -3055,6 +3049,12 @@ class OffloadingActionBuilder final { } IA->setId(CUID); + if (CompileHostOnly) + return ABRT_Success; + + // Replicate inputs for each GPU architecture. + auto Ty = IA->getType() == types::TY_HIP ? types::TY_HIP_DEVICE + : types::TY_CUDA_DEVICE; for (unsigned I = 0, E = GpuArchList.size(); I != E; ++I) { CudaDeviceActions.push_back( C.MakeAction(IA->getInputArg(), Ty, IA->getId())); diff --git a/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp b/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp index 2213f431eb8114..574092c3e215de 100644 --- a/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp +++ b/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp @@ -34,7 +34,8 @@ systemz::FloatABI systemz::getSystemZFloatABI(const Driver &D, return ABI; } -std::string systemz::getSystemZTargetCPU(const ArgList &Args) { +std::string systemz::getSystemZTargetCPU(const ArgList &Args, + const llvm::Triple &T) { if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_march_EQ)) { llvm::StringRef CPUName = A->getValue(); @@ -48,6 +49,8 @@ std::string systemz::getSystemZTargetCPU(const ArgList &Args) { return std::string(CPUName); } + if (T.isOSzOS()) + return "zEC12"; return CLANG_SYSTEMZ_DEFAULT_ARCH; } diff --git a/clang/lib/Driver/ToolChains/Arch/SystemZ.h b/clang/lib/Driver/ToolChains/Arch/SystemZ.h index 1e42b68a8f3c20..f2d30d24ba63c5 100644 --- a/clang/lib/Driver/ToolChains/Arch/SystemZ.h +++ b/clang/lib/Driver/ToolChains/Arch/SystemZ.h @@ -27,7 +27,8 @@ enum class FloatABI { FloatABI getSystemZFloatABI(const Driver &D, const llvm::opt::ArgList &Args); -std::string getSystemZTargetCPU(const llvm::opt::ArgList &Args); +std::string getSystemZTargetCPU(const llvm::opt::ArgList &Args, + const llvm::Triple &T); void getSystemZTargetFeatures(const Driver &D, const llvm::opt::ArgList &Args, std::vector &Features); diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index 0601016c3b14b8..2ce6779f4b43e3 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -674,7 +674,7 @@ std::string tools::getCPUName(const Driver &D, const ArgList &Args, return getLanaiTargetCPU(Args); case llvm::Triple::systemz: - return systemz::getSystemZTargetCPU(Args); + return systemz::getSystemZTargetCPU(Args, T); case llvm::Triple::r600: case llvm::Triple::amdgcn: diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp index 426042b272e2dc..b7ae0deeb1219b 100644 --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -937,7 +937,8 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C, case llvm::Triple::systemz: { // Always pass an -march option, since our default of z10 is later // than the GNU assembler's default. - std::string CPUName = systemz::getSystemZTargetCPU(Args); + std::string CPUName = + systemz::getSystemZTargetCPU(Args, getToolChain().getTriple()); CmdArgs.push_back(Args.MakeArgString("-march=" + CPUName)); break; } diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 6a1cf61659fd97..dfa703aed0d34d 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -2874,21 +2874,26 @@ class AnnotatingParser { if (Line.InPPDirective && AfterRParen->is(tok::minus)) return false; + const auto *Prev = BeforeRParen; + + // Look for a function pointer type, e.g. `(*)()`. + if (Prev->is(tok::r_paren)) { + if (Prev->is(TT_CastRParen)) + return false; + Prev = Prev->MatchingParen; + if (!Prev) + return false; + Prev = Prev->Previous; + if (!Prev || Prev->isNot(tok::r_paren)) + return false; + Prev = Prev->MatchingParen; + return Prev && Prev->is(TT_FunctionTypeLParen); + } + // Search for unexpected tokens. - for (auto *Prev = BeforeRParen; Prev != LParen; Prev = Prev->Previous) { - if (Prev->is(tok::r_paren)) { - if (Prev->is(TT_CastRParen)) - return false; - Prev = Prev->MatchingParen; - if (!Prev) - return false; - if (Prev->is(TT_FunctionTypeLParen)) - break; - continue; - } + for (Prev = BeforeRParen; Prev != LParen; Prev = Prev->Previous) if (!Prev->isOneOf(tok::kw_const, tok::identifier, tok::coloncolon)) return false; - } return true; } diff --git a/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp b/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp index f618c536b5f3c6..8cdb463e2c99f2 100644 --- a/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp +++ b/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp @@ -138,10 +138,8 @@ namespace { SmallVector BlockDeclRefs; // Block related declarations. - SmallVector BlockByCopyDecls; - llvm::SmallPtrSet BlockByCopyDeclsPtrSet; - SmallVector BlockByRefDecls; - llvm::SmallPtrSet BlockByRefDeclsPtrSet; + llvm::SmallSetVector BlockByCopyDecls; + llvm::SmallSetVector BlockByRefDecls; llvm::DenseMap BlockByRefDeclNo; llvm::SmallPtrSet ImportedBlockDecls; llvm::SmallPtrSet ImportedLocalExternalDecls; @@ -4082,19 +4080,17 @@ std::string RewriteModernObjC::SynthesizeBlockFunc(BlockExpr *CE, int i, // Create local declarations to avoid rewriting all closure decl ref exprs. // First, emit a declaration for all "by ref" decls. - for (SmallVectorImpl::iterator I = BlockByRefDecls.begin(), - E = BlockByRefDecls.end(); I != E; ++I) { + for (ValueDecl *VD : BlockByRefDecls) { S += " "; - std::string Name = (*I)->getNameAsString(); + std::string Name = VD->getNameAsString(); std::string TypeString; - RewriteByRefString(TypeString, Name, (*I)); + RewriteByRefString(TypeString, Name, VD); TypeString += " *"; Name = TypeString + Name; - S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by ref\n"; + S += Name + " = __cself->" + VD->getNameAsString() + "; // bound by ref\n"; } // Next, emit a declaration for all "by copy" declarations. - for (SmallVectorImpl::iterator I = BlockByCopyDecls.begin(), - E = BlockByCopyDecls.end(); I != E; ++I) { + for (ValueDecl *VD : BlockByCopyDecls) { S += " "; // Handle nested closure invocation. For example: // @@ -4106,21 +4102,20 @@ std::string RewriteModernObjC::SynthesizeBlockFunc(BlockExpr *CE, int i, // myImportedClosure(); // import and invoke the closure // }; // - if (isTopLevelBlockPointerType((*I)->getType())) { - RewriteBlockPointerTypeVariable(S, (*I)); + if (isTopLevelBlockPointerType(VD->getType())) { + RewriteBlockPointerTypeVariable(S, VD); S += " = ("; - RewriteBlockPointerType(S, (*I)->getType()); + RewriteBlockPointerType(S, VD->getType()); S += ")"; - S += "__cself->" + (*I)->getNameAsString() + "; // bound by copy\n"; - } - else { - std::string Name = (*I)->getNameAsString(); - QualType QT = (*I)->getType(); - if (HasLocalVariableExternalStorage(*I)) + S += "__cself->" + VD->getNameAsString() + "; // bound by copy\n"; + } else { + std::string Name = VD->getNameAsString(); + QualType QT = VD->getType(); + if (HasLocalVariableExternalStorage(VD)) QT = Context->getPointerType(QT); QT.getAsStringInternal(Name, Context->getPrintingPolicy()); - S += Name + " = __cself->" + - (*I)->getNameAsString() + "; // bound by copy\n"; + S += Name + " = __cself->" + VD->getNameAsString() + + "; // bound by copy\n"; } } std::string RewrittenStr = RewrittenBlockExprs[CE]; @@ -4146,7 +4141,7 @@ std::string RewriteModernObjC::SynthesizeBlockHelperFuncs( S += VD->getNameAsString(); S += ", (void*)src->"; S += VD->getNameAsString(); - if (BlockByRefDeclsPtrSet.count(VD)) + if (BlockByRefDecls.count(VD)) S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);"; else if (VD->getType()->isBlockPointerType()) S += ", " + utostr(BLOCK_FIELD_IS_BLOCK) + "/*BLOCK_FIELD_IS_BLOCK*/);"; @@ -4163,7 +4158,7 @@ std::string RewriteModernObjC::SynthesizeBlockHelperFuncs( for (ValueDecl *VD : ImportedBlockDecls) { S += "_Block_object_dispose((void*)src->"; S += VD->getNameAsString(); - if (BlockByRefDeclsPtrSet.count(VD)) + if (BlockByRefDecls.count(VD)) S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);"; else if (VD->getType()->isBlockPointerType()) S += ", " + utostr(BLOCK_FIELD_IS_BLOCK) + "/*BLOCK_FIELD_IS_BLOCK*/);"; @@ -4190,10 +4185,9 @@ std::string RewriteModernObjC::SynthesizeBlockImpl(BlockExpr *CE, if (BlockDeclRefs.size()) { // Output all "by copy" declarations. - for (SmallVectorImpl::iterator I = BlockByCopyDecls.begin(), - E = BlockByCopyDecls.end(); I != E; ++I) { + for (ValueDecl *VD : BlockByCopyDecls) { S += " "; - std::string FieldName = (*I)->getNameAsString(); + std::string FieldName = VD->getNameAsString(); std::string ArgName = "_" + FieldName; // Handle nested closure invocation. For example: // @@ -4205,12 +4199,12 @@ std::string RewriteModernObjC::SynthesizeBlockImpl(BlockExpr *CE, // myImportedBlock(); // import and invoke the closure // }; // - if (isTopLevelBlockPointerType((*I)->getType())) { + if (isTopLevelBlockPointerType(VD->getType())) { S += "struct __block_impl *"; Constructor += ", void *" + ArgName; } else { - QualType QT = (*I)->getType(); - if (HasLocalVariableExternalStorage(*I)) + QualType QT = VD->getType(); + if (HasLocalVariableExternalStorage(VD)) QT = Context->getPointerType(QT); QT.getAsStringInternal(FieldName, Context->getPrintingPolicy()); QT.getAsStringInternal(ArgName, Context->getPrintingPolicy()); @@ -4219,14 +4213,13 @@ std::string RewriteModernObjC::SynthesizeBlockImpl(BlockExpr *CE, S += FieldName + ";\n"; } // Output all "by ref" declarations. - for (SmallVectorImpl::iterator I = BlockByRefDecls.begin(), - E = BlockByRefDecls.end(); I != E; ++I) { + for (ValueDecl *VD : BlockByRefDecls) { S += " "; - std::string FieldName = (*I)->getNameAsString(); + std::string FieldName = VD->getNameAsString(); std::string ArgName = "_" + FieldName; { std::string TypeString; - RewriteByRefString(TypeString, FieldName, (*I)); + RewriteByRefString(TypeString, FieldName, VD); TypeString += " *"; FieldName = TypeString + FieldName; ArgName = TypeString + ArgName; @@ -4238,24 +4231,21 @@ std::string RewriteModernObjC::SynthesizeBlockImpl(BlockExpr *CE, Constructor += ", int flags=0)"; // Initialize all "by copy" arguments. bool firsTime = true; - for (SmallVectorImpl::iterator I = BlockByCopyDecls.begin(), - E = BlockByCopyDecls.end(); I != E; ++I) { - std::string Name = (*I)->getNameAsString(); - if (firsTime) { - Constructor += " : "; - firsTime = false; - } - else - Constructor += ", "; - if (isTopLevelBlockPointerType((*I)->getType())) - Constructor += Name + "((struct __block_impl *)_" + Name + ")"; - else - Constructor += Name + "(_" + Name + ")"; + for (const ValueDecl *VD : BlockByCopyDecls) { + std::string Name = VD->getNameAsString(); + if (firsTime) { + Constructor += " : "; + firsTime = false; + } else + Constructor += ", "; + if (isTopLevelBlockPointerType(VD->getType())) + Constructor += Name + "((struct __block_impl *)_" + Name + ")"; + else + Constructor += Name + "(_" + Name + ")"; } // Initialize all "by ref" arguments. - for (SmallVectorImpl::iterator I = BlockByRefDecls.begin(), - E = BlockByRefDecls.end(); I != E; ++I) { - std::string Name = (*I)->getNameAsString(); + for (const ValueDecl *VD : BlockByRefDecls) { + std::string Name = VD->getNameAsString(); if (firsTime) { Constructor += " : "; firsTime = false; @@ -4340,17 +4330,11 @@ void RewriteModernObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart, ValueDecl *VD = Exp->getDecl(); BlockDeclRefs.push_back(Exp); if (!VD->hasAttr()) { - if (!BlockByCopyDeclsPtrSet.count(VD)) { - BlockByCopyDeclsPtrSet.insert(VD); - BlockByCopyDecls.push_back(VD); - } + BlockByCopyDecls.insert(VD); continue; } - if (!BlockByRefDeclsPtrSet.count(VD)) { - BlockByRefDeclsPtrSet.insert(VD); - BlockByRefDecls.push_back(VD); - } + BlockByRefDecls.insert(VD); // imported objects in the inner blocks not used in the outer // blocks must be copied/disposed in the outer block as well. @@ -4380,9 +4364,7 @@ void RewriteModernObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart, BlockDeclRefs.clear(); BlockByRefDecls.clear(); - BlockByRefDeclsPtrSet.clear(); BlockByCopyDecls.clear(); - BlockByCopyDeclsPtrSet.clear(); ImportedBlockDecls.clear(); } if (RewriteSC) { @@ -5160,20 +5142,12 @@ void RewriteModernObjC::CollectBlockDeclRefInfo(BlockExpr *Exp) { if (BlockDeclRefs.size()) { // Unique all "by copy" declarations. for (unsigned i = 0; i < BlockDeclRefs.size(); i++) - if (!BlockDeclRefs[i]->getDecl()->hasAttr()) { - if (!BlockByCopyDeclsPtrSet.count(BlockDeclRefs[i]->getDecl())) { - BlockByCopyDeclsPtrSet.insert(BlockDeclRefs[i]->getDecl()); - BlockByCopyDecls.push_back(BlockDeclRefs[i]->getDecl()); - } - } + if (!BlockDeclRefs[i]->getDecl()->hasAttr()) + BlockByCopyDecls.insert(BlockDeclRefs[i]->getDecl()); // Unique all "by ref" declarations. for (unsigned i = 0; i < BlockDeclRefs.size(); i++) - if (BlockDeclRefs[i]->getDecl()->hasAttr()) { - if (!BlockByRefDeclsPtrSet.count(BlockDeclRefs[i]->getDecl())) { - BlockByRefDeclsPtrSet.insert(BlockDeclRefs[i]->getDecl()); - BlockByRefDecls.push_back(BlockDeclRefs[i]->getDecl()); - } - } + if (BlockDeclRefs[i]->getDecl()->hasAttr()) + BlockByRefDecls.insert(BlockDeclRefs[i]->getDecl()); // Find any imported blocks...they will need special attention. for (unsigned i = 0; i < BlockDeclRefs.size(); i++) if (BlockDeclRefs[i]->getDecl()->hasAttr() || @@ -5205,20 +5179,16 @@ Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp, for (unsigned i = 0; i < InnerBlockDeclRefs.size(); i++) { DeclRefExpr *Exp = InnerBlockDeclRefs[i]; ValueDecl *VD = Exp->getDecl(); - if (!VD->hasAttr() && !BlockByCopyDeclsPtrSet.count(VD)) { - // We need to save the copied-in variables in nested - // blocks because it is needed at the end for some of the API generations. - // See SynthesizeBlockLiterals routine. + if (!VD->hasAttr() && BlockByCopyDecls.insert(VD)) { + // We need to save the copied-in variables in nested + // blocks because it is needed at the end for some of the API + // generations. See SynthesizeBlockLiterals routine. InnerDeclRefs.push_back(Exp); countOfInnerDecls++; BlockDeclRefs.push_back(Exp); - BlockByCopyDeclsPtrSet.insert(VD); - BlockByCopyDecls.push_back(VD); } - if (VD->hasAttr() && !BlockByRefDeclsPtrSet.count(VD)) { + if (VD->hasAttr() && BlockByRefDecls.insert(VD)) { InnerDeclRefs.push_back(Exp); countOfInnerDecls++; BlockDeclRefs.push_back(Exp); - BlockByRefDeclsPtrSet.insert(VD); - BlockByRefDecls.push_back(VD); } } // Find any imported blocks...they will need special attention. @@ -5299,47 +5269,43 @@ Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp, if (BlockDeclRefs.size()) { Expr *Exp; // Output all "by copy" declarations. - for (SmallVectorImpl::iterator I = BlockByCopyDecls.begin(), - E = BlockByCopyDecls.end(); I != E; ++I) { - if (isObjCType((*I)->getType())) { + for (ValueDecl *VD : BlockByCopyDecls) { + if (isObjCType(VD->getType())) { // FIXME: Conform to ABI ([[obj retain] autorelease]). - FD = SynthBlockInitFunctionDecl((*I)->getName()); + FD = SynthBlockInitFunctionDecl(VD->getName()); Exp = new (Context) DeclRefExpr(*Context, FD, false, FD->getType(), VK_LValue, SourceLocation()); - if (HasLocalVariableExternalStorage(*I)) { - QualType QT = (*I)->getType(); + if (HasLocalVariableExternalStorage(VD)) { + QualType QT = VD->getType(); QT = Context->getPointerType(QT); Exp = UnaryOperator::Create(const_cast(*Context), Exp, UO_AddrOf, QT, VK_PRValue, OK_Ordinary, SourceLocation(), false, FPOptionsOverride()); } - } else if (isTopLevelBlockPointerType((*I)->getType())) { - FD = SynthBlockInitFunctionDecl((*I)->getName()); + } else if (isTopLevelBlockPointerType(VD->getType())) { + FD = SynthBlockInitFunctionDecl(VD->getName()); Arg = new (Context) DeclRefExpr(*Context, FD, false, FD->getType(), VK_LValue, SourceLocation()); Exp = NoTypeInfoCStyleCastExpr(Context, Context->VoidPtrTy, CK_BitCast, Arg); } else { - FD = SynthBlockInitFunctionDecl((*I)->getName()); + FD = SynthBlockInitFunctionDecl(VD->getName()); Exp = new (Context) DeclRefExpr(*Context, FD, false, FD->getType(), VK_LValue, SourceLocation()); - if (HasLocalVariableExternalStorage(*I)) { - QualType QT = (*I)->getType(); + if (HasLocalVariableExternalStorage(VD)) { + QualType QT = VD->getType(); QT = Context->getPointerType(QT); Exp = UnaryOperator::Create(const_cast(*Context), Exp, UO_AddrOf, QT, VK_PRValue, OK_Ordinary, SourceLocation(), false, FPOptionsOverride()); } - } InitExprs.push_back(Exp); } // Output all "by ref" declarations. - for (SmallVectorImpl::iterator I = BlockByRefDecls.begin(), - E = BlockByRefDecls.end(); I != E; ++I) { - ValueDecl *ND = (*I); + for (ValueDecl *ND : BlockByRefDecls) { std::string Name(ND->getNameAsString()); std::string RecName; RewriteByRefString(RecName, Name, ND, true); @@ -5351,7 +5317,7 @@ Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp, assert(RD && "SynthBlockInitExpr(): Can't find RecordDecl"); QualType castT = Context->getPointerType(Context->getTagDeclType(RD)); - FD = SynthBlockInitFunctionDecl((*I)->getName()); + FD = SynthBlockInitFunctionDecl(ND->getName()); Exp = new (Context) DeclRefExpr(*Context, FD, false, FD->getType(), VK_LValue, SourceLocation()); bool isNestedCapturedVar = false; @@ -5406,9 +5372,7 @@ Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp, BlockDeclRefs.clear(); BlockByRefDecls.clear(); - BlockByRefDeclsPtrSet.clear(); BlockByCopyDecls.clear(); - BlockByCopyDeclsPtrSet.clear(); ImportedBlockDecls.clear(); return NewRep; } diff --git a/clang/lib/Headers/hexagon_types.h b/clang/lib/Headers/hexagon_types.h index 029727cc48176b..8e73fad4bcd424 100644 --- a/clang/lib/Headers/hexagon_types.h +++ b/clang/lib/Headers/hexagon_types.h @@ -1,7 +1,11 @@ -/******************************************************************************/ -/* (c) 2020 Qualcomm Innovation Center, Inc. All rights reserved. */ -/* */ -/******************************************************************************/ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + #ifndef HEXAGON_TYPES_H #define HEXAGON_TYPES_H diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h index 5c08a45a35377d..2ac18056b0fc3d 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -1603,6 +1603,32 @@ double3 saturate(double3); _HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_saturate) double4 saturate(double4); +//===----------------------------------------------------------------------===// +// select builtins +//===----------------------------------------------------------------------===// + +/// \fn T select(bool Cond, T TrueVal, T FalseVal) +/// \brief ternary operator. +/// \param Cond The Condition input value. +/// \param TrueVal The Value returned if Cond is true. +/// \param FalseVal The Value returned if Cond is false. + +template +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_select) +T select(bool, T, T); + +/// \fn vector select(vector Conds, vector TrueVals, +/// vector FalseVals) +/// \brief ternary operator for vectors. All vectors must be the same size. +/// \param Conds The Condition input values. +/// \param TrueVals The vector values are chosen from when conditions are true. +/// \param FalseVals The vector values are chosen from when conditions are +/// false. + +template +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_select) +vector select(vector, vector, vector); + //===----------------------------------------------------------------------===// // sin builtins //===----------------------------------------------------------------------===// diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 78d729c5ef7d8a..61a1ca3da6bca0 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -146,6 +146,86 @@ void Parser::ParseAttributes(unsigned WhichAttrKinds, ParsedAttributes &Attrs, } while (MoreToParse); } +/// ParseSingleGNUAttribute - Parse a single GNU attribute. +/// +/// [GNU] attrib: +/// empty +/// attrib-name +/// attrib-name '(' identifier ')' +/// attrib-name '(' identifier ',' nonempty-expr-list ')' +/// attrib-name '(' argument-expression-list [C99 6.5.2] ')' +/// +/// [GNU] attrib-name: +/// identifier +/// typespec +/// typequal +/// storageclass +bool Parser::ParseSingleGNUAttribute(ParsedAttributes &Attrs, + SourceLocation &EndLoc, + LateParsedAttrList *LateAttrs, + Declarator *D) { + IdentifierInfo *AttrName = Tok.getIdentifierInfo(); + if (!AttrName) + return true; + + SourceLocation AttrNameLoc = ConsumeToken(); + + if (Tok.isNot(tok::l_paren)) { + Attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, + ParsedAttr::Form::GNU()); + return false; + } + + bool LateParse = false; + if (!LateAttrs) + LateParse = false; + else if (LateAttrs->lateAttrParseExperimentalExtOnly()) { + // The caller requested that this attribute **only** be late + // parsed for `LateAttrParseExperimentalExt` attributes. This will + // only be late parsed if the experimental language option is enabled. + LateParse = getLangOpts().ExperimentalLateParseAttributes && + IsAttributeLateParsedExperimentalExt(*AttrName); + } else { + // The caller did not restrict late parsing to only + // `LateAttrParseExperimentalExt` attributes so late parse + // both `LateAttrParseStandard` and `LateAttrParseExperimentalExt` + // attributes. + LateParse = IsAttributeLateParsedExperimentalExt(*AttrName) || + IsAttributeLateParsedStandard(*AttrName); + } + + // Handle "parameterized" attributes + if (!LateParse) { + ParseGNUAttributeArgs(AttrName, AttrNameLoc, Attrs, &EndLoc, nullptr, + SourceLocation(), ParsedAttr::Form::GNU(), D); + return false; + } + + // Handle attributes with arguments that require late parsing. + LateParsedAttribute *LA = + new LateParsedAttribute(this, *AttrName, AttrNameLoc); + LateAttrs->push_back(LA); + + // Attributes in a class are parsed at the end of the class, along + // with other late-parsed declarations. + if (!ClassStack.empty() && !LateAttrs->parseSoon()) + getCurrentClass().LateParsedDeclarations.push_back(LA); + + // Be sure ConsumeAndStoreUntil doesn't see the start l_paren, since it + // recursively consumes balanced parens. + LA->Toks.push_back(Tok); + ConsumeParen(); + // Consume everything up to and including the matching right parens. + ConsumeAndStoreUntil(tok::r_paren, LA->Toks, /*StopAtSemi=*/true); + + Token Eof; + Eof.startToken(); + Eof.setLocation(Tok.getLocation()); + LA->Toks.push_back(Eof); + + return false; +} + /// ParseGNUAttributes - Parse a non-empty attributes list. /// /// [GNU] attributes: @@ -223,64 +303,9 @@ void Parser::ParseGNUAttributes(ParsedAttributes &Attrs, AttributeCommonInfo::Syntax::AS_GNU); break; } - IdentifierInfo *AttrName = Tok.getIdentifierInfo(); - if (!AttrName) - break; - SourceLocation AttrNameLoc = ConsumeToken(); - - if (Tok.isNot(tok::l_paren)) { - Attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, - ParsedAttr::Form::GNU()); - continue; - } - - bool LateParse = false; - if (!LateAttrs) - LateParse = false; - else if (LateAttrs->lateAttrParseExperimentalExtOnly()) { - // The caller requested that this attribute **only** be late - // parsed for `LateAttrParseExperimentalExt` attributes. This will - // only be late parsed if the experimental language option is enabled. - LateParse = getLangOpts().ExperimentalLateParseAttributes && - IsAttributeLateParsedExperimentalExt(*AttrName); - } else { - // The caller did not restrict late parsing to only - // `LateAttrParseExperimentalExt` attributes so late parse - // both `LateAttrParseStandard` and `LateAttrParseExperimentalExt` - // attributes. - LateParse = IsAttributeLateParsedExperimentalExt(*AttrName) || - IsAttributeLateParsedStandard(*AttrName); - } - - // Handle "parameterized" attributes - if (!LateParse) { - ParseGNUAttributeArgs(AttrName, AttrNameLoc, Attrs, &EndLoc, nullptr, - SourceLocation(), ParsedAttr::Form::GNU(), D); - continue; - } - - // Handle attributes with arguments that require late parsing. - LateParsedAttribute *LA = - new LateParsedAttribute(this, *AttrName, AttrNameLoc); - LateAttrs->push_back(LA); - - // Attributes in a class are parsed at the end of the class, along - // with other late-parsed declarations. - if (!ClassStack.empty() && !LateAttrs->parseSoon()) - getCurrentClass().LateParsedDeclarations.push_back(LA); - - // Be sure ConsumeAndStoreUntil doesn't see the start l_paren, since it - // recursively consumes balanced parens. - LA->Toks.push_back(Tok); - ConsumeParen(); - // Consume everything up to and including the matching right parens. - ConsumeAndStoreUntil(tok::r_paren, LA->Toks, /*StopAtSemi=*/true); - - Token Eof; - Eof.startToken(); - Eof.setLocation(Tok.getLocation()); - LA->Toks.push_back(Eof); + if (ParseSingleGNUAttribute(Attrs, EndLoc, LateAttrs, D)) + break; } while (Tok.is(tok::comma)); if (ExpectAndConsume(tok::r_paren)) diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 29acd06af603be..46ddd360870b4f 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -2865,6 +2865,7 @@ bool FunctionEffectDiff::shouldDiagnoseConversion( // matching is better. return true; } + llvm_unreachable("Unhandled FunctionEffectDiff::Kind enum"); case FunctionEffect::Kind::Blocking: case FunctionEffect::Kind::Allocating: return false; @@ -2890,6 +2891,7 @@ bool FunctionEffectDiff::shouldDiagnoseRedeclaration( // All these forms of mismatches are diagnosed. return true; } + llvm_unreachable("Unhandled FunctionEffectDiff::Kind enum"); case FunctionEffect::Kind::Blocking: case FunctionEffect::Kind::Allocating: return false; @@ -2921,6 +2923,7 @@ FunctionEffectDiff::shouldDiagnoseMethodOverride( case Kind::ConditionMismatch: return OverrideResult::Warn; } + llvm_unreachable("Unhandled FunctionEffectDiff::Kind enum"); case FunctionEffect::Kind::Blocking: case FunctionEffect::Kind::Allocating: diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp index 1bb8955f6f8792..a574d56646f3a2 100644 --- a/clang/lib/Sema/SemaCoroutine.cpp +++ b/clang/lib/Sema/SemaCoroutine.cpp @@ -844,6 +844,19 @@ ExprResult Sema::BuildOperatorCoawaitLookupExpr(Scope *S, SourceLocation Loc) { return CoawaitOp; } +static bool isAttributedCoroAwaitElidable(const QualType &QT) { + auto *Record = QT->getAsCXXRecordDecl(); + return Record && Record->hasAttr(); +} + +static bool isCoroAwaitElidableCall(Expr *Operand) { + if (!Operand->isPRValue()) { + return false; + } + + return isAttributedCoroAwaitElidable(Operand->getType()); +} + // Attempts to resolve and build a CoawaitExpr from "raw" inputs, bailing out to // DependentCoawaitExpr if needed. ExprResult Sema::BuildUnresolvedCoawaitExpr(SourceLocation Loc, Expr *Operand, @@ -867,7 +880,16 @@ ExprResult Sema::BuildUnresolvedCoawaitExpr(SourceLocation Loc, Expr *Operand, } auto *RD = Promise->getType()->getAsCXXRecordDecl(); - auto *Transformed = Operand; + bool AwaitElidable = + isCoroAwaitElidableCall(Operand) && + isAttributedCoroAwaitElidable( + getCurFunctionDecl(/*AllowLambda=*/true)->getReturnType()); + + if (AwaitElidable) + if (auto *Call = dyn_cast(Operand->IgnoreImplicit())) + Call->setCoroElideSafe(); + + Expr *Transformed = Operand; if (lookupMember(*this, "await_transform", RD, Loc)) { ExprResult R = buildPromiseCall(*this, Promise, Loc, "await_transform", Operand); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 0f63c764536ecb..3c6a0dff798ff6 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -9766,6 +9766,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // the function decl is created above). // FIXME: We need a better way to separate C++ standard and clang modules. bool ImplicitInlineCXX20 = !getLangOpts().CPlusPlusModules || + NewFD->isConstexpr() || NewFD->isConsteval() || !NewFD->getOwningModule() || NewFD->isFromExplicitGlobalModule() || NewFD->getOwningModule()->isHeaderLikeModule(); diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index d068cb6a78f266..72d82b424c26c8 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -2993,10 +2993,17 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) { return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) << Unknown << Tune << ParsedAttrs.Tune << Target; - if (Context.getTargetInfo().getTriple().isRISCV() && - ParsedAttrs.Duplicate != "") - return Diag(LiteralLoc, diag::err_duplicate_target_attribute) - << Duplicate << None << ParsedAttrs.Duplicate << Target; + if (Context.getTargetInfo().getTriple().isRISCV()) { + if (ParsedAttrs.Duplicate != "") + return Diag(LiteralLoc, diag::err_duplicate_target_attribute) + << Duplicate << None << ParsedAttrs.Duplicate << Target; + for (const auto &Feature : ParsedAttrs.Features) { + StringRef CurFeature = Feature; + if (!CurFeature.starts_with('+') && !CurFeature.starts_with('-')) + return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) + << Unsupported << None << AttrStr << Target; + } + } if (ParsedAttrs.Duplicate != "") return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index f90f16c2923d03..6b6fa98bf394ca 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -4396,8 +4396,9 @@ Sema::BuildMemInitializer(Decl *ConstructorD, for (auto const &Base : ClassDecl->bases()) { auto BaseTemplate = Base.getType()->getAs(); - if (BaseTemplate && Context.hasSameTemplateName( - BaseTemplate->getTemplateName(), TN)) { + if (BaseTemplate && + Context.hasSameTemplateName(BaseTemplate->getTemplateName(), TN, + /*IgnoreDeduced=*/true)) { Diag(IdLoc, diag::ext_unqualified_base_class) << SourceRange(IdLoc, Init->getSourceRange().getEnd()); BaseType = Base.getType(); @@ -11459,8 +11460,8 @@ bool Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R, if (auto RetTST = TSI->getTypeLoc().getAsAdjusted()) { TemplateName SpecifiedName = RetTST.getTypePtr()->getTemplateName(); - bool TemplateMatches = - Context.hasSameTemplateName(SpecifiedName, GuidedTemplate); + bool TemplateMatches = Context.hasSameTemplateName( + SpecifiedName, GuidedTemplate, /*IgnoreDeduced=*/true); const QualifiedTemplateName *Qualifiers = SpecifiedName.getAsQualifiedTemplateName(); diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index 3b40769939f12f..3b91303ac8cb8a 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -1531,6 +1531,79 @@ void SetElementTypeAsReturnType(Sema *S, CallExpr *TheCall, TheCall->setType(ReturnType); } +static bool CheckScalarOrVector(Sema *S, CallExpr *TheCall, QualType Scalar, + unsigned ArgIndex) { + assert(TheCall->getNumArgs() >= ArgIndex); + QualType ArgType = TheCall->getArg(ArgIndex)->getType(); + auto *VTy = ArgType->getAs(); + // not the scalar or vector + if (!(S->Context.hasSameUnqualifiedType(ArgType, Scalar) || + (VTy && + S->Context.hasSameUnqualifiedType(VTy->getElementType(), Scalar)))) { + S->Diag(TheCall->getArg(0)->getBeginLoc(), + diag::err_typecheck_expect_scalar_or_vector) + << ArgType << Scalar; + return true; + } + return false; +} + +static bool CheckBoolSelect(Sema *S, CallExpr *TheCall) { + assert(TheCall->getNumArgs() == 3); + Expr *Arg1 = TheCall->getArg(1); + Expr *Arg2 = TheCall->getArg(2); + if (!S->Context.hasSameUnqualifiedType(Arg1->getType(), Arg2->getType())) { + S->Diag(TheCall->getBeginLoc(), + diag::err_typecheck_call_different_arg_types) + << Arg1->getType() << Arg2->getType() << Arg1->getSourceRange() + << Arg2->getSourceRange(); + return true; + } + + TheCall->setType(Arg1->getType()); + return false; +} + +static bool CheckVectorSelect(Sema *S, CallExpr *TheCall) { + assert(TheCall->getNumArgs() == 3); + Expr *Arg1 = TheCall->getArg(1); + Expr *Arg2 = TheCall->getArg(2); + if (!Arg1->getType()->isVectorType()) { + S->Diag(Arg1->getBeginLoc(), diag::err_builtin_non_vector_type) + << "Second" << TheCall->getDirectCallee() << Arg1->getType() + << Arg1->getSourceRange(); + return true; + } + + if (!Arg2->getType()->isVectorType()) { + S->Diag(Arg2->getBeginLoc(), diag::err_builtin_non_vector_type) + << "Third" << TheCall->getDirectCallee() << Arg2->getType() + << Arg2->getSourceRange(); + return true; + } + + if (!S->Context.hasSameUnqualifiedType(Arg1->getType(), Arg2->getType())) { + S->Diag(TheCall->getBeginLoc(), + diag::err_typecheck_call_different_arg_types) + << Arg1->getType() << Arg2->getType() << Arg1->getSourceRange() + << Arg2->getSourceRange(); + return true; + } + + // caller has checked that Arg0 is a vector. + // check all three args have the same length. + if (TheCall->getArg(0)->getType()->getAs()->getNumElements() != + Arg1->getType()->getAs()->getNumElements()) { + S->Diag(TheCall->getBeginLoc(), + diag::err_typecheck_vector_lengths_not_equal) + << TheCall->getArg(0)->getType() << Arg1->getType() + << TheCall->getArg(0)->getSourceRange() << Arg1->getSourceRange(); + return true; + } + TheCall->setType(Arg1->getType()); + return false; +} + // Note: returning true in this case results in CheckBuiltinFunctionCall // returning an ExprError bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { @@ -1563,6 +1636,20 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { return true; break; } + case Builtin::BI__builtin_hlsl_select: { + if (SemaRef.checkArgCount(TheCall, 3)) + return true; + if (CheckScalarOrVector(&SemaRef, TheCall, getASTContext().BoolTy, 0)) + return true; + QualType ArgTy = TheCall->getArg(0)->getType(); + if (ArgTy->isBooleanType() && CheckBoolSelect(&SemaRef, TheCall)) + return true; + auto *VTy = ArgTy->getAs(); + if (VTy && VTy->getElementType()->isBooleanType() && + CheckVectorSelect(&SemaRef, TheCall)) + return true; + break; + } case Builtin::BI__builtin_hlsl_elementwise_saturate: case Builtin::BI__builtin_hlsl_elementwise_rcp: { if (CheckAllArgsHaveFloatRepresentation(&SemaRef, TheCall)) diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 23c4903ec15855..b952ffbd69f5d5 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -42,6 +42,7 @@ #include "llvm/ADT/PointerEmbeddedInt.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Sequence.h" +#include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Frontend/OpenMP/OMPAssume.h" @@ -3707,6 +3708,17 @@ getMapClauseKindFromModifier(OpenMPDefaultmapClauseModifier M, } namespace { +struct VariableImplicitInfo { + static const unsigned MapKindNum = OMPC_MAP_unknown; + static const unsigned DefaultmapKindNum = OMPC_DEFAULTMAP_unknown + 1; + + llvm::SetVector Privates; + llvm::SetVector Firstprivates; + llvm::SetVector Mappings[DefaultmapKindNum][MapKindNum]; + llvm::SmallVector + MapModifiers[DefaultmapKindNum]; +}; + class DSAAttrChecker final : public StmtVisitor { DSAStackTy *Stack; Sema &SemaRef; @@ -3714,12 +3726,8 @@ class DSAAttrChecker final : public StmtVisitor { bool ErrorFound = false; bool TryCaptureCXXThisMembers = false; CapturedStmt *CS = nullptr; - const static unsigned DefaultmapKindNum = OMPC_DEFAULTMAP_unknown + 1; - llvm::SmallVector ImplicitFirstprivate; - llvm::SmallVector ImplicitPrivate; - llvm::SmallVector ImplicitMap[DefaultmapKindNum][OMPC_MAP_delete]; - llvm::SmallVector - ImplicitMapModifier[DefaultmapKindNum]; + + VariableImplicitInfo ImpInfo; SemaOpenMP::VarsWithInheritedDSAType VarsWithInheritedDSA; llvm::SmallDenseSet ImplicitDeclarations; @@ -3871,9 +3879,9 @@ class DSAAttrChecker final : public StmtVisitor { bool IsModifierPresent = Stack->getDefaultmapModifier(ClauseKind) == OMPC_DEFAULTMAP_MODIFIER_present; if (IsModifierPresent) { - if (!llvm::is_contained(ImplicitMapModifier[ClauseKind], + if (!llvm::is_contained(ImpInfo.MapModifiers[ClauseKind], OMPC_MAP_MODIFIER_present)) { - ImplicitMapModifier[ClauseKind].push_back( + ImpInfo.MapModifiers[ClauseKind].push_back( OMPC_MAP_MODIFIER_present); } } @@ -3913,13 +3921,13 @@ class DSAAttrChecker final : public StmtVisitor { IsFirstprivate = IsFirstprivate || (Stack->mustBeFirstprivate(ClauseKind) && !Res); if (IsFirstprivate) { - ImplicitFirstprivate.emplace_back(E); + ImpInfo.Firstprivates.insert(E); } else { OpenMPDefaultmapClauseModifier M = Stack->getDefaultmapModifier(ClauseKind); OpenMPMapClauseKind Kind = getMapClauseKindFromModifier( M, ClauseKind == OMPC_DEFAULTMAP_aggregate || Res); - ImplicitMap[ClauseKind][Kind].emplace_back(E); + ImpInfo.Mappings[ClauseKind][Kind].insert(E); } return; } @@ -3956,9 +3964,9 @@ class DSAAttrChecker final : public StmtVisitor { !DVar.RefExpr)) && !Stack->isLoopControlVariable(VD).first) { if (Stack->getDefaultDSA() == DSA_private) - ImplicitPrivate.push_back(E); + ImpInfo.Privates.insert(E); else - ImplicitFirstprivate.push_back(E); + ImpInfo.Firstprivates.insert(E); return; } @@ -4015,7 +4023,7 @@ class DSAAttrChecker final : public StmtVisitor { getVariableCategoryFromDecl(SemaRef.getLangOpts(), FD); OpenMPMapClauseKind Kind = getMapClauseKindFromModifier( Modifier, /*IsAggregateOrDeclareTarget=*/true); - ImplicitMap[ClauseKind][Kind].emplace_back(E); + ImpInfo.Mappings[ClauseKind][Kind].insert(E); return; } @@ -4050,7 +4058,7 @@ class DSAAttrChecker final : public StmtVisitor { // expression. // TODO: try to make it firstprivate. if (DVar.CKind != OMPC_unknown) - ImplicitFirstprivate.push_back(E); + ImpInfo.Firstprivates.insert(E); } return; } @@ -4172,18 +4180,7 @@ class DSAAttrChecker final : public StmtVisitor { } } bool isErrorFound() const { return ErrorFound; } - ArrayRef getImplicitFirstprivate() const { - return ImplicitFirstprivate; - } - ArrayRef getImplicitPrivate() const { return ImplicitPrivate; } - ArrayRef getImplicitMap(OpenMPDefaultmapClauseKind DK, - OpenMPMapClauseKind MK) const { - return ImplicitMap[DK][MK]; - } - ArrayRef - getImplicitMapModifier(OpenMPDefaultmapClauseKind Kind) const { - return ImplicitMapModifier[Kind]; - } + const VariableImplicitInfo &getImplicitInfo() const { return ImpInfo; } const SemaOpenMP::VarsWithInheritedDSAType &getVarsWithInheritedDSA() const { return VarsWithInheritedDSA; } @@ -6060,69 +6057,56 @@ StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective( return StmtError(); // Generate list of implicitly defined firstprivate variables. VarsWithInheritedDSA = DSAChecker.getVarsWithInheritedDSA(); + VariableImplicitInfo ImpInfo = DSAChecker.getImplicitInfo(); - SmallVector ImplicitFirstprivates( - DSAChecker.getImplicitFirstprivate()); - SmallVector ImplicitPrivates(DSAChecker.getImplicitPrivate()); - const unsigned DefaultmapKindNum = OMPC_DEFAULTMAP_unknown + 1; - SmallVector ImplicitMaps[DefaultmapKindNum][OMPC_MAP_delete]; - SmallVector - ImplicitMapModifiers[DefaultmapKindNum]; SmallVector - ImplicitMapModifiersLoc[DefaultmapKindNum]; + ImplicitMapModifiersLoc[VariableImplicitInfo::DefaultmapKindNum]; // Get the original location of present modifier from Defaultmap clause. - SourceLocation PresentModifierLocs[DefaultmapKindNum]; + SourceLocation PresentModifierLocs[VariableImplicitInfo::DefaultmapKindNum]; for (OMPClause *C : Clauses) { if (auto *DMC = dyn_cast(C)) if (DMC->getDefaultmapModifier() == OMPC_DEFAULTMAP_MODIFIER_present) PresentModifierLocs[DMC->getDefaultmapKind()] = DMC->getDefaultmapModifierLoc(); } - for (unsigned VC = 0; VC < DefaultmapKindNum; ++VC) { - auto K = static_cast(VC); - for (unsigned I = 0; I < OMPC_MAP_delete; ++I) { - ArrayRef ImplicitMap = - DSAChecker.getImplicitMap(K, static_cast(I)); - ImplicitMaps[VC][I].append(ImplicitMap.begin(), ImplicitMap.end()); - } - ArrayRef ImplicitModifier = - DSAChecker.getImplicitMapModifier(K); - ImplicitMapModifiers[VC].append(ImplicitModifier.begin(), - ImplicitModifier.end()); - std::fill_n(std::back_inserter(ImplicitMapModifiersLoc[VC]), - ImplicitModifier.size(), PresentModifierLocs[VC]); + + for (OpenMPDefaultmapClauseKind K : + llvm::enum_seq_inclusive( + OpenMPDefaultmapClauseKind(), OMPC_DEFAULTMAP_unknown)) { + std::fill_n(std::back_inserter(ImplicitMapModifiersLoc[K]), + ImpInfo.MapModifiers[K].size(), PresentModifierLocs[K]); } // Mark taskgroup task_reduction descriptors as implicitly firstprivate. for (OMPClause *C : Clauses) { if (auto *IRC = dyn_cast(C)) { for (Expr *E : IRC->taskgroup_descriptors()) if (E) - ImplicitFirstprivates.emplace_back(E); + ImpInfo.Firstprivates.insert(E); } // OpenMP 5.0, 2.10.1 task Construct // [detach clause]... The event-handle will be considered as if it was // specified on a firstprivate clause. if (auto *DC = dyn_cast(C)) - ImplicitFirstprivates.push_back(DC->getEventHandler()); + ImpInfo.Firstprivates.insert(DC->getEventHandler()); } - if (!ImplicitFirstprivates.empty()) { + if (!ImpInfo.Firstprivates.empty()) { if (OMPClause *Implicit = ActOnOpenMPFirstprivateClause( - ImplicitFirstprivates, SourceLocation(), SourceLocation(), - SourceLocation())) { + ImpInfo.Firstprivates.getArrayRef(), SourceLocation(), + SourceLocation(), SourceLocation())) { ClausesWithImplicit.push_back(Implicit); ErrorFound = cast(Implicit)->varlist_size() != - ImplicitFirstprivates.size(); + ImpInfo.Firstprivates.size(); } else { ErrorFound = true; } } - if (!ImplicitPrivates.empty()) { - if (OMPClause *Implicit = - ActOnOpenMPPrivateClause(ImplicitPrivates, SourceLocation(), - SourceLocation(), SourceLocation())) { + if (!ImpInfo.Privates.empty()) { + if (OMPClause *Implicit = ActOnOpenMPPrivateClause( + ImpInfo.Privates.getArrayRef(), SourceLocation(), + SourceLocation(), SourceLocation())) { ClausesWithImplicit.push_back(Implicit); ErrorFound = cast(Implicit)->varlist_size() != - ImplicitPrivates.size(); + ImpInfo.Privates.size(); } else { ErrorFound = true; } @@ -6152,9 +6136,10 @@ StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective( ClausesWithImplicit.emplace_back(Implicit); } } - for (unsigned I = 0, E = DefaultmapKindNum; I < E; ++I) { + for (unsigned I = 0; I < VariableImplicitInfo::DefaultmapKindNum; ++I) { int ClauseKindCnt = -1; - for (ArrayRef ImplicitMap : ImplicitMaps[I]) { + for (unsigned J = 0; J < VariableImplicitInfo::MapKindNum; ++J) { + ArrayRef ImplicitMap = ImpInfo.Mappings[I][J].getArrayRef(); ++ClauseKindCnt; if (ImplicitMap.empty()) continue; @@ -6162,7 +6147,7 @@ StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective( DeclarationNameInfo MapperId; auto K = static_cast(ClauseKindCnt); if (OMPClause *Implicit = ActOnOpenMPMapClause( - nullptr, ImplicitMapModifiers[I], ImplicitMapModifiersLoc[I], + nullptr, ImpInfo.MapModifiers[I], ImplicitMapModifiersLoc[I], MapperIdScopeSpec, MapperId, K, /*IsMapTypeImplicit=*/true, SourceLocation(), SourceLocation(), ImplicitMap, OMPVarListLocTy())) { diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index bf6b53700d90eb..513f83146fb59e 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -3302,8 +3302,8 @@ Sema::findFailedBooleanCondition(Expr *Cond) { QualType Sema::CheckTemplateIdType(TemplateName Name, SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs) { - DependentTemplateName *DTN - = Name.getUnderlying().getAsDependentTemplateName(); + DependentTemplateName *DTN = + Name.getUnderlying().getAsDependentTemplateName(); if (DTN && DTN->isIdentifier()) // When building a template-id where the template-name is dependent, // assume the template is a type template. Either our assumption is @@ -3314,10 +3314,11 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, TemplateArgs.arguments()); if (Name.getAsAssumedTemplateName() && - resolveAssumedTemplateNameAsType(/*Scope*/nullptr, Name, TemplateLoc)) + resolveAssumedTemplateNameAsType(/*Scope=*/nullptr, Name, TemplateLoc)) return QualType(); - TemplateDecl *Template = Name.getAsTemplateDecl(); + auto [Template, DefaultArgs] = Name.getTemplateDeclAndDefaultArgs(); + if (!Template || isa(Template) || isa(Template) || isa(Template)) { // We might have a substituted template template parameter pack. If so, @@ -3335,8 +3336,9 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, // Check that the template argument list is well-formed for this // template. SmallVector SugaredConverted, CanonicalConverted; - if (CheckTemplateArgumentList(Template, TemplateLoc, TemplateArgs, false, - SugaredConverted, CanonicalConverted, + if (CheckTemplateArgumentList(Template, TemplateLoc, TemplateArgs, + DefaultArgs, false, SugaredConverted, + CanonicalConverted, /*UpdateArgsWithConversions=*/true)) return QualType(); @@ -4012,7 +4014,8 @@ DeclResult Sema::ActOnVarTemplateSpecialization( // template. SmallVector SugaredConverted, CanonicalConverted; if (CheckTemplateArgumentList(VarTemplate, TemplateNameLoc, TemplateArgs, - false, SugaredConverted, CanonicalConverted, + /*DefaultArgs=*/{}, false, SugaredConverted, + CanonicalConverted, /*UpdateArgsWithConversions=*/true)) return true; @@ -4179,8 +4182,8 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc, SmallVector SugaredConverted, CanonicalConverted; if (CheckTemplateArgumentList( Template, TemplateNameLoc, - const_cast(TemplateArgs), false, - SugaredConverted, CanonicalConverted, + const_cast(TemplateArgs), + /*DefaultArgs=*/{}, false, SugaredConverted, CanonicalConverted, /*UpdateArgsWithConversions=*/true)) return true; @@ -4374,6 +4377,7 @@ Sema::CheckConceptTemplateId(const CXXScopeSpec &SS, if (CheckTemplateArgumentList( NamedConcept, ConceptNameInfo.getLoc(), const_cast(*TemplateArgs), + /*DefaultArgs=*/{}, /*PartialTemplateArgs=*/false, SugaredConverted, CanonicalConverted, /*UpdateArgsWithConversions=*/false)) return ExprError(); @@ -5299,7 +5303,8 @@ static bool diagnoseMissingArgument(Sema &S, SourceLocation Loc, /// for specializing the given template. bool Sema::CheckTemplateArgumentList( TemplateDecl *Template, SourceLocation TemplateLoc, - TemplateArgumentListInfo &TemplateArgs, bool PartialTemplateArgs, + TemplateArgumentListInfo &TemplateArgs, const DefaultArguments &DefaultArgs, + bool PartialTemplateArgs, SmallVectorImpl &SugaredConverted, SmallVectorImpl &CanonicalConverted, bool UpdateArgsWithConversions, bool *ConstraintsNotSatisfied, @@ -5327,9 +5332,29 @@ bool Sema::CheckTemplateArgumentList( SmallVector CanonicalArgumentPack; unsigned ArgIdx = 0, NumArgs = NewArgs.size(); LocalInstantiationScope InstScope(*this, true); - for (TemplateParameterList::iterator Param = Params->begin(), - ParamEnd = Params->end(); - Param != ParamEnd; /* increment in loop */) { + for (TemplateParameterList::iterator ParamBegin = Params->begin(), + ParamEnd = Params->end(), + Param = ParamBegin; + Param != ParamEnd; + /* increment in loop */) { + if (size_t ParamIdx = Param - ParamBegin; + DefaultArgs && ParamIdx >= DefaultArgs.StartPos) { + // All written arguments should have been consumed by this point. + assert(ArgIdx == NumArgs && "bad default argument deduction"); + // FIXME: Don't ignore parameter packs. + if (ParamIdx == DefaultArgs.StartPos && !(*Param)->isParameterPack()) { + assert(Param + DefaultArgs.Args.size() <= ParamEnd); + // Default arguments from a DeducedTemplateName are already converted. + for (const TemplateArgument &DefArg : DefaultArgs.Args) { + SugaredConverted.push_back(DefArg); + CanonicalConverted.push_back( + Context.getCanonicalTemplateArgument(DefArg)); + ++Param; + } + continue; + } + } + // If we have an expanded parameter pack, make sure we don't have too // many arguments. if (std::optional Expansions = getExpandedPackSize(*Param)) { @@ -5543,6 +5568,7 @@ bool Sema::CheckTemplateArgumentList( CTAK_Specified)) return true; + SugaredConverted.back().setIsDefaulted(true); CanonicalConverted.back().setIsDefaulted(true); // Core issue 150 (assumed resolution): if this is a template template @@ -7126,7 +7152,7 @@ bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param, TemplateArgumentLoc &Arg, bool IsDeduced) { TemplateName Name = Arg.getArgument().getAsTemplateOrTemplatePattern(); - TemplateDecl *Template = Name.getAsTemplateDecl(); + auto [Template, DefaultArgs] = Name.getTemplateDeclAndDefaultArgs(); if (!Template) { // Any dependent template name is fine. assert(Name.isDependent() && "Non-dependent template isn't a declaration?"); @@ -7177,7 +7203,7 @@ bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param, return false; if (isTemplateTemplateParameterAtLeastAsSpecializedAs( - Params, Template, Arg.getLocation(), IsDeduced)) { + Params, Template, DefaultArgs, Arg.getLocation(), IsDeduced)) { // P2113 // C++20[temp.func.order]p2 // [...] If both deductions succeed, the partial ordering selects the @@ -8231,7 +8257,9 @@ DeclResult Sema::ActOnClassTemplateSpecialization( // template. SmallVector SugaredConverted, CanonicalConverted; if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, TemplateArgs, - false, SugaredConverted, CanonicalConverted, + /*DefaultArgs=*/{}, + /*PartialTemplateArgs=*/false, SugaredConverted, + CanonicalConverted, /*UpdateArgsWithConversions=*/true)) return true; @@ -9603,7 +9631,8 @@ DeclResult Sema::ActOnExplicitInstantiation( // template. SmallVector SugaredConverted, CanonicalConverted; if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, TemplateArgs, - false, SugaredConverted, CanonicalConverted, + /*DefaultArgs=*/{}, false, SugaredConverted, + CanonicalConverted, /*UpdateArgsWithConversions=*/true)) return true; diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 01f18e5a325197..4c88159ea4cedf 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -134,11 +134,16 @@ static bool hasSameExtendedValue(llvm::APSInt X, llvm::APSInt Y) { return X == Y; } +/// The kind of PartialOrdering we're performing template argument deduction +/// for (C++11 [temp.deduct.partial]). +enum class PartialOrderingKind { None, NonCall, Call }; + static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( Sema &S, TemplateParameterList *TemplateParams, QualType Param, QualType Arg, TemplateDeductionInfo &Info, SmallVectorImpl &Deduced, unsigned TDF, - bool PartialOrdering, bool DeducedFromArrayBound, bool *HasDeducedAnyParam); + PartialOrderingKind POK, bool DeducedFromArrayBound, + bool *HasDeducedAnyParam); enum class PackFold { ParameterToArgument, ArgumentToParameter }; static TemplateDeductionResult @@ -147,8 +152,8 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, ArrayRef As, TemplateDeductionInfo &Info, SmallVectorImpl &Deduced, - bool NumberOfArgumentsMustMatch, PackFold PackFold, - bool *HasDeducedAnyParam); + bool NumberOfArgumentsMustMatch, bool PartialOrdering, + PackFold PackFold, bool *HasDeducedAnyParam); static void MarkUsedTemplateParameters(ASTContext &Ctx, const TemplateArgument &TemplateArg, @@ -401,6 +406,7 @@ DeduceNonTypeTemplateArgument(Sema &S, TemplateParameterList *TemplateParams, const NonTypeTemplateParmDecl *NTTP, const DeducedTemplateArgument &NewDeduced, QualType ValueType, TemplateDeductionInfo &Info, + bool PartialOrdering, SmallVectorImpl &Deduced, bool *HasDeducedAnyParam) { assert(NTTP->getDepth() == Info.getDeducedDepth() && @@ -445,7 +451,9 @@ DeduceNonTypeTemplateArgument(Sema &S, TemplateParameterList *TemplateParams, return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, ParamType, ValueType, Info, Deduced, - TDF_SkipNonDependent, /*PartialOrdering=*/false, + TDF_SkipNonDependent, + PartialOrdering ? PartialOrderingKind::NonCall + : PartialOrderingKind::None, /*ArrayBound=*/NewDeduced.wasDeducedFromArrayBound(), HasDeducedAnyParam); } @@ -455,13 +463,13 @@ static TemplateDeductionResult DeduceNonTypeTemplateArgument( Sema &S, TemplateParameterList *TemplateParams, const NonTypeTemplateParmDecl *NTTP, const llvm::APSInt &Value, QualType ValueType, bool DeducedFromArrayBound, TemplateDeductionInfo &Info, - SmallVectorImpl &Deduced, + bool PartialOrdering, SmallVectorImpl &Deduced, bool *HasDeducedAnyParam) { return DeduceNonTypeTemplateArgument( S, TemplateParams, NTTP, DeducedTemplateArgument(S.Context, Value, ValueType, DeducedFromArrayBound), - ValueType, Info, Deduced, HasDeducedAnyParam); + ValueType, Info, PartialOrdering, Deduced, HasDeducedAnyParam); } /// Deduce the value of the given non-type template parameter @@ -470,6 +478,7 @@ static TemplateDeductionResult DeduceNullPtrTemplateArgument(Sema &S, TemplateParameterList *TemplateParams, const NonTypeTemplateParmDecl *NTTP, QualType NullPtrType, TemplateDeductionInfo &Info, + bool PartialOrdering, SmallVectorImpl &Deduced, bool *HasDeducedAnyParam) { Expr *Value = S.ImpCastExprToType( @@ -481,7 +490,7 @@ DeduceNullPtrTemplateArgument(Sema &S, TemplateParameterList *TemplateParams, .get(); return DeduceNonTypeTemplateArgument( S, TemplateParams, NTTP, DeducedTemplateArgument(Value), Value->getType(), - Info, Deduced, HasDeducedAnyParam); + Info, PartialOrdering, Deduced, HasDeducedAnyParam); } /// Deduce the value of the given non-type template parameter @@ -491,12 +500,12 @@ DeduceNullPtrTemplateArgument(Sema &S, TemplateParameterList *TemplateParams, static TemplateDeductionResult DeduceNonTypeTemplateArgument(Sema &S, TemplateParameterList *TemplateParams, const NonTypeTemplateParmDecl *NTTP, Expr *Value, - TemplateDeductionInfo &Info, + TemplateDeductionInfo &Info, bool PartialOrdering, SmallVectorImpl &Deduced, bool *HasDeducedAnyParam) { return DeduceNonTypeTemplateArgument( S, TemplateParams, NTTP, DeducedTemplateArgument(Value), Value->getType(), - Info, Deduced, HasDeducedAnyParam); + Info, PartialOrdering, Deduced, HasDeducedAnyParam); } /// Deduce the value of the given non-type template parameter @@ -507,76 +516,21 @@ static TemplateDeductionResult DeduceNonTypeTemplateArgument(Sema &S, TemplateParameterList *TemplateParams, const NonTypeTemplateParmDecl *NTTP, ValueDecl *D, QualType T, TemplateDeductionInfo &Info, + bool PartialOrdering, SmallVectorImpl &Deduced, bool *HasDeducedAnyParam) { TemplateArgument New(D, T); - return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, - DeducedTemplateArgument(New), T, Info, - Deduced, HasDeducedAnyParam); -} - -/// Create a shallow copy of a given template parameter declaration, with -/// empty source locations and using the given TemplateArgument as it's -/// default argument. -/// -/// \returns The new template parameter declaration. -static NamedDecl *getTemplateParameterWithDefault(Sema &S, NamedDecl *A, - TemplateArgument Default) { - switch (A->getKind()) { - case Decl::TemplateTypeParm: { - auto *T = cast(A); - auto *R = TemplateTypeParmDecl::Create( - S.Context, A->getDeclContext(), SourceLocation(), SourceLocation(), - T->getDepth(), T->getIndex(), T->getIdentifier(), - T->wasDeclaredWithTypename(), T->isParameterPack(), - T->hasTypeConstraint()); - R->setDefaultArgument( - S.Context, - S.getTrivialTemplateArgumentLoc(Default, QualType(), SourceLocation())); - if (R->hasTypeConstraint()) { - auto *C = R->getTypeConstraint(); - R->setTypeConstraint(C->getConceptReference(), - C->getImmediatelyDeclaredConstraint()); - } - return R; - } - case Decl::NonTypeTemplateParm: { - auto *T = cast(A); - auto *R = NonTypeTemplateParmDecl::Create( - S.Context, A->getDeclContext(), SourceLocation(), SourceLocation(), - T->getDepth(), T->getIndex(), T->getIdentifier(), T->getType(), - T->isParameterPack(), T->getTypeSourceInfo()); - R->setDefaultArgument(S.Context, - S.getTrivialTemplateArgumentLoc( - Default, Default.getNonTypeTemplateArgumentType(), - SourceLocation())); - if (auto *PTC = T->getPlaceholderTypeConstraint()) - R->setPlaceholderTypeConstraint(PTC); - return R; - } - case Decl::TemplateTemplateParm: { - auto *T = cast(A); - auto *R = TemplateTemplateParmDecl::Create( - S.Context, A->getDeclContext(), SourceLocation(), T->getDepth(), - T->getIndex(), T->isParameterPack(), T->getIdentifier(), - T->wasDeclaredWithTypename(), T->getTemplateParameters()); - R->setDefaultArgument( - S.Context, - S.getTrivialTemplateArgumentLoc(Default, QualType(), SourceLocation())); - return R; - } - default: - llvm_unreachable("Unexpected Decl Kind"); - } + return DeduceNonTypeTemplateArgument( + S, TemplateParams, NTTP, DeducedTemplateArgument(New), T, Info, + PartialOrdering, Deduced, HasDeducedAnyParam); } -static TemplateDeductionResult -DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, - TemplateName Param, TemplateName Arg, - TemplateDeductionInfo &Info, - ArrayRef DefaultArguments, - SmallVectorImpl &Deduced, - bool *HasDeducedAnyParam) { +static TemplateDeductionResult DeduceTemplateArguments( + Sema &S, TemplateParameterList *TemplateParams, TemplateName Param, + TemplateName Arg, TemplateDeductionInfo &Info, + ArrayRef DefaultArguments, bool PartialOrdering, + SmallVectorImpl &Deduced, + bool *HasDeducedAnyParam) { TemplateDecl *ParamDecl = Param.getAsTemplateDecl(); if (!ParamDecl) { // The parameter type is dependent and is not a template template parameter, @@ -589,42 +543,30 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, if (TempParam->getDepth() != Info.getDeducedDepth()) return TemplateDeductionResult::Success; - auto NewDeduced = DeducedTemplateArgument(Arg); - // Provisional resolution for CWG2398: If Arg is also a template template - // param, and it names a template specialization, then we deduce a - // synthesized template template parameter based on A, but using the TS's - // arguments as defaults. - if (auto *TempArg = dyn_cast_or_null( - Arg.getAsTemplateDecl())) { - assert(!TempArg->isExpandedParameterPack()); - - TemplateParameterList *As = TempArg->getTemplateParameters(); - if (DefaultArguments.size() != 0) { - assert(DefaultArguments.size() <= As->size()); - SmallVector Params(As->size()); - for (unsigned I = 0; I < DefaultArguments.size(); ++I) - Params[I] = getTemplateParameterWithDefault(S, As->getParam(I), - DefaultArguments[I]); - for (unsigned I = DefaultArguments.size(); I < As->size(); ++I) - Params[I] = As->getParam(I); - // FIXME: We could unique these, and also the parameters, but we don't - // expect programs to contain a large enough amount of these deductions - // for that to be worthwhile. - auto *TPL = TemplateParameterList::Create( - S.Context, SourceLocation(), SourceLocation(), Params, - SourceLocation(), As->getRequiresClause()); - NewDeduced = DeducedTemplateArgument( - TemplateName(TemplateTemplateParmDecl::Create( - S.Context, TempArg->getDeclContext(), SourceLocation(), - TempArg->getDepth(), TempArg->getPosition(), - TempArg->isParameterPack(), TempArg->getIdentifier(), - TempArg->wasDeclaredWithTypename(), TPL))); + ArrayRef Params = + ParamDecl->getTemplateParameters()->asArray(); + unsigned StartPos = 0; + for (unsigned I = 0, E = std::min(Params.size(), DefaultArguments.size()); + I < E; ++I) { + if (Params[I]->isParameterPack()) { + StartPos = DefaultArguments.size(); + break; } + StartPos = I + 1; } - DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context, - Deduced[TempParam->getIndex()], - NewDeduced); + // Provisional resolution for CWG2398: If Arg names a template + // specialization, then we deduce a synthesized template name + // based on A, but using the TS's extra arguments, relative to P, as + // defaults. + DeducedTemplateArgument NewDeduced = + PartialOrdering + ? TemplateArgument(S.Context.getDeducedTemplateName( + Arg, {StartPos, DefaultArguments.drop_front(StartPos)})) + : Arg; + + DeducedTemplateArgument Result = checkDeducedTemplateArguments( + S.Context, Deduced[TempParam->getIndex()], NewDeduced); if (Result.isNull()) { Info.Param = TempParam; Info.FirstArg = Deduced[TempParam->getIndex()]; @@ -639,7 +581,8 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, } // Verify that the two template names are equivalent. - if (S.Context.hasSameTemplateName(Param, Arg)) + if (S.Context.hasSameTemplateName( + Param, Arg, /*IgnoreDeduced=*/DefaultArguments.size() != 0)) return TemplateDeductionResult::Success; // Mismatch of non-dependent template parameter to argument. @@ -681,7 +624,7 @@ static const TemplateSpecializationType *getLastTemplateSpecType(QualType QT) { static TemplateDeductionResult DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams, const QualType P, QualType A, - TemplateDeductionInfo &Info, + TemplateDeductionInfo &Info, bool PartialOrdering, SmallVectorImpl &Deduced, bool *HasDeducedAnyParam) { QualType UP = P; @@ -730,9 +673,10 @@ DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams, ->template_arguments(); // Perform template argument deduction for the template name. - if (auto Result = - DeduceTemplateArguments(S, TemplateParams, TNP, TNA, Info, - AResolved, Deduced, HasDeducedAnyParam); + if (auto Result = DeduceTemplateArguments(S, TemplateParams, TNP, TNA, Info, + /*DefaultArguments=*/AResolved, + PartialOrdering, Deduced, + HasDeducedAnyParam); Result != TemplateDeductionResult::Success) return Result; @@ -741,8 +685,8 @@ DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams, // filled in by default arguments. return DeduceTemplateArguments( S, TemplateParams, PResolved, AResolved, Info, Deduced, - /*NumberOfArgumentsMustMatch=*/false, PackFold::ParameterToArgument, - HasDeducedAnyParam); + /*NumberOfArgumentsMustMatch=*/false, PartialOrdering, + PackFold::ParameterToArgument, HasDeducedAnyParam); } // If the argument type is a class template specialization, we @@ -763,9 +707,10 @@ DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams, *NNS, false, TemplateName(SA->getSpecializedTemplate())); // Perform template argument deduction for the template name. - if (auto Result = DeduceTemplateArguments(S, TemplateParams, TNP, TNA, Info, - SA->getTemplateArgs().asArray(), - Deduced, HasDeducedAnyParam); + if (auto Result = DeduceTemplateArguments( + S, TemplateParams, TNP, TNA, Info, + /*DefaultArguments=*/SA->getTemplateArgs().asArray(), PartialOrdering, + Deduced, HasDeducedAnyParam); Result != TemplateDeductionResult::Success) return Result; @@ -773,7 +718,7 @@ DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams, return DeduceTemplateArguments(S, TemplateParams, PResolved, SA->getTemplateArgs().asArray(), Info, Deduced, /*NumberOfArgumentsMustMatch=*/true, - PackFold::ParameterToArgument, + PartialOrdering, PackFold::ParameterToArgument, HasDeducedAnyParam); } @@ -1189,7 +1134,7 @@ template static TemplateDeductionResult DeduceForEachType( Sema &S, TemplateParameterList *TemplateParams, ArrayRef Params, ArrayRef Args, TemplateDeductionInfo &Info, - SmallVectorImpl &Deduced, bool PartialOrdering, + SmallVectorImpl &Deduced, PartialOrderingKind POK, bool FinishingDeduction, T &&DeductFunc) { // C++0x [temp.deduct.type]p10: // Similarly, if P has a form that contains (T), then each parameter type @@ -1219,8 +1164,7 @@ static TemplateDeductionResult DeduceForEachType( if (TemplateDeductionResult Result = DeductFunc(S, TemplateParams, ParamIdx, ArgIdx, Params[ParamIdx].getUnqualifiedType(), - Args[ArgIdx].getUnqualifiedType(), Info, Deduced, - PartialOrdering); + Args[ArgIdx].getUnqualifiedType(), Info, Deduced, POK); Result != TemplateDeductionResult::Success) return Result; @@ -1248,7 +1192,7 @@ static TemplateDeductionResult DeduceForEachType( if (TemplateDeductionResult Result = DeductFunc( S, TemplateParams, ParamIdx, ArgIdx, Pattern.getUnqualifiedType(), Args[ArgIdx].getUnqualifiedType(), - Info, Deduced, PartialOrdering); + Info, Deduced, POK); Result != TemplateDeductionResult::Success) return Result; PackScope.nextPackElement(); @@ -1292,7 +1236,7 @@ static TemplateDeductionResult DeduceForEachType( // During partial ordering, if Ai was originally a function parameter pack: // - if P does not contain a function parameter type corresponding to Ai then // Ai is ignored; - if (PartialOrdering && ArgIdx + 1 == Args.size() && + if (POK == PartialOrderingKind::Call && ArgIdx + 1 == Args.size() && isa(Args[ArgIdx])) return TemplateDeductionResult::Success; @@ -1339,18 +1283,18 @@ static TemplateDeductionResult DeduceTemplateArguments( Sema &S, TemplateParameterList *TemplateParams, ArrayRef Params, ArrayRef Args, TemplateDeductionInfo &Info, SmallVectorImpl &Deduced, unsigned TDF, - bool PartialOrdering, bool *HasDeducedAnyParam, + PartialOrderingKind POK, bool *HasDeducedAnyParam, llvm::SmallBitVector *HasDeducedParam) { return ::DeduceForEachType( - S, TemplateParams, Params, Args, Info, Deduced, PartialOrdering, + S, TemplateParams, Params, Args, Info, Deduced, POK, /*FinishingDeduction=*/false, [&](Sema &S, TemplateParameterList *TemplateParams, int ParamIdx, int ArgIdx, QualType P, QualType A, TemplateDeductionInfo &Info, SmallVectorImpl &Deduced, - bool PartialOrdering) { + PartialOrderingKind POK) { bool HasDeducedAnyParamCopy = false; TemplateDeductionResult TDR = DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, P, A, Info, Deduced, TDF, PartialOrdering, + S, TemplateParams, P, A, Info, Deduced, TDF, POK, /*DeducedFromArrayBound=*/false, &HasDeducedAnyParamCopy); if (HasDeducedAnyParam && HasDeducedAnyParamCopy) *HasDeducedAnyParam = true; @@ -1454,7 +1398,7 @@ static bool isForwardingReference(QualType Param, unsigned FirstInnerIndex) { static TemplateDeductionResult DeduceTemplateBases(Sema &S, const CXXRecordDecl *RD, TemplateParameterList *TemplateParams, QualType P, - TemplateDeductionInfo &Info, + TemplateDeductionInfo &Info, bool PartialOrdering, SmallVectorImpl &Deduced, bool *HasDeducedAnyParam) { // C++14 [temp.deduct.call] p4b3: @@ -1507,9 +1451,9 @@ DeduceTemplateBases(Sema &S, const CXXRecordDecl *RD, Deduced.end()); TemplateDeductionInfo BaseInfo(TemplateDeductionInfo::ForBase, Info); bool HasDeducedAnyParamCopy = false; - TemplateDeductionResult BaseResult = - DeduceTemplateSpecArguments(S, TemplateParams, P, NextT, BaseInfo, - DeducedCopy, &HasDeducedAnyParamCopy); + TemplateDeductionResult BaseResult = DeduceTemplateSpecArguments( + S, TemplateParams, P, NextT, BaseInfo, PartialOrdering, DeducedCopy, + &HasDeducedAnyParamCopy); // If this was a successful deduction, add it to the list of matches, // otherwise we need to continue searching its bases. @@ -1555,6 +1499,14 @@ DeduceTemplateBases(Sema &S, const CXXRecordDecl *RD, return TemplateDeductionResult::Success; } +/// When propagating a partial ordering kind into a NonCall context, +/// this is used to downgrade a 'Call' into a 'NonCall', so that +/// the kind still reflects whether we are in a partial ordering context. +static PartialOrderingKind +degradeCallPartialOrderingKind(PartialOrderingKind POK) { + return std::min(POK, PartialOrderingKind::NonCall); +} + /// Deduce the template arguments by comparing the parameter type and /// the argument type (C++ [temp.deduct.type]). /// @@ -1583,7 +1535,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( Sema &S, TemplateParameterList *TemplateParams, QualType P, QualType A, TemplateDeductionInfo &Info, SmallVectorImpl &Deduced, unsigned TDF, - bool PartialOrdering, bool DeducedFromArrayBound, + PartialOrderingKind POK, bool DeducedFromArrayBound, bool *HasDeducedAnyParam) { // If the argument type is a pack expansion, look at its pattern. @@ -1592,7 +1544,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( A = AExp->getPattern(); assert(!isa(A.getCanonicalType())); - if (PartialOrdering) { + if (POK == PartialOrderingKind::Call) { // C++11 [temp.deduct.partial]p5: // Before the partial ordering is done, certain transformations are // performed on the types used for partial ordering: @@ -1866,7 +1818,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( return TemplateDeductionResult::NonDeducedMismatch; return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, CP->getElementType(), CA->getElementType(), Info, - Deduced, TDF, /*PartialOrdering=*/false, + Deduced, TDF, degradeCallPartialOrderingKind(POK), /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); } @@ -1877,7 +1829,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( return TemplateDeductionResult::NonDeducedMismatch; return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, PA->getValueType(), AA->getValueType(), Info, - Deduced, TDF, /*PartialOrdering=*/false, + Deduced, TDF, degradeCallPartialOrderingKind(POK), /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); } @@ -1895,8 +1847,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, P->castAs()->getPointeeType(), PointeeType, Info, Deduced, TDF & (TDF_IgnoreQualifiers | TDF_DerivedClass), - /*PartialOrdering=*/false, /*DeducedFromArrayBound=*/false, - HasDeducedAnyParam); + degradeCallPartialOrderingKind(POK), + /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); } // T & @@ -1908,7 +1860,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, RP->getPointeeType(), RA->getPointeeType(), Info, - Deduced, 0, /*PartialOrdering=*/false, + Deduced, 0, degradeCallPartialOrderingKind(POK), /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); } @@ -1921,7 +1873,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, RP->getPointeeType(), RA->getPointeeType(), Info, - Deduced, 0, /*PartialOrdering=*/false, + Deduced, 0, degradeCallPartialOrderingKind(POK), /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); } @@ -1936,7 +1888,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, IAP->getElementType(), IAA->getElementType(), Info, - Deduced, TDF & TDF_IgnoreQualifiers, /*PartialOrdering=*/false, + Deduced, TDF & TDF_IgnoreQualifiers, + degradeCallPartialOrderingKind(POK), /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); } @@ -1950,7 +1903,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, CAP->getElementType(), CAA->getElementType(), Info, - Deduced, TDF & TDF_IgnoreQualifiers, /*PartialOrdering=*/false, + Deduced, TDF & TDF_IgnoreQualifiers, + degradeCallPartialOrderingKind(POK), /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); } @@ -1966,7 +1920,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( if (auto Result = DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, DAP->getElementType(), AA->getElementType(), Info, Deduced, TDF & TDF_IgnoreQualifiers, - /*PartialOrdering=*/false, + degradeCallPartialOrderingKind(POK), /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); Result != TemplateDeductionResult::Success) return Result; @@ -1985,13 +1939,14 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( llvm::APSInt Size(CAA->getSize()); return DeduceNonTypeTemplateArgument( S, TemplateParams, NTTP, Size, S.Context.getSizeType(), - /*ArrayBound=*/true, Info, Deduced, HasDeducedAnyParam); + /*ArrayBound=*/true, Info, POK != PartialOrderingKind::None, + Deduced, HasDeducedAnyParam); } if (const auto *DAA = dyn_cast(AA)) if (DAA->getSizeExpr()) - return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, - DAA->getSizeExpr(), Info, - Deduced, HasDeducedAnyParam); + return DeduceNonTypeTemplateArgument( + S, TemplateParams, NTTP, DAA->getSizeExpr(), Info, + POK != PartialOrderingKind::None, Deduced, HasDeducedAnyParam); // Incomplete type does not match a dependently-sized array type return TemplateDeductionResult::NonDeducedMismatch; @@ -2014,8 +1969,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // Check return types. if (auto Result = DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, FPP->getReturnType(), FPA->getReturnType(), - Info, Deduced, 0, - /*PartialOrdering=*/false, + Info, Deduced, 0, degradeCallPartialOrderingKind(POK), /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); Result != TemplateDeductionResult::Success) return Result; @@ -2023,8 +1977,9 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // Check parameter types. if (auto Result = DeduceTemplateArguments( S, TemplateParams, FPP->param_types(), FPA->param_types(), Info, - Deduced, TDF & TDF_TopLevelParameterTypeList, PartialOrdering, - HasDeducedAnyParam, /*HasDeducedParam=*/nullptr); + Deduced, TDF & TDF_TopLevelParameterTypeList, POK, + HasDeducedAnyParam, + /*HasDeducedParam=*/nullptr); Result != TemplateDeductionResult::Success) return Result; @@ -2052,14 +2007,14 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // FIXME: Should we? return DeduceNonTypeTemplateArgument( S, TemplateParams, NTTP, Noexcept, S.Context.BoolTy, - /*DeducedFromArrayBound=*/true, Info, Deduced, - HasDeducedAnyParam); + /*DeducedFromArrayBound=*/true, Info, + POK != PartialOrderingKind::None, Deduced, HasDeducedAnyParam); case CT_Dependent: if (Expr *ArgNoexceptExpr = FPA->getNoexceptExpr()) - return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, - ArgNoexceptExpr, Info, Deduced, - HasDeducedAnyParam); + return DeduceNonTypeTemplateArgument( + S, TemplateParams, NTTP, ArgNoexceptExpr, Info, + POK != PartialOrderingKind::None, Deduced, HasDeducedAnyParam); // Can't deduce anything from throw(T...). break; } @@ -2086,13 +2041,15 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // arguments from the template-id. if (!(TDF & TDF_DerivedClass) || !A->isRecordType()) return DeduceTemplateSpecArguments(S, TemplateParams, P, A, Info, + POK != PartialOrderingKind::None, Deduced, HasDeducedAnyParam); SmallVector DeducedOrig(Deduced.begin(), Deduced.end()); - auto Result = DeduceTemplateSpecArguments(S, TemplateParams, P, A, Info, - Deduced, HasDeducedAnyParam); + auto Result = DeduceTemplateSpecArguments( + S, TemplateParams, P, A, Info, POK != PartialOrderingKind::None, + Deduced, HasDeducedAnyParam); if (Result == TemplateDeductionResult::Success) return Result; @@ -2111,6 +2068,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // Check bases according to C++14 [temp.deduct.call] p4b3: auto BaseResult = DeduceTemplateBases(S, RD, TemplateParams, P, Info, + POK != PartialOrderingKind::None, Deduced, HasDeducedAnyParam); return BaseResult != TemplateDeductionResult::Invalid ? BaseResult : Result; @@ -2143,15 +2101,15 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( unsigned SubTDF = TDF & TDF_IgnoreQualifiers; if (auto Result = DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, PPT, APT, Info, Deduced, SubTDF, - /*PartialOrdering=*/false, /*DeducedFromArrayBound=*/false, - HasDeducedAnyParam); + degradeCallPartialOrderingKind(POK), + /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); Result != TemplateDeductionResult::Success) return Result; return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, QualType(MPP->getClass(), 0), QualType(MPA->getClass(), 0), Info, Deduced, SubTDF, - /*PartialOrdering=*/false, /*DeducedFromArrayBound=*/false, - HasDeducedAnyParam); + degradeCallPartialOrderingKind(POK), + /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); } // (clang extension) @@ -2166,7 +2124,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( return TemplateDeductionResult::NonDeducedMismatch; return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, BPP->getPointeeType(), BPA->getPointeeType(), Info, - Deduced, 0, /*PartialOrdering=*/false, + Deduced, 0, degradeCallPartialOrderingKind(POK), /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); } @@ -2192,8 +2150,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // Perform deduction on the element types. return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, VP->getElementType(), ElementType, Info, Deduced, - TDF, /*PartialOrdering=*/false, /*DeducedFromArrayBound=*/false, - HasDeducedAnyParam); + TDF, degradeCallPartialOrderingKind(POK), + /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); } case Type::DependentVector: { @@ -2203,7 +2161,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // Perform deduction on the element types. if (auto Result = DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, VP->getElementType(), VA->getElementType(), - Info, Deduced, TDF, /*PartialOrdering=*/false, + Info, Deduced, TDF, degradeCallPartialOrderingKind(POK), /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); Result != TemplateDeductionResult::Success) return Result; @@ -2219,16 +2177,17 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // Note that we use the "array bound" rules here; just like in that // case, we don't have any particular type for the vector size, but // we can provide one if necessary. - return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, ArgSize, - S.Context.UnsignedIntTy, true, - Info, Deduced, HasDeducedAnyParam); + return DeduceNonTypeTemplateArgument( + S, TemplateParams, NTTP, ArgSize, S.Context.UnsignedIntTy, true, + Info, POK != PartialOrderingKind::None, Deduced, + HasDeducedAnyParam); } if (const auto *VA = A->getAs()) { // Perform deduction on the element types. if (auto Result = DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, VP->getElementType(), VA->getElementType(), - Info, Deduced, TDF, /*PartialOrdering=*/false, + Info, Deduced, TDF, degradeCallPartialOrderingKind(POK), /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); Result != TemplateDeductionResult::Success) return Result; @@ -2239,9 +2198,9 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( if (!NTTP) return TemplateDeductionResult::Success; - return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, - VA->getSizeExpr(), Info, Deduced, - HasDeducedAnyParam); + return DeduceNonTypeTemplateArgument( + S, TemplateParams, NTTP, VA->getSizeExpr(), Info, + POK != PartialOrderingKind::None, Deduced, HasDeducedAnyParam); } return TemplateDeductionResult::NonDeducedMismatch; @@ -2257,7 +2216,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // Perform deduction on the element types. if (auto Result = DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, VP->getElementType(), VA->getElementType(), - Info, Deduced, TDF, /*PartialOrdering=*/false, + Info, Deduced, TDF, degradeCallPartialOrderingKind(POK), /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); Result != TemplateDeductionResult::Success) return Result; @@ -2273,16 +2232,16 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // Note that we use the "array bound" rules here; just like in that // case, we don't have any particular type for the vector size, but // we can provide one if necessary. - return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, ArgSize, - S.Context.IntTy, true, Info, - Deduced, HasDeducedAnyParam); + return DeduceNonTypeTemplateArgument( + S, TemplateParams, NTTP, ArgSize, S.Context.IntTy, true, Info, + POK != PartialOrderingKind::None, Deduced, HasDeducedAnyParam); } if (const auto *VA = A->getAs()) { // Perform deduction on the element types. if (auto Result = DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, VP->getElementType(), VA->getElementType(), - Info, Deduced, TDF, /*PartialOrdering=*/false, + Info, Deduced, TDF, degradeCallPartialOrderingKind(POK), /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); Result != TemplateDeductionResult::Success) return Result; @@ -2293,9 +2252,9 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( if (!NTTP) return TemplateDeductionResult::Success; - return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, - VA->getSizeExpr(), Info, Deduced, - HasDeducedAnyParam); + return DeduceNonTypeTemplateArgument( + S, TemplateParams, NTTP, VA->getSizeExpr(), Info, + POK != PartialOrderingKind::None, Deduced, HasDeducedAnyParam); } return TemplateDeductionResult::NonDeducedMismatch; @@ -2319,7 +2278,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // Perform deduction on element types. return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, MP->getElementType(), MA->getElementType(), Info, - Deduced, TDF, /*PartialOrdering=*/false, + Deduced, TDF, degradeCallPartialOrderingKind(POK), /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); } @@ -2332,14 +2291,14 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // Check the element type of the matrixes. if (auto Result = DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, MP->getElementType(), MA->getElementType(), - Info, Deduced, TDF, /*PartialOrdering=*/false, + Info, Deduced, TDF, degradeCallPartialOrderingKind(POK), /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); Result != TemplateDeductionResult::Success) return Result; // Try to deduce a matrix dimension. auto DeduceMatrixArg = - [&S, &Info, &Deduced, &TemplateParams, &HasDeducedAnyParam]( + [&S, &Info, &Deduced, &TemplateParams, &HasDeducedAnyParam, POK]( Expr *ParamExpr, const MatrixType *A, unsigned (ConstantMatrixType::*GetArgDimension)() const, Expr *(DependentSizedMatrixType::*GetArgDimensionExpr)() const) { @@ -2376,12 +2335,13 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( ArgConst = (ACM->*GetArgDimension)(); return DeduceNonTypeTemplateArgument( S, TemplateParams, NTTP, ArgConst, S.Context.getSizeType(), - /*ArrayBound=*/true, Info, Deduced, HasDeducedAnyParam); + /*ArrayBound=*/true, Info, POK != PartialOrderingKind::None, + Deduced, HasDeducedAnyParam); } return DeduceNonTypeTemplateArgument( S, TemplateParams, NTTP, (ADM->*GetArgDimensionExpr)(), Info, - Deduced, HasDeducedAnyParam); + POK != PartialOrderingKind::None, Deduced, HasDeducedAnyParam); }; if (auto Result = DeduceMatrixArg(MP->getRowExpr(), MA, @@ -2405,7 +2365,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // Perform deduction on the pointer type. if (auto Result = DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, ASP->getPointeeType(), ASA->getPointeeType(), - Info, Deduced, TDF, /*PartialOrdering=*/false, + Info, Deduced, TDF, degradeCallPartialOrderingKind(POK), /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); Result != TemplateDeductionResult::Success) return Result; @@ -2416,9 +2376,9 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( if (!NTTP) return TemplateDeductionResult::Success; - return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, - ASA->getAddrSpaceExpr(), Info, - Deduced, HasDeducedAnyParam); + return DeduceNonTypeTemplateArgument( + S, TemplateParams, NTTP, ASA->getAddrSpaceExpr(), Info, + POK != PartialOrderingKind::None, Deduced, HasDeducedAnyParam); } if (isTargetAddressSpace(A.getAddressSpace())) { @@ -2430,8 +2390,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( if (auto Result = DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, ASP->getPointeeType(), S.Context.removeAddrSpaceQualType(A), Info, Deduced, TDF, - /*PartialOrdering=*/false, /*DeducedFromArrayBound=*/false, - HasDeducedAnyParam); + degradeCallPartialOrderingKind(POK), + /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); Result != TemplateDeductionResult::Success) return Result; @@ -2443,7 +2403,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( return DeduceNonTypeTemplateArgument( S, TemplateParams, NTTP, ArgAddressSpace, S.Context.IntTy, true, - Info, Deduced, HasDeducedAnyParam); + Info, POK != PartialOrderingKind::None, Deduced, + HasDeducedAnyParam); } return TemplateDeductionResult::NonDeducedMismatch; @@ -2463,9 +2424,9 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( llvm::APSInt ArgSize(S.Context.getTypeSize(S.Context.IntTy), false); ArgSize = IA->getNumBits(); - return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, ArgSize, - S.Context.IntTy, true, Info, - Deduced, HasDeducedAnyParam); + return DeduceNonTypeTemplateArgument( + S, TemplateParams, NTTP, ArgSize, S.Context.IntTy, true, Info, + POK != PartialOrderingKind::None, Deduced, HasDeducedAnyParam); } if (const auto *IA = A->getAs()) { @@ -2496,8 +2457,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( if (PIT->hasSelectedType()) { return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, PIT->getSelectedType(), A, Info, Deduced, TDF, - /*PartialOrdering=*/false, /*DeducedFromArrayBound=*/false, - HasDeducedAnyParam); + degradeCallPartialOrderingKind(POK), + /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); } return TemplateDeductionResult::IncompletePack; } @@ -2509,7 +2470,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( static TemplateDeductionResult DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, const TemplateArgument &P, TemplateArgument A, - TemplateDeductionInfo &Info, + TemplateDeductionInfo &Info, bool PartialOrdering, SmallVectorImpl &Deduced, bool *HasDeducedAnyParam) { // If the template argument is a pack expansion, perform template argument @@ -2526,17 +2487,21 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, if (A.getKind() == TemplateArgument::Type) return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, P.getAsType(), A.getAsType(), Info, Deduced, 0, - /*PartialOrdering=*/false, /*DeducedFromArrayBound=*/false, - HasDeducedAnyParam); + PartialOrdering ? PartialOrderingKind::NonCall + : PartialOrderingKind::None, + /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); Info.FirstArg = P; Info.SecondArg = A; return TemplateDeductionResult::NonDeducedMismatch; case TemplateArgument::Template: + // PartialOrdering does not matter here, since template specializations are + // not being deduced. if (A.getKind() == TemplateArgument::Template) return DeduceTemplateArguments( S, TemplateParams, P.getAsTemplate(), A.getAsTemplate(), Info, - /*DefaultArguments=*/{}, Deduced, HasDeducedAnyParam); + /*DefaultArguments=*/{}, /*PartialOrdering=*/false, Deduced, + HasDeducedAnyParam); Info.FirstArg = P; Info.SecondArg = A; return TemplateDeductionResult::NonDeducedMismatch; @@ -2587,20 +2552,20 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, case TemplateArgument::Integral: case TemplateArgument::Expression: case TemplateArgument::StructuralValue: - return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, - DeducedTemplateArgument(A), - A.getNonTypeTemplateArgumentType(), - Info, Deduced, HasDeducedAnyParam); + return DeduceNonTypeTemplateArgument( + S, TemplateParams, NTTP, DeducedTemplateArgument(A), + A.getNonTypeTemplateArgumentType(), Info, PartialOrdering, Deduced, + HasDeducedAnyParam); case TemplateArgument::NullPtr: - return DeduceNullPtrTemplateArgument(S, TemplateParams, NTTP, - A.getNullPtrType(), Info, Deduced, - HasDeducedAnyParam); + return DeduceNullPtrTemplateArgument( + S, TemplateParams, NTTP, A.getNullPtrType(), Info, PartialOrdering, + Deduced, HasDeducedAnyParam); case TemplateArgument::Declaration: return DeduceNonTypeTemplateArgument( S, TemplateParams, NTTP, A.getAsDecl(), A.getParamTypeForDecl(), - Info, Deduced, HasDeducedAnyParam); + Info, PartialOrdering, Deduced, HasDeducedAnyParam); case TemplateArgument::Null: case TemplateArgument::Type: @@ -2672,8 +2637,8 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, ArrayRef As, TemplateDeductionInfo &Info, SmallVectorImpl &Deduced, - bool NumberOfArgumentsMustMatch, PackFold PackFold, - bool *HasDeducedAnyParam) { + bool NumberOfArgumentsMustMatch, bool PartialOrdering, + PackFold PackFold, bool *HasDeducedAnyParam) { if (PackFold == PackFold::ArgumentToParameter) std::swap(Ps, As); // C++0x [temp.deduct.type]p9: @@ -2710,7 +2675,8 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, if (PackFold == PackFold::ArgumentToParameter) std::swap(Pi, Ai); if (auto Result = DeduceTemplateArguments(S, TemplateParams, Pi, Ai, Info, - Deduced, HasDeducedAnyParam); + PartialOrdering, Deduced, + HasDeducedAnyParam); Result != TemplateDeductionResult::Success) return Result; @@ -2742,7 +2708,8 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, std::swap(Pi, Ai); // Deduce template arguments from the pattern. if (auto Result = DeduceTemplateArguments(S, TemplateParams, Pi, Ai, Info, - Deduced, HasDeducedAnyParam); + PartialOrdering, Deduced, + HasDeducedAnyParam); Result != TemplateDeductionResult::Success) return Result; @@ -2766,7 +2733,8 @@ TemplateDeductionResult Sema::DeduceTemplateArguments( bool NumberOfArgumentsMustMatch) { return ::DeduceTemplateArguments( *this, TemplateParams, Ps, As, Info, Deduced, NumberOfArgumentsMustMatch, - PackFold::ParameterToArgument, /*HasDeducedAnyParam=*/nullptr); + /*PartialOrdering=*/false, PackFold::ParameterToArgument, + /*HasDeducedAnyParam=*/nullptr); } /// Determine whether two template arguments are the same. @@ -3291,7 +3259,7 @@ FinishTemplateArgumentDeduction( SmallVector SugaredConvertedInstArgs, CanonicalConvertedInstArgs; if (S.CheckTemplateArgumentList( - Template, Partial->getLocation(), InstArgs, false, + Template, Partial->getLocation(), InstArgs, /*DefaultArgs=*/{}, false, SugaredConvertedInstArgs, CanonicalConvertedInstArgs, /*UpdateArgsWithConversions=*/true, &ConstraintsNotSatisfied)) return ConstraintsNotSatisfied @@ -3443,7 +3411,8 @@ DeduceTemplateArguments(Sema &S, T *Partial, if (TemplateDeductionResult Result = ::DeduceTemplateArguments( S, Partial->getTemplateParameters(), Partial->getTemplateArgs().asArray(), TemplateArgs, Info, Deduced, - /*NumberOfArgumentsMustMatch=*/false, PackFold::ParameterToArgument, + /*NumberOfArgumentsMustMatch=*/false, /*PartialOrdering=*/true, + PackFold::ParameterToArgument, /*HasDeducedAnyParam=*/nullptr); Result != TemplateDeductionResult::Success) return Result; @@ -3593,8 +3562,8 @@ TemplateDeductionResult Sema::SubstituteExplicitTemplateArguments( return TemplateDeductionResult::InstantiationDepth; if (CheckTemplateArgumentList(FunctionTemplate, SourceLocation(), - ExplicitTemplateArgs, true, SugaredBuilder, - CanonicalBuilder, + ExplicitTemplateArgs, /*DefaultArgs=*/{}, true, + SugaredBuilder, CanonicalBuilder, /*UpdateArgsWithConversions=*/false) || Trap.hasErrorOccurred()) { unsigned Index = SugaredBuilder.size(); @@ -4247,7 +4216,7 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams, TemplateDeductionInfo Info(Ovl->getNameLoc()); TemplateDeductionResult Result = DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, ParamType, ArgType, Info, Deduced, TDF, - /*PartialOrdering=*/false, /*DeducedFromArrayBound=*/false, + PartialOrderingKind::None, /*DeducedFromArrayBound=*/false, /*HasDeducedAnyParam=*/nullptr); if (Result != TemplateDeductionResult::Success) continue; @@ -4434,7 +4403,7 @@ static TemplateDeductionResult DeduceFromInitializerList( llvm::APInt Size(S.Context.getIntWidth(T), ILE->getNumInits()); if (auto Result = DeduceNonTypeTemplateArgument( S, TemplateParams, NTTP, llvm::APSInt(Size), T, - /*ArrayBound=*/true, Info, Deduced, + /*ArrayBound=*/true, Info, /*PartialOrdering=*/false, Deduced, /*HasDeducedAnyParam=*/nullptr); Result != TemplateDeductionResult::Success) return Result; @@ -4480,7 +4449,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsFromCallArgument( Sema::OriginalCallArg(OrigParamType, DecomposedParam, ArgIdx, ArgType)); return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, ParamType, ArgType, Info, Deduced, TDF, - /*PartialOrdering=*/false, /*DeducedFromArrayBound=*/false, + PartialOrderingKind::None, /*DeducedFromArrayBound=*/false, /*HasDeducedAnyParam=*/nullptr); } @@ -4808,7 +4777,7 @@ TemplateDeductionResult Sema::DeduceTemplateArguments( // Deduce template arguments from the function type. if (TemplateDeductionResult Result = DeduceTemplateArgumentsByTypeMatch( *this, TemplateParams, FunctionType, ArgFunctionType, Info, Deduced, - TDF, /*PartialOrdering=*/false, /*DeducedFromArrayBound=*/false, + TDF, PartialOrderingKind::None, /*DeducedFromArrayBound=*/false, /*HasDeducedAnyParam=*/nullptr); Result != TemplateDeductionResult::Success) return Result; @@ -4987,7 +4956,7 @@ TemplateDeductionResult Sema::DeduceTemplateArguments( if (TemplateDeductionResult Result = DeduceTemplateArgumentsByTypeMatch( *this, TemplateParams, P, A, Info, Deduced, TDF, - /*PartialOrdering=*/false, /*DeducedFromArrayBound=*/false, + PartialOrderingKind::None, /*DeducedFromArrayBound=*/false, /*HasDeducedAnyParam=*/nullptr); Result != TemplateDeductionResult::Success) return Result; @@ -5125,9 +5094,9 @@ static bool CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type, TemplateArgs.addArgument(TypeLoc.getArgLoc(I)); llvm::SmallVector SugaredConverted, CanonicalConverted; - if (S.CheckTemplateArgumentList(Concept, SourceLocation(), TemplateArgs, - /*PartialTemplateArgs=*/false, - SugaredConverted, CanonicalConverted)) + if (S.CheckTemplateArgumentList( + Concept, SourceLocation(), TemplateArgs, /*DefaultArgs=*/{}, + /*PartialTemplateArgs=*/false, SugaredConverted, CanonicalConverted)) return true; MultiLevelTemplateArgumentList MLTAL(Concept, CanonicalConverted, /*Final=*/false); @@ -5278,7 +5247,8 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result, if (auto TDK = DeduceTemplateArgumentsFromCallArgument( *this, TemplateParamsSt.get(), 0, TemplArg, Init->getType(), Init->Classify(getASTContext()), Init, Info, Deduced, - OriginalCallArgs, /*Decomposed=*/true, + OriginalCallArgs, + /*Decomposed=*/true, /*ArgIdx=*/0, /*TDF=*/0); TDK != TemplateDeductionResult::Success) { if (TDK == TemplateDeductionResult::Inconsistent) { @@ -5306,8 +5276,8 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result, if (auto TDK = DeduceTemplateArgumentsFromCallArgument( *this, TemplateParamsSt.get(), 0, FuncParam, Init->getType(), Init->Classify(getASTContext()), Init, Info, Deduced, - OriginalCallArgs, /*Decomposed=*/false, /*ArgIdx=*/0, /*TDF=*/0, - FailedTSC); + OriginalCallArgs, + /*Decomposed=*/false, /*ArgIdx=*/0, /*TDF=*/0, FailedTSC); TDK != TemplateDeductionResult::Success) return DeductionFailed(TDK); } @@ -5650,8 +5620,8 @@ static bool isAtLeastAsSpecializedAs(Sema &S, SourceLocation Loc, if (TPOC != TPOC_Call) { if (DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, Proto2->getReturnType(), Proto1->getReturnType(), - Info, Deduced, TDF_None, - /*PartialOrdering=*/true, /*DeducedFromArrayBound=*/false, + Info, Deduced, TDF_None, PartialOrderingKind::Call, + /*DeducedFromArrayBound=*/false, &HasDeducedAnyParamFromReturnType) != TemplateDeductionResult::Success) return false; @@ -5661,7 +5631,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S, SourceLocation Loc, if (TPOC != TPOC_Conversion) { HasDeducedParam.resize(Args2.size()); if (DeduceTemplateArguments(S, TemplateParams, Args2, Args1, Info, Deduced, - TDF_None, /*PartialOrdering=*/true, + TDF_None, PartialOrderingKind::Call, /*HasDeducedAnyParam=*/nullptr, &HasDeducedParam) != TemplateDeductionResult::Success) @@ -5700,11 +5670,12 @@ static bool isAtLeastAsSpecializedAs(Sema &S, SourceLocation Loc, return ::DeduceForEachType( S, TemplateParams, Args2, Args1, Info, Deduced, - /*PartialOrdering=*/true, /*FinishingDeduction=*/true, + PartialOrderingKind::Call, /*FinishingDeduction=*/true, [&](Sema &S, TemplateParameterList *, int ParamIdx, int ArgIdx, QualType P, QualType A, TemplateDeductionInfo &Info, - SmallVectorImpl &Deduced, bool) { + SmallVectorImpl &Deduced, + PartialOrderingKind) { return ::CheckDeductionConsistency( S, FTD, ArgIdx, P, A, DeducedArgs, /*CheckConsistency=*/HasDeducedParam[ParamIdx]); @@ -6151,7 +6122,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S, QualType T1, QualType T2, Deduced.resize(P2->getTemplateParameters()->size()); if (DeduceTemplateArgumentsByTypeMatch( S, P2->getTemplateParameters(), T2, T1, Info, Deduced, TDF_None, - /*PartialOrdering=*/true, /*DeducedFromArrayBound=*/false, + PartialOrderingKind::Call, /*DeducedFromArrayBound=*/false, /*HasDeducedAnyParam=*/nullptr) != TemplateDeductionResult::Success) return false; @@ -6408,8 +6379,8 @@ bool Sema::isMoreSpecializedThanPrimary( } bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs( - TemplateParameterList *P, TemplateDecl *AArg, SourceLocation Loc, - bool IsDeduced) { + TemplateParameterList *P, TemplateDecl *AArg, + const DefaultArguments &DefaultArgs, SourceLocation Loc, bool IsDeduced) { // C++1z [temp.arg.template]p4: (DR 150) // A template template-parameter P is at least as specialized as a // template template-argument A if, given the following rewrite to two @@ -6457,8 +6428,9 @@ bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs( // If the rewrite produces an invalid type, then P is not at least as // specialized as A. SmallVector SugaredPArgs; - if (CheckTemplateArgumentList(AArg, Loc, PArgList, false, SugaredPArgs, - PArgs, /*UpdateArgsWithConversions=*/true, + if (CheckTemplateArgumentList(AArg, Loc, PArgList, DefaultArgs, false, + SugaredPArgs, PArgs, + /*UpdateArgsWithConversions=*/true, /*ConstraintsNotSatisfied=*/nullptr, /*PartialOrderTTP=*/true) || Trap.hasErrorOccurred()) @@ -6483,6 +6455,7 @@ bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs( // currently implemented as a special case elsewhere. if (::DeduceTemplateArguments(*this, A, AArgs, PArgs, Info, Deduced, /*NumberOfArgumentsMustMatch=*/false, + /*PartialOrdering=*/true, IsDeduced ? PackFold::ArgumentToParameter : PackFold::ParameterToArgument, /*HasDeducedAnyParam=*/nullptr) != diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 51109b092d7568..6df412cbb09c83 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -3920,10 +3920,10 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl( // Check that the template argument list is well-formed for this // class template. SmallVector SugaredConverted, CanonicalConverted; - if (SemaRef.CheckTemplateArgumentList(InstClassTemplate, D->getLocation(), - InstTemplateArgs, false, - SugaredConverted, CanonicalConverted, - /*UpdateArgsWithConversions=*/true)) + if (SemaRef.CheckTemplateArgumentList( + InstClassTemplate, D->getLocation(), InstTemplateArgs, + /*DefaultArgs=*/{}, false, SugaredConverted, CanonicalConverted, + /*UpdateArgsWithConversions=*/true)) return nullptr; // Figure out where to insert this class template explicit specialization @@ -4028,10 +4028,10 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl( // Check that the template argument list is well-formed for this template. SmallVector SugaredConverted, CanonicalConverted; - if (SemaRef.CheckTemplateArgumentList(InstVarTemplate, D->getLocation(), - VarTemplateArgsInfo, false, - SugaredConverted, CanonicalConverted, - /*UpdateArgsWithConversions=*/true)) + if (SemaRef.CheckTemplateArgumentList( + InstVarTemplate, D->getLocation(), VarTemplateArgsInfo, + /*DefaultArgs=*/{}, false, SugaredConverted, CanonicalConverted, + /*UpdateArgsWithConversions=*/true)) return nullptr; // Check whether we've already seen a declaration of this specialization. @@ -4296,6 +4296,7 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( SmallVector SugaredConverted, CanonicalConverted; if (SemaRef.CheckTemplateArgumentList( ClassTemplate, PartialSpec->getLocation(), InstTemplateArgs, + /*DefaultArgs=*/{}, /*PartialTemplateArgs=*/false, SugaredConverted, CanonicalConverted)) return nullptr; @@ -4407,9 +4408,10 @@ TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization( // Check that the template argument list is well-formed for this // class template. SmallVector SugaredConverted, CanonicalConverted; - if (SemaRef.CheckTemplateArgumentList( - VarTemplate, PartialSpec->getLocation(), InstTemplateArgs, - /*PartialTemplateArgs=*/false, SugaredConverted, CanonicalConverted)) + if (SemaRef.CheckTemplateArgumentList(VarTemplate, PartialSpec->getLocation(), + InstTemplateArgs, /*DefaultArgs=*/{}, + /*PartialTemplateArgs=*/false, + SugaredConverted, CanonicalConverted)) return nullptr; // Check these arguments are valid for a template partial specialization. diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp index bcd31c98871e22..40522a07f6339c 100644 --- a/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -39,6 +39,10 @@ namespace { bool InLambda = false; unsigned DepthLimit = (unsigned)-1; +#ifndef NDEBUG + bool ContainsFunctionParmPackExpr = false; +#endif + void addUnexpanded(NamedDecl *ND, SourceLocation Loc = SourceLocation()) { if (auto *VD = dyn_cast(ND)) { // For now, the only problematic case is a generic lambda's templated @@ -280,6 +284,17 @@ namespace { return inherited::TraverseLambdaCapture(Lambda, C, Init); } + +#ifndef NDEBUG + bool TraverseFunctionParmPackExpr(FunctionParmPackExpr *) { + ContainsFunctionParmPackExpr = true; + return true; + } + + bool containsFunctionParmPackExpr() const { + return ContainsFunctionParmPackExpr; + } +#endif }; } @@ -414,16 +429,21 @@ bool Sema::DiagnoseUnexpandedParameterPack(Expr *E, if (!E->containsUnexpandedParameterPack()) return false; - // CollectUnexpandedParameterPacksVisitor does not expect to see a - // FunctionParmPackExpr, but diagnosing unexpected parameter packs may still - // see such an expression in a lambda body. - // We'll bail out early in this case to avoid triggering an assertion. - if (isa(E) && getEnclosingLambda()) - return false; - + // FunctionParmPackExprs are special: + // + // 1) they're used to model DeclRefExprs to packs that have been expanded but + // had that expansion held off in the process of transformation. + // + // 2) they always have the unexpanded dependencies but don't introduce new + // unexpanded packs. + // + // We might encounter a FunctionParmPackExpr being a full expression, which a + // larger CXXFoldExpr would expand. SmallVector Unexpanded; - CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseStmt(E); - assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs"); + CollectUnexpandedParameterPacksVisitor Visitor(Unexpanded); + Visitor.TraverseStmt(E); + assert((!Unexpanded.empty() || Visitor.containsFunctionParmPackExpr()) && + "Unable to find unexpanded parameter packs"); return DiagnoseUnexpandedParameterPacks(E->getBeginLoc(), UPPC, Unexpanded); } diff --git a/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp b/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp index 6fc16223ea8287..524a4c43abf243 100644 --- a/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp @@ -48,16 +48,6 @@ bool CheckerManager::hasPathSensitiveCheckers() const { EvalCallCheckers, EndOfTranslationUnitCheckers); } -void CheckerManager::finishedCheckerRegistration() { -#ifndef NDEBUG - // Make sure that for every event that has listeners, there is at least - // one dispatcher registered for it. - for (const auto &Event : Events) - assert(Event.second.HasDispatcher && - "No dispatcher registered for an event"); -#endif -} - void CheckerManager::reportInvalidCheckerOptionValue( const CheckerBase *C, StringRef OptionName, StringRef ExpectedValueDesc) const { diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 315d85319a85a9..fdabba46992b08 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1938,6 +1938,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::CXXRewrittenBinaryOperatorClass: case Stmt::RequiresExprClass: case Expr::CXXParenListInitExprClass: + case Stmt::EmbedExprClass: // Fall through. // Cases we intentionally don't evaluate, since they don't need @@ -2440,10 +2441,6 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, Bldr.addNodes(Dst); break; } - - case Stmt::EmbedExprClass: - llvm::report_fatal_error("Support for EmbedExpr is not implemented."); - break; } } diff --git a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp index ba29c123139016..c257a87dff385b 100644 --- a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp +++ b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp @@ -2380,8 +2380,12 @@ RegionStoreManager::bind(RegionBindingsConstRef B, Loc L, SVal V) { // Binding directly to a symbolic region should be treated as binding // to element 0. - if (const SymbolicRegion *SR = dyn_cast(R)) - R = GetElementZeroRegion(SR, SR->getPointeeStaticType()); + if (const auto *SymReg = dyn_cast(R)) { + QualType Ty = SymReg->getPointeeStaticType(); + if (Ty->isVoidType()) + Ty = StateMgr.getContext().CharTy; + R = GetElementZeroRegion(SymReg, Ty); + } assert((!isa(R) || !B.lookup(R)) && "'this' pointer is not an l-value and is not assignable"); diff --git a/clang/lib/StaticAnalyzer/Frontend/CreateCheckerManager.cpp b/clang/lib/StaticAnalyzer/Frontend/CreateCheckerManager.cpp index 21a60785eb5253..f60221ad7587e4 100644 --- a/clang/lib/StaticAnalyzer/Frontend/CreateCheckerManager.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/CreateCheckerManager.cpp @@ -28,7 +28,6 @@ CheckerManager::CheckerManager( AOptions, checkerRegistrationFns); Registry.initializeRegistry(*this); Registry.initializeManager(*this); - finishedCheckerRegistration(); } CheckerManager::CheckerManager(AnalyzerOptions &AOptions, diff --git a/clang/test/AST/ByteCode/codegen.cpp b/clang/test/AST/ByteCode/codegen.cpp index 9fac28a52d3150..12d8b5a5c548e1 100644 --- a/clang/test/AST/ByteCode/codegen.cpp +++ b/clang/test/AST/ByteCode/codegen.cpp @@ -73,3 +73,21 @@ namespace Null { // CHECK: call {{.*}} @_ZN4Null4nullEv( int S::*q = null(); } + +struct A { + A(); + ~A(); + enum E { Foo }; +}; + +A *g(); + +void f(A *a) { + A::E e1 = a->Foo; + + // CHECK: call noundef ptr @_Z1gv() + A::E e2 = g()->Foo; + // CHECK: call void @_ZN1AC1Ev( + // CHECK: call void @_ZN1AD1Ev( + A::E e3 = A().Foo; +} diff --git a/clang/test/AST/ByteCode/constexpr-vectors.cpp b/clang/test/AST/ByteCode/constexpr-vectors.cpp index 684c5810702cc3..7a65b263784586 100644 --- a/clang/test/AST/ByteCode/constexpr-vectors.cpp +++ b/clang/test/AST/ByteCode/constexpr-vectors.cpp @@ -57,6 +57,20 @@ void CharUsage() { constexpr auto H = FourCharsVecSize{1, 2, 3, 4} != 3; static_assert(H[0] == -1 && H[1] == -1 && H[2] == 0 && H[3] == -1, ""); + constexpr auto O = FourCharsVecSize{5, 0, 6, 0} && + FourCharsVecSize{5, 5, 0, 0}; + static_assert(O[0] == 1 && O[1] == 0 && O[2] == 0 && O[3] == 0, ""); + + constexpr auto P = FourCharsVecSize{5, 0, 6, 0} || + FourCharsVecSize{5, 5, 0, 0}; + static_assert(P[0] == 1 && P[1] == 1 && P[2] == 1 && P[3] == 0, ""); + + constexpr auto Q = FourCharsVecSize{5, 0, 6, 0} && 3; + static_assert(Q[0] == 1 && Q[1] == 0 && Q[2] == 1 && Q[3] == 0, ""); + + constexpr auto R = FourCharsVecSize{5, 0, 6, 0} || 3; + static_assert(R[0] == 1 && R[1] == 1 && R[2] == 1 && R[3] == 1, ""); + constexpr auto H1 = FourCharsVecSize{-1, -1, 0, -1}; constexpr auto InvH = -H1; static_assert(InvH[0] == 1 && InvH[1] == 1 && InvH[2] == 0 && InvH[3] == 1, ""); @@ -111,6 +125,21 @@ void CharExtVecUsage() { constexpr auto H = FourCharsExtVec{1, 2, 3, 4} != 3; static_assert(H[0] == -1 && H[1] == -1 && H[2] == 0 && H[3] == -1, ""); + constexpr auto O = FourCharsExtVec{5, 0, 6, 0} && + FourCharsExtVec{5, 5, 0, 0}; + static_assert(O[0] == 1 && O[1] == 0 && O[2] == 0 && O[3] == 0, ""); + + constexpr auto P = FourCharsExtVec{5, 0, 6, 0} || + FourCharsExtVec{5, 5, 0, 0}; + static_assert(P[0] == 1 && P[1] == 1 && P[2] == 1 && P[3] == 0, ""); + + constexpr auto Q = FourCharsExtVec{5, 0, 6, 0} && 3; + static_assert(Q[0] == 1 && Q[1] == 0 && Q[2] == 1 && Q[3] == 0, ""); + + constexpr auto R = FourCharsExtVec{5, 0, 6, 0} || 3; + static_assert(R[0] == 1 && R[1] == 1 && R[2] == 1 && R[3] == 1, ""); + + constexpr auto H1 = FourCharsExtVec{-1, -1, 0, -1}; constexpr auto InvH = -H1; static_assert(InvH[0] == 1 && InvH[1] == 1 && InvH[2] == 0 && InvH[3] == 1, ""); @@ -165,10 +194,33 @@ void FloatUsage() { constexpr auto H = FourFloatsVecSize{1, 2, 3, 4} != 3; static_assert(H[0] == -1 && H[1] == -1 && H[2] == 0 && H[3] == -1, ""); + constexpr auto O1 = FourFloatsVecSize{5, 0, 6, 0} && + FourFloatsVecSize{5, 5, 0, 0}; + static_assert(O1[0] == 1 && O1[1] == 0 && O1[2] == 0 && O1[3] == 0, ""); + + constexpr auto P1 = FourFloatsVecSize{5, 0, 6, 0} || + FourFloatsVecSize{5, 5, 0, 0}; + static_assert(P1[0] == 1 && P1[1] == 1 && P1[2] == 1 && P1[3] == 0, ""); + + constexpr auto Q = FourFloatsVecSize{5, 0, 6, 0} && 3; + static_assert(Q[0] == 1 && Q[1] == 0 && Q[2] == 1 && Q[3] == 0, ""); + + constexpr auto R = FourFloatsVecSize{5, 0, 6, 0} || 3; + static_assert(R[0] == 1 && R[1] == 1 && R[2] == 1 && R[3] == 1, ""); + + constexpr auto Y = FourFloatsVecSize{1.200000e+01, 1.700000e+01, -1.000000e+00, -1.000000e+00}; constexpr auto Z = -Y; static_assert(Z[0] == -1.200000e+01 && Z[1] == -1.700000e+01 && Z[2] == 1.000000e+00 && Z[3] == 1.000000e+00, ""); + constexpr auto O = FourFloatsVecSize{5, 0, 6, 0} && + FourFloatsVecSize{5, 5, 0, 0}; + static_assert(O[0] == 1 && O[1] == 0 && O[2] == 0 && O[3] == 0, ""); + + constexpr auto P = FourFloatsVecSize{5, 0, 6, 0} || + FourFloatsVecSize{5, 5, 0, 0}; + static_assert(P[0] == 1 && P[1] == 1 && P[2] == 1 && P[3] == 0, ""); + // Operator ~ is illegal on floats. constexpr auto ae = ~FourFloatsVecSize{0, 1, 8, -1}; // expected-error {{invalid argument type}} @@ -219,6 +271,20 @@ void FloatVecUsage() { constexpr auto H = FourFloatsVecSize{1, 2, 3, 4} != 3; static_assert(H[0] == -1 && H[1] == -1 && H[2] == 0 && H[3] == -1, ""); + constexpr auto O = FourFloatsVecSize{5, 0, 6, 0} && + FourFloatsVecSize{5, 5, 0, 0}; + static_assert(O[0] == 1 && O[1] == 0 && O[2] == 0 && O[3] == 0, ""); + + constexpr auto P = FourFloatsVecSize{5, 0, 6, 0} || + FourFloatsVecSize{5, 5, 0, 0}; + static_assert(P[0] == 1 && P[1] == 1 && P[2] == 1 && P[3] == 0, ""); + + constexpr auto Q = FourFloatsVecSize{5, 0, 6, 0} && 3; + static_assert(Q[0] == 1 && Q[1] == 0 && Q[2] == 1 && Q[3] == 0, ""); + + constexpr auto R = FourFloatsVecSize{5, 0, 6, 0} || 3; + static_assert(R[0] == 1 && R[1] == 1 && R[2] == 1 && R[3] == 1, ""); + constexpr auto Y = FourFloatsVecSize{1.200000e+01, 1.700000e+01, -1.000000e+00, -1.000000e+00}; constexpr auto Z = -Y; static_assert(Z[0] == -1.200000e+01 && Z[1] == -1.700000e+01 && Z[2] == 1.000000e+00 && Z[3] == 1.000000e+00, ""); @@ -234,6 +300,18 @@ void I128Usage() { constexpr auto a = FourI128VecSize{1, 2, 3, 4}; static_assert(a[0] == 1 && a[1] == 2 && a[2] == 3 && a[3] == 4, ""); + constexpr auto a1 = FourI128VecSize{5, 0, 6, 0} && FourI128VecSize{5, 5, 0, 0}; + static_assert(a1[0] == 1 && a1[1] == 0 && a1[2] == 0 && a1[3] == 0, ""); + + constexpr auto a2 = FourI128VecSize{5, 0, 6, 0} || FourI128VecSize{5, 5, 0, 0}; + static_assert(a2[0] == 1 && a2[1] == 1 && a2[2] == 1 && a2[3] == 0, ""); + + constexpr auto Q = FourI128VecSize{5, 0, 6, 0} && 3; + static_assert(Q[0] == 1 && Q[1] == 0 && Q[2] == 1 && Q[3] == 0, ""); + + constexpr auto R = FourI128VecSize{5, 0, 6, 0} || 3; + static_assert(R[0] == 1 && R[1] == 1 && R[2] == 1 && R[3] == 1, ""); + constexpr auto b = a < 3; static_assert(b[0] == -1 && b[1] == -1 && b[2] == 0 && b[3] == 0, ""); @@ -249,6 +327,18 @@ void I128VecUsage() { constexpr auto a = FourI128ExtVec{1, 2, 3, 4}; static_assert(a[0] == 1 && a[1] == 2 && a[2] == 3 && a[3] == 4, ""); + constexpr auto a1 = FourI128ExtVec{5, 0, 6, 0} && FourI128ExtVec{5, 5, 0, 0}; + static_assert(a1[0] == 1 && a1[1] == 0 && a1[2] == 0 && a1[3] == 0, ""); + + constexpr auto a2 = FourI128ExtVec{5, 0, 6, 0} || FourI128ExtVec{5, 5, 0, 0}; + static_assert(a2[0] == 1 && a2[1] == 1 && a2[2] == 1 && a2[3] == 0, ""); + + constexpr auto Q = FourI128ExtVec{5, 0, 6, 0} && 3; + static_assert(Q[0] == 1 && Q[1] == 0 && Q[2] == 1 && Q[3] == 0, ""); + + constexpr auto R = FourI128ExtVec{5, 0, 6, 0} || 3; + static_assert(R[0] == 1 && R[1] == 1 && R[2] == 1 && R[3] == 1, ""); + constexpr auto b = a < 3; static_assert(b[0] == -1 && b[1] == -1 && b[2] == 0 && b[3] == 0, ""); diff --git a/clang/test/AST/ByteCode/initializer_list.cpp b/clang/test/AST/ByteCode/initializer_list.cpp new file mode 100644 index 00000000000000..4e3b8dc9120167 --- /dev/null +++ b/clang/test/AST/ByteCode/initializer_list.cpp @@ -0,0 +1,55 @@ +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -fms-extensions -std=c++20 -verify=expected,both %s +// RUN: %clang_cc1 -std=c++20 -fms-extensions -verify=ref,both %s + +// both-no-diagnostics + +namespace std { + typedef decltype(sizeof(int)) size_t; + template + class initializer_list + { + const _E* __begin_; + size_t __size_; + + initializer_list(const _E* __b, size_t __s) + : __begin_(__b), + __size_(__s) + {} + + public: + typedef _E value_type; + typedef const _E& reference; + typedef const _E& const_reference; + typedef size_t size_type; + + typedef const _E* iterator; + typedef const _E* const_iterator; + + constexpr initializer_list() : __begin_(nullptr), __size_(0) {} + + constexpr size_t size() const {return __size_;} + constexpr const _E* begin() const {return __begin_;} + constexpr const _E* end() const {return __begin_ + __size_;} + }; +} + +class Thing { +public: + int m = 12; + constexpr Thing(int m) : m(m) {} + constexpr bool operator==(const Thing& that) const { + return this->m == that.m; + } +}; + +constexpr bool is_contained(std::initializer_list Set, const Thing &Element) { + return (*Set.begin() == Element); +} + +constexpr int foo() { + const Thing a{12}; + const Thing b{14}; + return is_contained({a}, b); +} + +static_assert(foo() == 0); diff --git a/clang/test/AST/ByteCode/new-delete.cpp b/clang/test/AST/ByteCode/new-delete.cpp index 145bb366710f9b..76858aa94bb37d 100644 --- a/clang/test/AST/ByteCode/new-delete.cpp +++ b/clang/test/AST/ByteCode/new-delete.cpp @@ -586,6 +586,138 @@ constexpr void use_after_free_2() { // both-error {{never produces a constant ex p->f(); // both-note {{member call on heap allocated object that has been deleted}} } + +/// std::allocator definition +namespace std { + using size_t = decltype(sizeof(0)); + template struct allocator { + constexpr T *allocate(size_t N) { + return (T*)__builtin_operator_new(sizeof(T) * N); // both-note 2{{allocation performed here}} + } + constexpr void deallocate(void *p) { + __builtin_operator_delete(p); // both-note 2{{std::allocator<...>::deallocate' used to delete pointer to object allocated with 'new'}} \ + // both-note {{used to delete a null pointer}} + } + }; +} + +/// Specialization for float, using operator new/delete. +namespace std { + using size_t = decltype(sizeof(0)); + template<> struct allocator { + constexpr float *allocate(size_t N) { + return (float*)operator new (sizeof(float) * N); + } + constexpr void deallocate(void *p) { + operator delete(p); + } + }; +} + +namespace OperatorNewDelete { + + constexpr bool mismatched(int alloc_kind, int dealloc_kind) { + int *p; + switch (alloc_kind) { + case 0: + p = new int; // both-note {{heap allocation performed here}} + break; + case 1: + p = new int[1]; // both-note {{heap allocation performed here}} + break; + case 2: + p = std::allocator().allocate(1); + break; + } + switch (dealloc_kind) { + case 0: + delete p; // both-note {{'delete' used to delete pointer to object allocated with 'std::allocator<...>::allocate'}} + break; + case 1: + delete[] p; // both-note {{'delete' used to delete pointer to object allocated with 'std::allocator<...>::allocate'}} + break; + case 2: + std::allocator().deallocate(p); // both-note 2{{in call}} + break; + } + return true; + } + static_assert(mismatched(0, 2)); // both-error {{constant expression}} \ + // both-note {{in call to}} + static_assert(mismatched(1, 2)); // both-error {{constant expression}} \ + // both-note {{in call to}} + static_assert(mismatched(2, 0)); // both-error {{constant expression}} \ + // both-note {{in call}} + static_assert(mismatched(2, 1)); // both-error {{constant expression}} \ + // both-note {{in call}} + static_assert(mismatched(2, 2)); + + constexpr bool zeroAlloc() { + int *F = std::allocator().allocate(0); + std::allocator().deallocate(F); + return true; + } + static_assert(zeroAlloc()); + + /// FIXME: This is broken in the current interpreter. + constexpr int arrayAlloc() { + int *F = std::allocator().allocate(2); + F[0] = 10; // ref-note {{assignment to object outside its lifetime is not allowed in a constant expression}} + F[1] = 13; + int Res = F[1] + F[0]; + std::allocator().deallocate(F); + return Res; + } + static_assert(arrayAlloc() == 23); // ref-error {{not an integral constant expression}} \ + // ref-note {{in call to}} + + struct S { + int i; + constexpr S(int i) : i(i) {} + constexpr ~S() { } + }; + + /// FIXME: This is broken in the current interpreter. + constexpr bool structAlloc() { + S *s = std::allocator().allocate(1); + + s->i = 12; // ref-note {{assignment to object outside its lifetime is not allowed in a constant expression}} + + bool Res = (s->i == 12); + std::allocator().deallocate(s); + + return Res; + } + static_assert(structAlloc()); // ref-error {{not an integral constant expression}} \ + // ref-note {{in call to}} + + constexpr bool structAllocArray() { + S *s = std::allocator().allocate(9); + + s[2].i = 12; // ref-note {{assignment to object outside its lifetime is not allowed in a constant expression}} + bool Res = (s[2].i == 12); + std::allocator().deallocate(s); + + return Res; + } + static_assert(structAllocArray()); // ref-error {{not an integral constant expression}} \ + // ref-note {{in call to}} + + constexpr bool alloc_from_user_code() { + void *p = __builtin_operator_new(sizeof(int)); // both-note {{cannot allocate untyped memory in a constant expression; use 'std::allocator::allocate'}} + __builtin_operator_delete(p); + return true; + } + static_assert(alloc_from_user_code()); // both-error {{constant expression}} \ + // both-note {{in call to}} + + + constexpr int no_deallocate_nullptr = (std::allocator().deallocate(nullptr), 1); // both-error {{constant expression}} \ + // both-note {{in call}} + + static_assert((std::allocator().deallocate(std::allocator().allocate(10)), 1) == 1); +} + #else /// Make sure we reject this prior to C++20 constexpr int a() { // both-error {{never produces a constant expression}} diff --git a/clang/test/Analysis/asm.cpp b/clang/test/Analysis/asm.cpp index b17ab04994d249..e0691dc4d794f5 100644 --- a/clang/test/Analysis/asm.cpp +++ b/clang/test/Analysis/asm.cpp @@ -2,6 +2,8 @@ // RUN: -analyzer-checker debug.ExprInspection,core -Wno-error=invalid-gnu-asm-cast -w %s -verify int clang_analyzer_eval(int); +void clang_analyzer_dump(int); +void clang_analyzer_dump_ptr(void *); int global; void testRValueOutput() { @@ -40,3 +42,13 @@ void testInlineAsmMemcpyUninit(void) MyMemcpy(&a[1], &b[1], sizeof(b) - sizeof(b[1])); c = a[0]; // expected-warning{{Assigned value is garbage or undefined}} } + +void testAsmWithVoidPtrArgument() +{ + extern void *globalVoidPtr; + clang_analyzer_dump(*(int *)globalVoidPtr); // expected-warning-re {{reg_${{[0-9]+}}},0 S64b,int}>}} + clang_analyzer_dump_ptr(globalVoidPtr); // expected-warning-re {{&SymRegion{reg_${{[0-9]+}}}}} + asm ("" : : "a"(globalVoidPtr)); // no crash + clang_analyzer_dump(*(int *)globalVoidPtr); // expected-warning {{Unknown}} + clang_analyzer_dump_ptr(globalVoidPtr); // expected-warning-re {{&SymRegion{reg_${{[0-9]+}}}}} +} diff --git a/clang/test/Analysis/embed.c b/clang/test/Analysis/embed.c new file mode 100644 index 00000000000000..32f6c130325740 --- /dev/null +++ b/clang/test/Analysis/embed.c @@ -0,0 +1,12 @@ +// RUN: %clang_analyze_cc1 -std=c23 -analyzer-checker=core,debug.ExprInspection -verify %s + +void clang_analyzer_dump_ptr(const unsigned char *ptr); +void clang_analyzer_dump(unsigned char val); + +int main() { + const unsigned char SelfBytes[] = { + #embed "embed.c" + }; + clang_analyzer_dump_ptr(SelfBytes); // expected-warning {{&Element{SelfBytes,0 S64b,unsigned char}}} + clang_analyzer_dump(SelfBytes[0]); // expected-warning {{Unknown}} FIXME: This should be the `/` character. +} diff --git a/clang/test/Analysis/nullability-nocrash.c b/clang/test/Analysis/nullability-nocrash.c new file mode 100644 index 00000000000000..209b7708250676 --- /dev/null +++ b/clang/test/Analysis/nullability-nocrash.c @@ -0,0 +1,13 @@ +// RUN: %clang_analyze_cc1 -w -analyzer-checker=nullability \ +// RUN: -analyzer-output=text -verify %s +// +// expected-no-diagnostics +// +// Previously there was an assertion requiring that if an Event is handled by +// some enabled checker, then there must be at least one enabled checker which +// can emit that kind of Event. +// This assertion failed when NullabilityChecker (which is a subclass of +// check::Event) was enabled, but the checkers +// inheriting from EventDispatcher were all disabled. +// This test file validates that enabling the nullability checkers (without any +// other checkers) no longer causes a crash. diff --git a/clang/test/CodeGen/PowerPC/transparent_union.c b/clang/test/CodeGen/PowerPC/transparent_union.c deleted file mode 100644 index 968a385c0ee45f..00000000000000 --- a/clang/test/CodeGen/PowerPC/transparent_union.c +++ /dev/null @@ -1,67 +0,0 @@ -// RUN: %clang_cc1 -triple powerpc64le-unknown-linux -O2 -target-cpu pwr7 \ -// RUN: -emit-llvm -fshort-enums %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-64 -// RUN: %clang_cc1 -triple powerpc64-unknown-linux -O2 -target-cpu pwr7 \ -// RUN: -emit-llvm -fshort-enums %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-64 -// RUN: %clang_cc1 -triple powerpc-unknown-linux -O2 -target-cpu pwr7 \ -// RUN: -emit-llvm -fshort-enums %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-32 -// RUN: %clang_cc1 -triple powerpc64-unknown-aix -O2 -target-cpu pwr7 \ -// RUN: -emit-llvm -fshort-enums %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-64 -// RUN: %clang_cc1 -triple powerpc-unknown-aix -O2 -target-cpu pwr7 \ -// RUN: -emit-llvm -fshort-enums %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-32 - -typedef union tu_c { - signed char a; - signed char b; -} tu_c_t __attribute__((transparent_union)); - -typedef union tu_s { - short a; -} tu_s_t __attribute__((transparent_union)); - -typedef union tu_us { - unsigned short a; -} tu_us_t __attribute__((transparent_union)); - -typedef union tu_l { - long a; -} tu_l_t __attribute__((transparent_union)); - -// CHECK-LABEL: define{{.*}} void @ftest0( -// CHECK-SAME: i8 noundef signext [[UC_COERCE:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: ret void -void ftest0(tu_c_t uc) { } - -// CHECK-LABEL: define{{.*}} void @ftest1( -// CHECK-SAME: i16 noundef signext [[UC_COERCE:%.*]]) local_unnamed_addr #[[ATTR0]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: ret void -void ftest1(tu_s_t uc) { } - -// CHECK-LABEL: define{{.*}} void @ftest2( -// CHECK-SAME: i16 noundef zeroext [[UC_COERCE:%.*]]) local_unnamed_addr #[[ATTR0]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: ret void -void ftest2(tu_us_t uc) { } - -// CHECK-64-LABEL: define{{.*}} void @ftest3( -// CHECK-64-SAME: i64 [[UC_COERCE:%.*]]) local_unnamed_addr #[[ATTR0]] { -// CHECK-64-NEXT: [[ENTRY:.*:]] -// CHECK-64-NEXT: ret void -// -// CHECK-32-LABEL: define{{.*}} void @ftest3( -// CHECK-32-SAME: i32 [[UC_COERCE:%.*]]) local_unnamed_addr #[[ATTR0]] { -// CHECK-32-NEXT: [[ENTRY:.*:]] -// CHECK-32-NEXT: ret void -void ftest3(tu_l_t uc) { } - -typedef union etest { - enum flag {red, yellow, blue} fl; - enum weekend {sun, sat} b; -} etest_t __attribute__((transparent_union)); - -// CHECK-LABEL: define{{.*}} void @ftest4( -// CHECK-SAME: i8 noundef zeroext [[A_COERCE:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: ret void -void ftest4(etest_t a) {} diff --git a/clang/test/CodeGen/aarch64-neon-faminmax-intrinsics.c b/clang/test/CodeGen/aarch64-neon-faminmax-intrinsics.c new file mode 100644 index 00000000000000..3ae98b5723d7c8 --- /dev/null +++ b/clang/test/CodeGen/aarch64-neon-faminmax-intrinsics.c @@ -0,0 +1,107 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5 +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon -target-feature +faminmax -O3 -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon -target-feature +faminmax -S -O3 -Werror -Wall -o /dev/null %s + +// REQUIRES: aarch64-registered-target + +#include + +// CHECK-LABEL: define dso_local <4 x half> @test_vamin_f16( +// CHECK-SAME: <4 x half> noundef [[VN:%.*]], <4 x half> noundef [[VM:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[FAMIN2_I:%.*]] = tail call <4 x half> @llvm.aarch64.neon.famin.v4f16(<4 x half> [[VN]], <4 x half> [[VM]]) +// CHECK-NEXT: ret <4 x half> [[FAMIN2_I]] +// +float16x4_t test_vamin_f16(float16x4_t vn, float16x4_t vm) { + return vamin_f16(vn, vm); +} + +// CHECK-LABEL: define dso_local <8 x half> @test_vaminq_f16( +// CHECK-SAME: <8 x half> noundef [[VN:%.*]], <8 x half> noundef [[VM:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[FAMIN2_I:%.*]] = tail call <8 x half> @llvm.aarch64.neon.famin.v8f16(<8 x half> [[VN]], <8 x half> [[VM]]) +// CHECK-NEXT: ret <8 x half> [[FAMIN2_I]] +// +float16x8_t test_vaminq_f16(float16x8_t vn, float16x8_t vm) { + return vaminq_f16(vn, vm); +} + +// CHECK-LABEL: define dso_local <2 x float> @test_vamin_f32( +// CHECK-SAME: <2 x float> noundef [[VN:%.*]], <2 x float> noundef [[VM:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[FAMIN2_I:%.*]] = tail call <2 x float> @llvm.aarch64.neon.famin.v2f32(<2 x float> [[VN]], <2 x float> [[VM]]) +// CHECK-NEXT: ret <2 x float> [[FAMIN2_I]] +// +float32x2_t test_vamin_f32(float32x2_t vn, float32x2_t vm) { + return vamin_f32(vn, vm); +} + +// CHECK-LABEL: define dso_local <4 x float> @test_vaminq_f32( +// CHECK-SAME: <4 x float> noundef [[VN:%.*]], <4 x float> noundef [[VM:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[FAMIN2_I:%.*]] = tail call <4 x float> @llvm.aarch64.neon.famin.v4f32(<4 x float> [[VN]], <4 x float> [[VM]]) +// CHECK-NEXT: ret <4 x float> [[FAMIN2_I]] +// +float32x4_t test_vaminq_f32(float32x4_t vn, float32x4_t vm) { + return vaminq_f32(vn, vm); +} + +// CHECK-LABEL: define dso_local <2 x double> @test_vaminq_f64( +// CHECK-SAME: <2 x double> noundef [[VN:%.*]], <2 x double> noundef [[VM:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[FAMIN2_I:%.*]] = tail call <2 x double> @llvm.aarch64.neon.famin.v2f64(<2 x double> [[VN]], <2 x double> [[VM]]) +// CHECK-NEXT: ret <2 x double> [[FAMIN2_I]] +// +float64x2_t test_vaminq_f64(float64x2_t vn, float64x2_t vm) { + return vaminq_f64(vn, vm); +} + +// CHECK-LABEL: define dso_local <4 x half> @test_vamax_f16( +// CHECK-SAME: <4 x half> noundef [[VN:%.*]], <4 x half> noundef [[VM:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[FAMAX2_I:%.*]] = tail call <4 x half> @llvm.aarch64.neon.famax.v4f16(<4 x half> [[VN]], <4 x half> [[VM]]) +// CHECK-NEXT: ret <4 x half> [[FAMAX2_I]] +// +float16x4_t test_vamax_f16(float16x4_t vn, float16x4_t vm) { + return vamax_f16(vn, vm); +} + +// CHECK-LABEL: define dso_local <8 x half> @test_vamaxq_f16( +// CHECK-SAME: <8 x half> noundef [[VN:%.*]], <8 x half> noundef [[VM:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[FAMAX2_I:%.*]] = tail call <8 x half> @llvm.aarch64.neon.famax.v8f16(<8 x half> [[VN]], <8 x half> [[VM]]) +// CHECK-NEXT: ret <8 x half> [[FAMAX2_I]] +// +float16x8_t test_vamaxq_f16(float16x8_t vn, float16x8_t vm) { + return vamaxq_f16(vn, vm); +} + +// CHECK-LABEL: define dso_local <2 x float> @test_vamax_f32( +// CHECK-SAME: <2 x float> noundef [[VN:%.*]], <2 x float> noundef [[VM:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[FAMAX2_I:%.*]] = tail call <2 x float> @llvm.aarch64.neon.famax.v2f32(<2 x float> [[VN]], <2 x float> [[VM]]) +// CHECK-NEXT: ret <2 x float> [[FAMAX2_I]] +// +float32x2_t test_vamax_f32(float32x2_t vn, float32x2_t vm) { + return vamax_f32(vn, vm); +} + +// CHECK-LABEL: define dso_local <4 x float> @test_vamaxq_f32( +// CHECK-SAME: <4 x float> noundef [[VN:%.*]], <4 x float> noundef [[VM:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[FAMAX2_I:%.*]] = tail call <4 x float> @llvm.aarch64.neon.famax.v4f32(<4 x float> [[VN]], <4 x float> [[VM]]) +// CHECK-NEXT: ret <4 x float> [[FAMAX2_I]] +// +float32x4_t test_vamaxq_f32(float32x4_t vn, float32x4_t vm) { + return vamaxq_f32(vn, vm); +} + +// CHECK-LABEL: define dso_local <2 x double> @test_vamaxq_f64( +// CHECK-SAME: <2 x double> noundef [[VN:%.*]], <2 x double> noundef [[VM:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[FAMAX2_I:%.*]] = tail call <2 x double> @llvm.aarch64.neon.famax.v2f64(<2 x double> [[VN]], <2 x double> [[VM]]) +// CHECK-NEXT: ret <2 x double> [[FAMAX2_I]] +// +float64x2_t test_vamaxq_f64(float64x2_t vn, float64x2_t vm) { + return vamaxq_f64(vn, vm); +} diff --git a/clang/test/CodeGen/transparent-union-type.c b/clang/test/CodeGen/transparent-union-type.c new file mode 100644 index 00000000000000..f7fac25dc09848 --- /dev/null +++ b/clang/test/CodeGen/transparent-union-type.c @@ -0,0 +1,108 @@ +// RUN: %clang_cc1 -triple powerpc64le-linux -O2 -target-cpu pwr7 -emit-llvm \ +// RUN: -fshort-enums %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-64 +// RUN: %clang_cc1 -triple powerpc64-linux -O2 -target-cpu pwr7 -emit-llvm \ +// RUN: -fshort-enums %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-64 +// RUN: %clang_cc1 -triple powerpc-linux -O2 -target-cpu pwr7 -emit-llvm \ +// RUN: -fshort-enums %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-32 +// RUN: %clang_cc1 -triple powerpc64-aix -O2 -target-cpu pwr7 -emit-llvm \ +// RUN: -fshort-enums %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-64 +// RUN: %clang_cc1 -triple powerpc-aix -O2 -target-cpu pwr7 -emit-llvm \ +// RUN: -fshort-enums %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-32 +// RUN: %clang_cc1 -triple riscv64-linux -O2 -emit-llvm -fshort-enums \ +// RUN: %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-64 +// RUN: %clang_cc1 -triple riscv32-linux -O2 -emit-llvm -fshort-enums \ +// RUN: %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-32 +// RUN: %clang_cc1 -triple i386-linux -O2 -emit-llvm -fshort-enums \ +// RUN: %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-32 +// RUN: %clang_cc1 -triple x86_64-linux -O2 -emit-llvm -fshort-enums \ +// RUN: %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-64 +// RUN: %clang_cc1 -triple armv7-linux -O2 -emit-llvm -fshort-enums \ +// RUN: %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-32 +// RUN: %clang_cc1 -triple arm64 -target-abi darwinpcs -O2 -emit-llvm \ +// RUN: -fshort-enums %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-64 +// RUN: %clang_cc1 -triple aarch64 -target-abi darwinpcs -O2 -emit-llvm \ +// RUN: -fshort-enums %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-64 + +typedef union tu_c { + signed char a; + signed char b; +} tu_c_t __attribute__((transparent_union)); + +typedef union tu_s { + short a; +} tu_s_t __attribute__((transparent_union)); + +typedef union tu_us { + unsigned short a; +} tu_us_t __attribute__((transparent_union)); + +typedef union tu_l { + long a; +} tu_l_t __attribute__((transparent_union)); + +// CHECK-LABEL: define{{.*}} void @ftest0( +// CHECK-SAME: i8 noundef signext [[UC_COERCE:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: ret void +void ftest0(tu_c_t uc) { } + +// CHECK-LABEL: define{{.*}} void @ftest1( +// CHECK-SAME: i16 noundef signext [[UC_COERCE:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: ret void +void ftest1(tu_s_t uc) { } + +// CHECK-LABEL: define{{.*}} void @ftest1b( +// CHECK-SAME: ptr nocapture noundef readnone [[UC:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: ret void +// +void ftest1b(tu_s_t *uc) { } + +// CHECK-LABEL: define{{.*}} void @ftest2( +// CHECK-SAME: i16 noundef zeroext [[UC_COERCE:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: ret void +void ftest2(tu_us_t uc) { } + +// CHECK-64-LABEL: define{{.*}} void @ftest3( +// CHECK-64-SAME: i64 [[UC_COERCE:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-64-NEXT: [[ENTRY:.*:]] +// CHECK-64-NEXT: ret void +// +// CHECK-32-LABEL: define{{.*}} void @ftest3( +// CHECK-32-SAME: i32 [[UC_COERCE:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-32-NEXT: [[ENTRY:.*:]] +// CHECK-32-NEXT: ret void +void ftest3(tu_l_t uc) { } + +typedef union etest { + enum flag {red, yellow, blue} fl; + enum weekend {sun, sat} b; +} etest_t __attribute__((transparent_union)); + +// CHECK-LABEL: define{{.*}} void @ftest4( +// CHECK-SAME: i8 noundef zeroext [[A_COERCE:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: ret void +void ftest4(etest_t a) {} + +typedef union tu_ptr { + signed char *a; + unsigned short *b; + int *c; +} tu_ptr_t __attribute__((transparent_union)); + +// CHECK-LABEL: define{{.*}} void @ftest5( +// CHECK-SAME: ptr nocapture readnone [[UC_COERCE:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: ret void +// +void ftest5(tu_ptr_t uc) { } + +// CHECK-LABEL: define{{.*}} void @ftest6( +// CHECK-SAME: ptr nocapture noundef readnone [[UC:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: ret void +// +void ftest6(tu_ptr_t *uc) { } diff --git a/clang/test/CodeGenCoroutines/Inputs/utility.h b/clang/test/CodeGenCoroutines/Inputs/utility.h new file mode 100644 index 00000000000000..43c6d27823bd47 --- /dev/null +++ b/clang/test/CodeGenCoroutines/Inputs/utility.h @@ -0,0 +1,13 @@ +// This is a mock file for + +namespace std { + +template struct remove_reference { using type = T; }; +template struct remove_reference { using type = T; }; +template struct remove_reference { using type = T; }; + +template +constexpr typename std::remove_reference::type&& move(T &&t) noexcept { + return static_cast::type &&>(t); +} +} diff --git a/clang/test/CodeGenCoroutines/coro-await-elidable.cpp b/clang/test/CodeGenCoroutines/coro-await-elidable.cpp new file mode 100644 index 00000000000000..8512995dfad45a --- /dev/null +++ b/clang/test/CodeGenCoroutines/coro-await-elidable.cpp @@ -0,0 +1,87 @@ +// This file tests the coro_await_elidable attribute semantics. +// RUN: %clang_cc1 -triple=x86_64-unknown-linux-gnu -std=c++20 -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s + +#include "Inputs/coroutine.h" +#include "Inputs/utility.h" + +template +struct [[clang::coro_await_elidable]] Task { + struct promise_type { + struct FinalAwaiter { + bool await_ready() const noexcept { return false; } + + template + std::coroutine_handle<> await_suspend(std::coroutine_handle

coro) noexcept { + if (!coro) + return std::noop_coroutine(); + return coro.promise().continuation; + } + void await_resume() noexcept {} + }; + + Task get_return_object() noexcept { + return std::coroutine_handle::from_promise(*this); + } + + std::suspend_always initial_suspend() noexcept { return {}; } + FinalAwaiter final_suspend() noexcept { return {}; } + void unhandled_exception() noexcept {} + void return_value(T x) noexcept { + value = x; + } + + std::coroutine_handle<> continuation; + T value; + }; + + Task(std::coroutine_handle handle) : handle(handle) {} + ~Task() { + if (handle) + handle.destroy(); + } + + struct Awaiter { + Awaiter(Task *t) : task(t) {} + bool await_ready() const noexcept { return false; } + void await_suspend(std::coroutine_handle continuation) noexcept {} + T await_resume() noexcept { + return task->handle.promise().value; + } + + Task *task; + }; + + auto operator co_await() { + return Awaiter{this}; + } + +private: + std::coroutine_handle handle; +}; + +// CHECK-LABEL: define{{.*}} @_Z6calleev{{.*}} { +Task callee() { + co_return 1; +} + +// CHECK-LABEL: define{{.*}} @_Z8elidablev{{.*}} { +Task elidable() { + // CHECK: %[[TASK_OBJ:.+]] = alloca %struct.Task + // CHECK: call void @_Z6calleev(ptr dead_on_unwind writable sret(%struct.Task) align 8 %[[TASK_OBJ]]) #[[ELIDE_SAFE:.+]] + co_return co_await callee(); +} + +// CHECK-LABEL: define{{.*}} @_Z11nonelidablev{{.*}} { +Task nonelidable() { + // CHECK: %[[TASK_OBJ:.+]] = alloca %struct.Task + auto t = callee(); + // Because we aren't co_awaiting a prvalue, we cannot elide here. + // CHECK: call void @_Z6calleev(ptr dead_on_unwind writable sret(%struct.Task) align 8 %[[TASK_OBJ]]) + // CHECK-NOT: #[[ELIDE_SAFE]] + co_await t; + co_await std::move(t); + + co_return 1; +} + +// CHECK: attributes #[[ELIDE_SAFE]] = { coro_elide_safe } diff --git a/clang/test/CodeGenHLSL/builtins/select.hlsl b/clang/test/CodeGenHLSL/builtins/select.hlsl new file mode 100644 index 00000000000000..cade938b71a2ba --- /dev/null +++ b/clang/test/CodeGenHLSL/builtins/select.hlsl @@ -0,0 +1,54 @@ +// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \ +// RUN: dxil-pc-shadermodel6.3-library %s -emit-llvm -disable-llvm-passes \ +// RUN: -o - | FileCheck %s --check-prefixes=CHECK + +// CHECK-LABEL: test_select_bool_int +// CHECK: [[SELECT:%.*]] = select i1 {{%.*}}, i32 {{%.*}}, i32 {{%.*}} +// CHECK: ret i32 [[SELECT]] +int test_select_bool_int(bool cond0, int tVal, int fVal) { + return select(cond0, tVal, fVal); +} + +struct S { int a; }; +// CHECK-LABEL: test_select_infer +// CHECK: [[SELECT:%.*]] = select i1 {{%.*}}, ptr {{%.*}}, ptr {{%.*}} +// CHECK: store ptr [[SELECT]] +// CHECK: ret void +struct S test_select_infer(bool cond0, struct S tVal, struct S fVal) { + return select(cond0, tVal, fVal); +} + +// CHECK-LABEL: test_select_bool_vector +// CHECK: [[SELECT:%.*]] = select i1 {{%.*}}, <2 x i32> {{%.*}}, <2 x i32> {{%.*}} +// CHECK: ret <2 x i32> [[SELECT]] +int2 test_select_bool_vector(bool cond0, int2 tVal, int2 fVal) { + return select(cond0, tVal, fVal); +} + +// CHECK-LABEL: test_select_vector_1 +// CHECK: [[SELECT:%.*]] = select <1 x i1> {{%.*}}, <1 x i32> {{%.*}}, <1 x i32> {{%.*}} +// CHECK: ret <1 x i32> [[SELECT]] +int1 test_select_vector_1(bool1 cond0, int1 tVals, int1 fVals) { + return select(cond0, tVals, fVals); +} + +// CHECK-LABEL: test_select_vector_2 +// CHECK: [[SELECT:%.*]] = select <2 x i1> {{%.*}}, <2 x i32> {{%.*}}, <2 x i32> {{%.*}} +// CHECK: ret <2 x i32> [[SELECT]] +int2 test_select_vector_2(bool2 cond0, int2 tVals, int2 fVals) { + return select(cond0, tVals, fVals); +} + +// CHECK-LABEL: test_select_vector_3 +// CHECK: [[SELECT:%.*]] = select <3 x i1> {{%.*}}, <3 x i32> {{%.*}}, <3 x i32> {{%.*}} +// CHECK: ret <3 x i32> [[SELECT]] +int3 test_select_vector_3(bool3 cond0, int3 tVals, int3 fVals) { + return select(cond0, tVals, fVals); +} + +// CHECK-LABEL: test_select_vector_4 +// CHECK: [[SELECT:%.*]] = select <4 x i1> {{%.*}}, <4 x i32> {{%.*}}, <4 x i32> {{%.*}} +// CHECK: ret <4 x i32> [[SELECT]] +int4 test_select_vector_4(bool4 cond0, int4 tVals, int4 fVals) { + return select(cond0, tVals, fVals); +} diff --git a/clang/test/Driver/hip-cuid.hip b/clang/test/Driver/hip-cuid.hip index ed7de782bba5ac..2e38c59ccf5ef1 100644 --- a/clang/test/Driver/hip-cuid.hip +++ b/clang/test/Driver/hip-cuid.hip @@ -58,6 +58,28 @@ // RUN: %S/Inputs/hip_multiple_inputs/b.hip \ // RUN: 2>&1 | FileCheck -check-prefixes=COMMON,HEX %s +// Check that cuid is propagated to the host-only compilation. +// RUN: %clang -### -x hip \ +// RUN: --target=x86_64-unknown-linux-gnu \ +// RUN: --no-offload-new-driver \ +// RUN: --offload-arch=gfx900 \ +// RUN: --offload-host-only \ +// RUN: -c -nogpuinc -nogpulib -cuid=xyz_123 \ +// RUN: %S/Inputs/hip_multiple_inputs/a.cu \ +// RUN: %S/Inputs/hip_multiple_inputs/b.hip \ +// RUN: 2>&1 | FileCheck -check-prefixes=HOST %s + +// Check that cuid is propagated to the device-only compilation. +// RUN: %clang -### -x hip \ +// RUN: --target=x86_64-unknown-linux-gnu \ +// RUN: --no-offload-new-driver \ +// RUN: --offload-arch=gfx900 \ +// RUN: --offload-device-only \ +// RUN: -c -nogpuinc -nogpulib -cuid=xyz_123 \ +// RUN: %S/Inputs/hip_multiple_inputs/a.cu \ +// RUN: %S/Inputs/hip_multiple_inputs/b.hip \ +// RUN: 2>&1 | FileCheck -check-prefixes=DEVICE %s + // INVALID: invalid value 'invalid' in '-fuse-cuid=invalid' // COMMON: "-cc1"{{.*}} "-triple" "amdgcn-amd-amdhsa" @@ -92,3 +114,21 @@ // HEX-NOT: "-cuid=[[CUID]]" // COMMON-SAME: "-cuid=[[CUID2]]" // COMMON-SAME: "{{.*}}b.hip" + +// HOST: "-cc1"{{.*}} "-triple" "x86_64-unknown-linux-gnu" +// HOST-SAME: "-cuid=[[CUID:xyz_123]]" +// HOST-SAME: "{{.*}}a.cu" + +// HOST: "-cc1"{{.*}} "-triple" "x86_64-unknown-linux-gnu" +// HOST-SAME: "-cuid=[[CUID]]" +// HOST-SAME: "{{.*}}b.hip" + +// DEVICE: "-cc1"{{.*}} "-triple" "amdgcn-amd-amdhsa" +// DEVICE-SAME: "-target-cpu" "gfx900" +// DEVICE-SAME: "-cuid=[[CUID:xyz_123]]" +// DEVICE-SAME: "{{.*}}a.cu" + +// DEVICE: "-cc1"{{.*}} "-triple" "amdgcn-amd-amdhsa" +// DEVICE-SAME: "-target-cpu" "gfx900" +// DEVICE-SAME: "-cuid=[[CUID]]" +// DEVICE-SAME: "{{.*}}b.hip" diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test index eca86331149028..baa1816358b156 100644 --- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -59,6 +59,7 @@ // CHECK-NEXT: ConsumableAutoCast (SubjectMatchRule_record) // CHECK-NEXT: ConsumableSetOnRead (SubjectMatchRule_record) // CHECK-NEXT: Convergent (SubjectMatchRule_function) +// CHECK-NEXT: CoroAwaitElidable (SubjectMatchRule_record) // CHECK-NEXT: CoroDisableLifetimeBound (SubjectMatchRule_function) // CHECK-NEXT: CoroLifetimeBound (SubjectMatchRule_record) // CHECK-NEXT: CoroOnlyDestroyWhenComplete (SubjectMatchRule_record) diff --git a/clang/test/Modules/pr107673.cppm b/clang/test/Modules/pr107673.cppm new file mode 100644 index 00000000000000..dc66c9ac2245b3 --- /dev/null +++ b/clang/test/Modules/pr107673.cppm @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -std=c++20 %s -ast-dump | FileCheck %s +export module a; +export class f { +public: + void non_inline_func() {} + constexpr void constexpr_func() {} + consteval void consteval_func() {} +}; + +// CHECK-NOT: non_inline_func {{.*}}implicit-inline +// CHECK: constexpr_func {{.*}}implicit-inline +// CHECK: consteval_func {{.*}}implicit-inline diff --git a/clang/test/Preprocessor/predefined-arch-macros.c b/clang/test/Preprocessor/predefined-arch-macros.c index 6f470d85ca563c..49646d94d920c8 100644 --- a/clang/test/Preprocessor/predefined-arch-macros.c +++ b/clang/test/Preprocessor/predefined-arch-macros.c @@ -4053,6 +4053,20 @@ // Begin SystemZ/GCC/Linux tests ---------------- +// RUN: %clang -E -dM %s -o - 2>&1 \ +// RUN: -target s390x-ibm-zos \ +// RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_SYSTEMZ_ZOS +// CHECK_SYSTEMZ_ZOS: #define __ARCH__ 10 +// CHECK_SYSTEMZ_ZOS: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1 +// CHECK_SYSTEMZ_ZOS: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1 +// CHECK_SYSTEMZ_ZOS: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1 +// CHECK_SYSTEMZ_ZOS: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1 +// CHECK_SYSTEMZ_ZOS: #define __HTM__ 1 +// CHECK_SYSTEMZ_ZOS: #define __LONG_DOUBLE_128__ 1 +// CHECK_SYSTEMZ_ZOS: #define __s390__ 1 +// CHECK_SYSTEMZ_ZOS: #define __s390x__ 1 +// CHECK_SYSTEMZ_ZOS: #define __zarch__ 1 + // RUN: %clang -march=arch8 -E -dM %s -o - 2>&1 \ // RUN: -target s390x-unknown-linux \ // RUN: | FileCheck -match-full-lines %s -check-prefix=CHECK_SYSTEMZ_ARCH8 @@ -4064,6 +4078,7 @@ // CHECK_SYSTEMZ_ARCH8: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1 // CHECK_SYSTEMZ_ARCH8: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1 // CHECK_SYSTEMZ_ARCH8: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1 +// CHECK_SYSTEMZ_ARCH8-NOT: #define __HTM__ 1 // CHECK_SYSTEMZ_ARCH8: #define __LONG_DOUBLE_128__ 1 // CHECK_SYSTEMZ_ARCH8: #define __s390__ 1 // CHECK_SYSTEMZ_ARCH8: #define __s390x__ 1 @@ -4080,6 +4095,7 @@ // CHECK_SYSTEMZ_ARCH9: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1 // CHECK_SYSTEMZ_ARCH9: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1 // CHECK_SYSTEMZ_ARCH9: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1 +// CHECK_SYSTEMZ_ARCH9-NOT: #define __HTM__ 1 // CHECK_SYSTEMZ_ARCH9: #define __LONG_DOUBLE_128__ 1 // CHECK_SYSTEMZ_ARCH9: #define __s390__ 1 // CHECK_SYSTEMZ_ARCH9: #define __s390x__ 1 diff --git a/clang/test/Sema/aarch64-neon-faminmax-no-faminmax.c b/clang/test/Sema/aarch64-neon-faminmax-no-faminmax.c new file mode 100644 index 00000000000000..588f69cc7750b3 --- /dev/null +++ b/clang/test/Sema/aarch64-neon-faminmax-no-faminmax.c @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 -triple aarch64-linux-gnu -target-feature +neon -emit-llvm -verify %s -o /dev/null + +// REQUIRES: aarch64-registered-target + +#include + +float16x4_t a16x4, b16x4; +float16x8_t a16x8, b16x8; +float32x2_t a32x2, b32x2; +float32x4_t a32x4, b32x4; +float64x2_t a64x2, b64x2; + + +void test() { + (void) vamin_f16 (a16x4, b16x4); +// expected-error@-1 {{always_inline function 'vamin_f16' requires target feature 'faminmax'}} + (void) vaminq_f16(a16x8, b16x8); +// expected-error@-1 {{always_inline function 'vaminq_f16' requires target feature 'faminmax'}} + (void) vamin_f32 (a32x2, b32x2); +// expected-error@-1 {{always_inline function 'vamin_f32' requires target feature 'faminmax'}} + (void) vaminq_f32(a32x4, b32x4); +// expected-error@-1 {{always_inline function 'vaminq_f32' requires target feature 'faminmax'}} + (void) vaminq_f64(a64x2, b64x2); +// expected-error@-1 {{always_inline function 'vaminq_f64' requires target feature 'faminmax'}} + (void) vamax_f16 (a16x4, b16x4); +// expected-error@-1 {{always_inline function 'vamax_f16' requires target feature 'faminmax'}} + (void) vamaxq_f16(a16x8, b16x8); +// expected-error@-1 {{always_inline function 'vamaxq_f16' requires target feature 'faminmax'}} + (void) vamax_f32 (a32x2, b32x2); +// expected-error@-1 {{always_inline function 'vamax_f32' requires target feature 'faminmax'}} + (void) vamaxq_f32(a32x4, b32x4); +// expected-error@-1 {{always_inline function 'vamaxq_f32' requires target feature 'faminmax'}} + (void) vamaxq_f64(a64x2, b64x2); +// expected-error@-1 {{always_inline function 'vamaxq_f64' requires target feature 'faminmax'}} +} diff --git a/clang/test/Sema/aarch64-neon-faminmax-no-neon.c b/clang/test/Sema/aarch64-neon-faminmax-no-neon.c new file mode 100644 index 00000000000000..a210e8398d9b74 --- /dev/null +++ b/clang/test/Sema/aarch64-neon-faminmax-no-neon.c @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 -triple aarch64-linux-gnu -target-feature +faminmax -emit-llvm -verify %s -o /dev/null + +// REQUIRES: aarch64-registered-target + +#include + +float16x4_t a16x4, b16x4; +float16x8_t a16x8, b16x8; +float32x2_t a32x2, b32x2; +float32x4_t a32x4, b32x4; +float64x2_t a64x2, b64x2; + +void test () { + (void) vamin_f16 (a16x4, b16x4); +// expected-error@-1 {{always_inline function 'vamin_f16' requires target feature 'neon'}} + (void) vaminq_f16(a16x8, b16x8); +// expected-error@-1 {{always_inline function 'vaminq_f16' requires target feature 'neon'}} + (void) vamin_f32 (a32x2, b32x2); +// expected-error@-1 {{always_inline function 'vamin_f32' requires target feature 'neon'}} + (void) vaminq_f32(a32x4, b32x4); +// expected-error@-1 {{always_inline function 'vaminq_f32' requires target feature 'neon'}} + (void) vaminq_f64(a64x2, b64x2); +// expected-error@-1 {{always_inline function 'vaminq_f64' requires target feature 'neon'}} + (void) vamax_f16 (a16x4, b16x4); +// expected-error@-1 {{always_inline function 'vamax_f16' requires target feature 'neon'}} + (void) vamaxq_f16(a16x8, b16x8); +// expected-error@-1 {{always_inline function 'vamaxq_f16' requires target feature 'neon'}} + (void) vamax_f32 (a32x2, b32x2); +// expected-error@-1 {{always_inline function 'vamax_f32' requires target feature 'neon'}} + (void) vamaxq_f32(a32x4, b32x4); +// expected-error@-1 {{always_inline function 'vamaxq_f32' requires target feature 'neon'}} + (void) vamaxq_f64(a64x2, b64x2); +// expected-error@-1 {{always_inline function 'vamaxq_f64' requires target feature 'neon'}} +} diff --git a/clang/test/Sema/attr-target-riscv.c b/clang/test/Sema/attr-target-riscv.c index ed4e2915d6c6ef..35e2ec3986ada3 100644 --- a/clang/test/Sema/attr-target-riscv.c +++ b/clang/test/Sema/attr-target-riscv.c @@ -4,3 +4,15 @@ int __attribute__((target("arch=rv64g"))) foo(void) { return 0; } //expected-error@+1 {{redefinition of 'foo'}} int __attribute__((target("arch=rv64gc"))) foo(void) { return 0; } + +//expected-warning@+1 {{unsupported 'notafeature' in the 'target' attribute string; 'target' attribute ignored}} +int __attribute__((target("arch=+notafeature"))) UnsupportFeature(void) { return 0; } + +//expected-warning@+1 {{unsupported 'notafeature' in the 'target' attribute string; 'target' attribute ignored}} +int __attribute__((target("arch=-notafeature"))) UnsupportNegativeFeature(void) { return 0; } + +//expected-warning@+1 {{unsupported 'arch=+zba,zbb' in the 'target' attribute string; 'target' attribute ignored}} +int __attribute__((target("arch=+zba,zbb"))) WithoutPlus(void) { return 0; } + +//expected-warning@+1 {{unsupported 'arch=zba' in the 'target' attribute string; 'target' attribute ignored}} +int __attribute__((target("arch=zba"))) WithoutPlus2(void) { return 0; } diff --git a/clang/test/SemaCXX/lambda-pack-expansion.cpp b/clang/test/SemaCXX/lambda-pack-expansion.cpp index 77b2e244753a94..0e60ecd8756600 100644 --- a/clang/test/SemaCXX/lambda-pack-expansion.cpp +++ b/clang/test/SemaCXX/lambda-pack-expansion.cpp @@ -68,3 +68,29 @@ void f() { } } + +namespace GH61460 { + +template +void f1(Ts... ts); + +template void g(Ts... p1s) { + (void)[&](auto... p2s) { + ( + [&] { + p1s; + f1(p1s); + sizeof(p1s); + p2s; + }, + ...); + }; +} + +template void g2(Ts... p1s) { + (void)[&](auto... p2s) { [&] { p1s; p2s; }; }; // expected-error {{unexpanded parameter pack 'p2s'}} +} + +void f1() { g(); } + +} // namespace GH61460 diff --git a/clang/test/SemaCXX/pr61460.cpp b/clang/test/SemaCXX/pr61460.cpp deleted file mode 100644 index 471b1b39d23c2b..00000000000000 --- a/clang/test/SemaCXX/pr61460.cpp +++ /dev/null @@ -1,13 +0,0 @@ -// RUN: %clang_cc1 -std=c++17 %s -fsyntax-only -verify - -template void g(Ts... p1s) { - (void)[&](auto... p2s) { ([&] { p1s; p2s; }, ...); }; -} - -void f1() { - g(); -} - -template void g2(Ts... p1s) { - (void)[&](auto... p2s) { [&] { p1s; p2s; }; }; // expected-error {{expression contains unexpanded parameter pack 'p2s'}} -} diff --git a/clang/test/SemaHLSL/BuiltIns/select-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/select-errors.hlsl new file mode 100644 index 00000000000000..34b5fb6d54cd57 --- /dev/null +++ b/clang/test/SemaHLSL/BuiltIns/select-errors.hlsl @@ -0,0 +1,119 @@ +// RUN: %clang_cc1 -finclude-default-header +// -triple dxil-pc-shadermodel6.6-library %s -emit-llvm-only +// -disable-llvm-passes -verify -verify-ignore-unexpected + +int test_no_arg() { + return select(); + // expected-error@-1 {{no matching function for call to 'select'}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template + // not viable: requires 3 arguments, but 0 were provided}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not + // viable: requires 3 arguments, but 0 were provided}} +} + +int test_too_few_args(bool p0) { + return select(p0); + // expected-error@-1 {{no matching function for call to 'select'}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not + // viable: requires 3 arguments, but 1 was provided}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not + // viable: requires 3 arguments, but 1 was provided}} +} + +int test_too_many_args(bool p0, int t0, int f0, int g0) { + return select(p0, t0, f0, g0); + // expected-error@-1 {{no matching function for call to 'select'}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not + // viable: requires 3 arguments, but 4 were provided}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not + // viable: requires 3 arguments, but 4 were provided}} +} + +int test_select_first_arg_wrong_type(int1 p0, int t0, int f0) { + return select(p0, t0, f0); + // expected-error@-1 {{no matching function for call to 'select'}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not + // viable: no known conversion from 'vector' (vector of 1 'int' value) + // to 'bool' for 1st argument}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: could + // not match 'vector' against 'int'}} +} + +int1 test_select_bool_vals_diff_vecs(bool p0, int1 t0, int1 f0) { + return select(p0, t0, f0); + // expected-warning@-1 {{implicit conversion truncates vector: + // 'vector' (vector of 2 'int' values) to 'vector' + // (vector of 1 'int' value)}} +} + +int2 test_select_vector_vals_not_vecs(bool2 p0, int t0, + int f0) { + return select(p0, t0, f0); + // expected-error@-1 {{no matching function for call to 'select'}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: + // could not match 'vector' against 'int'}} + // expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not + // viable: no known conversion from 'vector' + // (vector of 2 'bool' values) to 'bool' for 1st argument}} +} + +int1 test_select_vector_vals_wrong_size(bool2 p0, int1 t0, int1 f0) { + return select(p0, t0, f0); // produce warnings + // expected-warning@-1 {{implicit conversion truncates vector: + // 'vector' (vector of 2 'bool' values) to 'vector' + // (vector of 1 'bool' value)}} + // expected-warning@-2 {{implicit conversion truncates vector: + // 'vector' (vector of 2 'int' values) to 'vector' + // (vector of 1 'int' value)}} +} + +// __builtin_hlsl_select tests +int test_select_builtin_wrong_arg_count(bool p0, int t0) { + return __builtin_hlsl_select(p0, t0); + // expected-error@-1 {{too few arguments to function call, expected 3, + // have 2}} +} + +// not a bool or a vector of bool. should be 2 errors. +int test_select_builtin_first_arg_wrong_type1(int p0, int t0, int f0) { + return __builtin_hlsl_select(p0, t0, f0); + // expected-error@-1 {{passing 'int' to parameter of incompatible type + // 'bool'}} + // expected-error@-2 {{First argument to __builtin_hlsl_select must be of + // vector type}} + } + +int test_select_builtin_first_arg_wrong_type2(int1 p0, int t0, int f0) { + return __builtin_hlsl_select(p0, t0, f0); + // expected-error@-1 {{passing 'vector' (vector of 1 'int' value) to + // parameter of incompatible type 'bool'}} + // expected-error@-2 {{First argument to __builtin_hlsl_select must be of + // vector type}} +} + +// if a bool last 2 args are of same type +int test_select_builtin_bool_incompatible_args(bool p0, int t0, double f0) { + return __builtin_hlsl_select(p0, t0, f0); + // expected-error@-1 {{arguments are of different types ('int' vs 'double')}} +} + +// if a vector second arg isnt a vector +int2 test_select_builtin_second_arg_not_vector(bool2 p0, int t0, int2 f0) { + return __builtin_hlsl_select(p0, t0, f0); + // expected-error@-1 {{Second argument to __builtin_hlsl_select must be of + // vector type}} +} + +// if a vector third arg isn't a vector +int2 test_select_builtin_second_arg_not_vector(bool2 p0, int2 t0, int f0) { + return __builtin_hlsl_select(p0, t0, f0); + // expected-error@-1 {{Third argument to __builtin_hlsl_select must be of + // vector type}} +} + +// if vector last 2 aren't same type (so both are vectors but wrong type) +int2 test_select_builtin_diff_types(bool1 p0, int1 t0, float1 f0) { + return __builtin_hlsl_select(p0, t0, f0); + // expected-error@-1 {{arguments are of different types ('vector' + // vs 'vector')}} +} diff --git a/clang/test/SemaHLSL/TruncationOverloadResolution.hlsl b/clang/test/SemaHLSL/TruncationOverloadResolution.hlsl index f8cfe22372e885..2bcb367c5669a3 100644 --- a/clang/test/SemaHLSL/TruncationOverloadResolution.hlsl +++ b/clang/test/SemaHLSL/TruncationOverloadResolution.hlsl @@ -1,24 +1,16 @@ -// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -fnative-half-type -finclude-default-header -fsyntax-only %s -DERROR=1 -verify +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -fnative-half-type -finclude-default-header -fsyntax-only -Wconversion %s -DERROR=1 -verify // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -fnative-half-type -finclude-default-header -ast-dump %s | FileCheck %s -// Case 1: Prefer exact-match truncation over conversion. -void Half4Float4Double2(double2 D); -void Half4Float4Double2(float4 D); -void Half4Float4Double2(half4 D); +// Case 1: Prefer conversion over exact match truncation. void Half4Float2(float2 D); void Half4Float2(half4 D); void Case1(float4 F, double4 D) { // CHECK: CallExpr {{.*}} 'void' - // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(double2)' - // CHECK-NEXT: DeclRefExpr {{.*}} 'void (double2)' lvalue Function {{.*}} 'Half4Float4Double2' 'void (double2)' - Half4Float4Double2(D); // expected-warning{{implicit conversion truncates vector: 'double4' (aka 'vector') to 'vector' (vector of 2 'double' values)}} - - // CHECK: CallExpr {{.*}} 'void' - // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(float2)' - // CHECK-NEXT: DeclRefExpr {{.*}} 'void (float2)' lvalue Function {{.*}} 'Half4Float2' 'void (float2)' - Half4Float2(F); // expected-warning{{implicit conversion truncates vector: 'float4' (aka 'vector') to 'vector' (vector of 2 'float' values)}} + // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(half4)' + // CHECK-NEXT: DeclRefExpr {{.*}} 'void (half4)' lvalue Function {{.*}} 'Half4Float2' 'void (half4)' + Half4Float2(F); // expected-warning{{implicit conversion loses floating-point precision: 'float4' (aka 'vector') to 'vector' (vector of 4 'half' values)}} } // Case 2: Prefer promotions over conversions when truncating. @@ -46,7 +38,13 @@ void Half2Half3(half2 D); // expected-note{{candidate function}} expected-note{{ void Double2Double3(double3 D); // expected-note{{candidate function}} expected-note{{candidate function}} expected-note{{candidate function}} void Double2Double3(double2 D); // expected-note{{candidate function}} expected-note{{candidate function}} expected-note{{candidate function}} +void Half4Float4Double2(double2 D); +void Half4Float4Double2(float4 D); // expected-note{{candidate function}} +void Half4Float4Double2(half4 D); // expected-note{{candidate function}} + void Case1(half4 H, float4 F, double4 D) { + Half4Float4Double2(D); // expected-error {{call to 'Half4Float4Double2' is ambiguous}} + Float2Double2(H); // expected-error {{call to 'Float2Double2' is ambiguous}} Half2Float2(D); // expected-error {{call to 'Half2Float2' is ambiguous}} @@ -55,8 +53,8 @@ void Case1(half4 H, float4 F, double4 D) { Half2Half3(F); // expected-error {{call to 'Half2Half3' is ambiguous}} Half2Half3(D); // expected-error {{call to 'Half2Half3' is ambiguous}} Half2Half3(H.xyz); - Half2Half3(F.xyz); - Half2Half3(D.xyz); + Half2Half3(F.xyz); // expected-warning {{implicit conversion loses floating-point precision: 'vector' (vector of 3 'float' values) to 'vector' (vector of 3 'half' values)}} + Half2Half3(D.xyz); // expected-warning {{implicit conversion loses floating-point precision: 'vector' (vector of 3 'double' values) to 'vector' (vector of 3 'half' values)}} Double2Double3(H); // expected-error {{call to 'Double2Double3' is ambiguous}} Double2Double3(F); // expected-error {{call to 'Double2Double3' is ambiguous}} diff --git a/clang/test/SemaTemplate/cwg2398.cpp b/clang/test/SemaTemplate/cwg2398.cpp index 6fe1bd3d4f1659..1d9747276fbe00 100644 --- a/clang/test/SemaTemplate/cwg2398.cpp +++ b/clang/test/SemaTemplate/cwg2398.cpp @@ -65,26 +65,20 @@ namespace class_template { template struct B; template