diff --git a/.ci/generate-buildkite-pipeline-premerge b/.ci/generate-buildkite-pipeline-premerge index 53a43070bf1ca3..7676ff716c4185 100755 --- a/.ci/generate-buildkite-pipeline-premerge +++ b/.ci/generate-buildkite-pipeline-premerge @@ -191,6 +191,9 @@ function keep-modified-projects() { } function check-targets() { + # Do not use "check-all" here because if there is "check-all" plus a + # project specific target like "check-clang", that project's tests + # will be run twice. projects=${@} for project in ${projects}; do case ${project} in @@ -216,7 +219,7 @@ function check-targets() { echo "check-lldb" ;; pstl) - echo "check-all" + # Currently we do not run pstl tests in CI. ;; libclc) # Currently there is no testing for libclc. diff --git a/.github/workflows/release-binaries.yml b/.github/workflows/release-binaries.yml index f24e25879b96bd..1cde628d3f66c3 100644 --- a/.github/workflows/release-binaries.yml +++ b/.github/workflows/release-binaries.yml @@ -328,7 +328,7 @@ jobs: run: | # Build some of the mlir tools that take a long time to link if [ "${{ needs.prepare.outputs.build-flang }}" = "true" ]; then - ninja -C ${{ steps.setup-stage.outputs.build-prefix }}/build/tools/clang/stage2-bins/ -j2 flang-new bbc + ninja -C ${{ steps.setup-stage.outputs.build-prefix }}/build/tools/clang/stage2-bins/ -j2 flang bbc fi ninja -C ${{ steps.setup-stage.outputs.build-prefix }}/build/tools/clang/stage2-bins/ \ mlir-bytecode-parser-fuzzer \ diff --git a/clang-tools-extra/clang-apply-replacements/lib/Tooling/ApplyReplacements.cpp b/clang-tools-extra/clang-apply-replacements/lib/Tooling/ApplyReplacements.cpp index 9e0da82dfd3806..b895075e4f31cc 100644 --- a/clang-tools-extra/clang-apply-replacements/lib/Tooling/ApplyReplacements.cpp +++ b/clang-tools-extra/clang-apply-replacements/lib/Tooling/ApplyReplacements.cpp @@ -148,11 +148,8 @@ groupReplacements(const TUReplacements &TUs, const TUDiagnostics &TUDs, if (auto Entry = SM.getFileManager().getOptionalFileRef(Path)) { if (SourceTU) { - auto &Replaces = DiagReplacements[*Entry]; - auto It = Replaces.find(R); - if (It == Replaces.end()) - Replaces.emplace(R, SourceTU); - else if (It->second != SourceTU) + auto [It, Inserted] = DiagReplacements[*Entry].try_emplace(R, SourceTU); + if (!Inserted && It->second != SourceTU) // This replacement is a duplicate of one suggested by another TU. return; } diff --git a/clang-tools-extra/clang-change-namespace/ChangeNamespace.cpp b/clang-tools-extra/clang-change-namespace/ChangeNamespace.cpp index 879c0d26d472a8..850df7daf5c038 100644 --- a/clang-tools-extra/clang-change-namespace/ChangeNamespace.cpp +++ b/clang-tools-extra/clang-change-namespace/ChangeNamespace.cpp @@ -606,9 +606,8 @@ void ChangeNamespaceTool::run( Result.Nodes.getNodeAs("func_ref")) { // If this reference has been processed as a function call, we do not // process it again. - if (ProcessedFuncRefs.count(FuncRef)) + if (!ProcessedFuncRefs.insert(FuncRef).second) return; - ProcessedFuncRefs.insert(FuncRef); const auto *Func = Result.Nodes.getNodeAs("func_decl"); assert(Func); const auto *Context = Result.Nodes.getNodeAs("dc"); diff --git a/clang-tools-extra/clang-tidy/bugprone/ForwardDeclarationNamespaceCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/ForwardDeclarationNamespaceCheck.cpp index d77df50f8fea24..080454287f28b5 100644 --- a/clang-tools-extra/clang-tidy/bugprone/ForwardDeclarationNamespaceCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/ForwardDeclarationNamespaceCheck.cpp @@ -146,12 +146,13 @@ void ForwardDeclarationNamespaceCheck::onEndOfTranslationUnit() { } // Check if a definition in another namespace exists. const auto DeclName = CurDecl->getName(); - if (!DeclNameToDefinitions.contains(DeclName)) { + auto It = DeclNameToDefinitions.find(DeclName); + if (It == DeclNameToDefinitions.end()) { continue; // No definition in this translation unit, we can skip it. } // Make a warning for each definition with the same name (in other // namespaces). - const auto &Definitions = DeclNameToDefinitions[DeclName]; + const auto &Definitions = It->second; for (const auto *Def : Definitions) { diag(CurDecl->getLocation(), "no definition found for %0, but a definition with " diff --git a/clang-tools-extra/clang-tidy/portability/CMakeLists.txt b/clang-tools-extra/clang-tidy/portability/CMakeLists.txt index 3f0b7d47207938..5a38722a61481b 100644 --- a/clang-tools-extra/clang-tidy/portability/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/portability/CMakeLists.txt @@ -9,6 +9,7 @@ add_clang_library(clangTidyPortabilityModule STATIC RestrictSystemIncludesCheck.cpp SIMDIntrinsicsCheck.cpp StdAllocatorConstCheck.cpp + TemplateVirtualMemberFunctionCheck.cpp LINK_LIBS clangTidy diff --git a/clang-tools-extra/clang-tidy/portability/PortabilityTidyModule.cpp b/clang-tools-extra/clang-tidy/portability/PortabilityTidyModule.cpp index b3759a754587d7..316b98b46cf3f2 100644 --- a/clang-tools-extra/clang-tidy/portability/PortabilityTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/portability/PortabilityTidyModule.cpp @@ -12,6 +12,7 @@ #include "RestrictSystemIncludesCheck.h" #include "SIMDIntrinsicsCheck.h" #include "StdAllocatorConstCheck.h" +#include "TemplateVirtualMemberFunctionCheck.h" namespace clang::tidy { namespace portability { @@ -25,6 +26,8 @@ class PortabilityModule : public ClangTidyModule { "portability-simd-intrinsics"); CheckFactories.registerCheck( "portability-std-allocator-const"); + CheckFactories.registerCheck( + "portability-template-virtual-member-function"); } }; diff --git a/clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.cpp b/clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.cpp new file mode 100644 index 00000000000000..9c2f27f01f1849 --- /dev/null +++ b/clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.cpp @@ -0,0 +1,44 @@ +//===--- TemplateVirtualMemberFunctionCheck.cpp - clang-tidy --------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "TemplateVirtualMemberFunctionCheck.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::portability { +namespace { +AST_MATCHER(CXXMethodDecl, isUsed) { return Node.isUsed(); } +} // namespace + +void TemplateVirtualMemberFunctionCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher( + cxxMethodDecl(ofClass(classTemplateSpecializationDecl( + unless(isExplicitTemplateSpecialization())) + .bind("specialization")), + isVirtual(), unless(isUsed()), + unless(cxxDestructorDecl(isDefaulted()))) + .bind("method"), + this); +} + +void TemplateVirtualMemberFunctionCheck::check( + const MatchFinder::MatchResult &Result) { + const auto *ImplicitSpecialization = + Result.Nodes.getNodeAs("specialization"); + const auto *MethodDecl = Result.Nodes.getNodeAs("method"); + + diag(MethodDecl->getLocation(), + "unspecified virtual member function instantiation; the virtual " + "member function is not instantiated but it might be with a " + "different compiler"); + diag(ImplicitSpecialization->getPointOfInstantiation(), + "template instantiated here", DiagnosticIDs::Note); +} + +} // namespace clang::tidy::portability diff --git a/clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.h b/clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.h new file mode 100644 index 00000000000000..41f92adadd6e8a --- /dev/null +++ b/clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.h @@ -0,0 +1,38 @@ +//===--- TemplateVirtualMemberFunctionCheck.h - clang-tidy ------*- C++ -*-===// +// +// 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 LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PORTABILITY_TEMPLATEVIRTUALMEMBERFUNCTIONCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PORTABILITY_TEMPLATEVIRTUALMEMBERFUNCTIONCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::portability { + +/// Upon instantiating a template class, non-virtual member functions don't have +/// to be instantiated unless they are used. Virtual member function +/// instantiation on the other hand is unspecified and depends on the +/// implementation of the compiler. This check intends to find cases when a +/// virtual member function is not instantiated but it might be with a different +/// compiler. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/portability/template-virtual-member-function.html +class TemplateVirtualMemberFunctionCheck : public ClangTidyCheck { +public: + TemplateVirtualMemberFunctionCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + return LangOpts.CPlusPlus; + } +}; + +} // namespace clang::tidy::portability + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PORTABILITY_TEMPLATEVIRTUALMEMBERFUNCTIONCHECK_H diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 3c4652e3c23774..3f7bcde1eb3014 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -121,6 +121,12 @@ New checks Gives warnings for tagged unions, where the number of tags is different from the number of data members inside the union. +- New :doc:`portability-template-virtual-member-function + ` check. + + Finds cases when an uninstantiated virtual member function in a template class + causes cross-compiler incompatibility. + New check aliases ^^^^^^^^^^^^^^^^^ diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index d76466d480d39c..0082234f5ed31b 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -348,6 +348,7 @@ Clang-Tidy Checks :doc:`portability-restrict-system-includes `, "Yes" :doc:`portability-simd-intrinsics `, :doc:`portability-std-allocator-const `, + :doc:`portability-template-virtual-member-function `, :doc:`readability-avoid-const-params-in-decls `, "Yes" :doc:`readability-avoid-nested-conditional-operator `, :doc:`readability-avoid-return-with-void-value `, "Yes" diff --git a/clang-tools-extra/docs/clang-tidy/checks/portability/template-virtual-member-function.rst b/clang-tools-extra/docs/clang-tidy/checks/portability/template-virtual-member-function.rst new file mode 100644 index 00000000000000..aa3ed6653b475b --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/portability/template-virtual-member-function.rst @@ -0,0 +1,37 @@ +.. title:: clang-tidy - portability-template-virtual-member-function + +portability-template-virtual-member-function +============================================ + +Finds cases when an uninstantiated virtual member function in a template class causes +cross-compiler incompatibility. + +Upon instantiating a template class, non-virtual member functions don't have to be +instantiated unless they are used. Virtual member function instantiation on the other hand +is unspecified and depends on the implementation of the compiler. + +In the following snippets the virtual member function is not instantiated by GCC and Clang, +but it is instantiated by MSVC, so while the snippet is accepted by the former compilers, +it is rejected by the latter. + +.. code:: c++ + + template + struct CrossPlatformError { + virtual ~CrossPlatformError() = default; + + static void used() {} + + virtual void unused() { + T MSVCError = this; + }; + }; + + int main() { + CrossPlatformError::used(); + return 0; + } + +Cross-platform projects that need to support MSVC on Windows might see compiler errors +because certain virtual member functions are instantiated, which are not instantiated +by other compilers on other platforms. This check highlights such virtual member functions. diff --git a/clang-tools-extra/test/clang-tidy/checkers/portability/template-virtual-member-function.cpp b/clang-tools-extra/test/clang-tidy/checkers/portability/template-virtual-member-function.cpp new file mode 100644 index 00000000000000..94786ae93dd3f3 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/portability/template-virtual-member-function.cpp @@ -0,0 +1,173 @@ +// RUN: %check_clang_tidy %s portability-template-virtual-member-function %t +namespace UninstantiatedVirtualMember { +template +struct CrossPlatformError { + virtual ~CrossPlatformError() = default; + + static void used() {} + + // CHECK-MESSAGES: [[#@LINE+1]]:18: warning: unspecified virtual member function instantiation + virtual void unused() { + T MSVCError = this; + }; +}; + +int main() { + // CHECK-MESSAGES: [[#@LINE+1]]:5: note: template instantiated here + CrossPlatformError::used(); + return 0; +} +} // namespace UninstantiatedVirtualMember + +namespace UninstantiatedVirtualMembers { +template +struct CrossPlatformError { + virtual ~CrossPlatformError() = default; + + static void used() {} + + // CHECK-MESSAGES: [[#@LINE+2]]:18: warning: unspecified virtual member function instantiation + // CHECK-MESSAGES: [[#@LINE+13]]:5: note: template instantiated here + virtual void unused() { + T MSVCError = this; + }; + + // CHECK-MESSAGES: [[#@LINE+2]]:18: warning: unspecified virtual member function instantiation + // CHECK-MESSAGES: [[#@LINE+7]]:5: note: template instantiated here + virtual void unused2() { + T MSVCError = this; + }; +}; + +int main() { + CrossPlatformError::used(); + return 0; +} +} // namespace UninstantiatedVirtualMembers + +namespace UninstantiatedVirtualDestructor { +template +struct CrossPlatformError { + // CHECK-MESSAGES: [[#@LINE+2]]:13: warning: unspecified virtual member function instantiation + // CHECK-MESSAGES: [[#@LINE+9]]:5: note: template instantiated here + virtual ~CrossPlatformError() { + T MSVCError = this; + }; + + static void used() {} +}; + +int main() { + CrossPlatformError::used(); + return 0; +} +} // namespace UninstantiatedVirtualDestructor + +namespace MultipleImplicitInstantiations { +template +struct CrossPlatformError { + virtual ~CrossPlatformError() = default; + + static void used() {} + + // CHECK-MESSAGES: [[#@LINE+2]]:18: warning: unspecified virtual member function instantiation + // CHECK-MESSAGES: [[#@LINE+7]]:5: note: template instantiated here + virtual void unused() { + T MSVCError = this; + }; +}; + +int main() { + CrossPlatformError::used(); + CrossPlatformError::used(); + CrossPlatformError::used(); + return 0; +} +} // namespace MultipleImplicitInstantiations + +namespace SomeImplicitInstantiationError { +template struct CrossPlatformError { + virtual ~CrossPlatformError() = default; + + static void used() {} + + // CHECK-MESSAGES: [[#@LINE+2]]:18: warning: unspecified virtual member function instantiation + // CHECK-MESSAGES: [[#@LINE+5]]:5: note: template instantiated here + virtual void unused(){}; +}; + +int main() { + CrossPlatformError::used(); + CrossPlatformError NoError; + return 0; +} +} // namespace SomeImplicitInstantiationError + +namespace InstantiatedVirtualMemberFunctions { +template +struct NoError { + virtual ~NoError() {}; + virtual void unused() {}; + virtual void unused2() {}; + virtual void unused3() {}; +}; + +int main() { + NoError Ne; + return 0; +} +} // namespace InstantiatedVirtualMemberFunctions + +namespace UninstantiatedNonVirtualMemberFunctions { +template +struct NoError { + static void used() {}; + void unused() {}; + void unused2() {}; + void unused3() {}; +}; + +int main() { + NoError::used(); + return 0; +} +} // namespace UninstantiatedNonVirtualMemberFunctions + +namespace PartialSpecializationError { +template +struct CrossPlatformError {}; + +template +struct CrossPlatformError{ + virtual ~CrossPlatformError() = default; + + static void used() {} + + // CHECK-MESSAGES: [[#@LINE+2]]:18: warning: unspecified virtual member function instantiation + // CHECK-MESSAGES: [[#@LINE+7]]:5: note: template instantiated here + virtual void unused() { + U MSVCError = this; + }; +}; + +int main() { + CrossPlatformError::used(); + return 0; +} +} // namespace PartialSpecializationError + +namespace PartialSpecializationNoInstantiation { +template +struct NoInstantiation {}; + +template +struct NoInstantiation{ + virtual ~NoInstantiation() = default; + + static void used() {} + + virtual void unused() { + U MSVCError = this; + }; +}; +} // namespace PartialSpecializationNoInstantiation diff --git a/clang/cmake/caches/Fuchsia-stage2.cmake b/clang/cmake/caches/Fuchsia-stage2.cmake index 26ae30c71b4df3..5af98c7b3b3fba 100644 --- a/clang/cmake/caches/Fuchsia-stage2.cmake +++ b/clang/cmake/caches/Fuchsia-stage2.cmake @@ -345,6 +345,7 @@ foreach(target armv6m-none-eabi;armv7m-none-eabi;armv8m.main-none-eabi) set(RUNTIMES_${target}_LIBCXX_CXX_ABI none CACHE STRING "") set(RUNTIMES_${target}_LIBCXX_ENABLE_SHARED OFF CACHE BOOL "") set(RUNTIMES_${target}_LIBCXX_ENABLE_STATIC ON CACHE BOOL "") + set(RUNTIMES_${target}_LIBCXX_SHARED_OUTPUT_NAME "c++-shared" CACHE STRING "") set(RUNTIMES_${target}_LIBCXX_LIBC "llvm-libc" CACHE STRING "") set(RUNTIMES_${target}_LIBCXX_ENABLE_FILESYSTEM OFF CACHE BOOL "") set(RUNTIMES_${target}_LIBCXX_ENABLE_RANDOM_DEVICE OFF CACHE BOOL "") @@ -396,6 +397,7 @@ foreach(target riscv32-unknown-elf) set(RUNTIMES_${target}_LIBCXX_CXX_ABI none CACHE STRING "") set(RUNTIMES_${target}_LIBCXX_ENABLE_SHARED OFF CACHE BOOL "") set(RUNTIMES_${target}_LIBCXX_ENABLE_STATIC ON CACHE BOOL "") + set(RUNTIMES_${target}_LIBCXX_SHARED_OUTPUT_NAME "c++-shared" CACHE STRING "") set(RUNTIMES_${target}_LIBCXX_LIBC "llvm-libc" CACHE STRING "") set(RUNTIMES_${target}_LIBCXX_ENABLE_FILESYSTEM OFF CACHE BOOL "") set(RUNTIMES_${target}_LIBCXX_ENABLE_RANDOM_DEVICE OFF CACHE BOOL "") diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index c0019cfe4658d7..763bc3ac159322 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -99,6 +99,20 @@ C++ Specific Potentially Breaking Changes // Was error, now evaluates to false. constexpr bool b = f() == g(); +- The warning ``-Wdeprecated-literal-operator`` is now on by default, as this is + something that WG21 has shown interest in removing from the language. The + result is that anyone who is compiling with ``-Werror`` should see this + diagnostic. To fix this diagnostic, simply removing the space character from + between the ``operator""`` and the user defined literal name will make the + source no longer deprecated. This is consistent with `CWG2521 _`. + + .. code-block:: c++ + + // Now diagnoses by default. + unsigned operator"" _udl_name(unsigned long long); + // Fixed version: + unsigned operator""_udl_name(unsigned long long); + ABI Changes in This Version --------------------------- @@ -171,13 +185,12 @@ C++23 Feature Support ^^^^^^^^^^^^^^^^^^^^^ - Removed the restriction to literal types in constexpr functions in C++23 mode. +- Extend lifetime of temporaries in mem-default-init for P2718R0. Clang now fully + supports `P2718R0 Lifetime extension in range-based for loops `_. + C++20 Feature Support ^^^^^^^^^^^^^^^^^^^^^ -C++17 Feature Support -^^^^^^^^^^^^^^^^^^^^^ -- The implementation of the relaxed template template argument matching rules is - more complete and reliable, and should provide more accurate diagnostics. Resolutions to C++ Defect Reports ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -204,8 +217,7 @@ Resolutions to C++ Defect Reports (`CWG2351: void{} `_). - Clang now has improved resolution to CWG2398, allowing class templates to have - default arguments deduced when partial ordering, and better backwards compatibility - in overload resolution. + 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. @@ -217,6 +229,10 @@ Resolutions to C++ Defect Reports - Clang now allows trailing requires clause on explicit deduction guides. (`CWG2707: Deduction guides cannot have a trailing requires-clause `_). +- Clang now diagnoses a space in the first production of a ``literal-operator-id`` + by default. + (`CWG2521: User-defined literals and reserved identifiers `_). + C Language Changes ------------------ @@ -336,10 +352,6 @@ Improvements to Clang's diagnostics - Clang now diagnoses when the result of a [[nodiscard]] function is discarded after being cast in C. Fixes #GH104391. -- Clang now properly explains the reason a template template argument failed to - match a template template parameter, in terms of the C++17 relaxed matching rules - instead of the old ones. - - Don't emit duplicated dangling diagnostics. (#GH93386). - Improved diagnostic when trying to befriend a concept. (#GH45182). @@ -384,6 +396,10 @@ Improvements to Clang's diagnostics - The warning for an unsupported type for a named register variable is now phrased ``unsupported type for named register variable``, instead of ``bad type for named register variable``. This makes it clear that the type is not supported at all, rather than being suboptimal in some way the error fails to mention (#GH111550). + +- Clang now emits a ``-Wdepredcated-literal-operator`` diagnostic, even if the + name was a reserved name, which we improperly allowed to suppress the + diagnostic. Improvements to Clang's time-trace ---------------------------------- @@ -449,8 +465,6 @@ Bug Fixes to C++ Support - Correctly check constraints of explicit instantiations of member functions. (#GH46029) - When performing partial ordering of function templates, clang now checks that the deduction was consistent. Fixes (#GH18291). -- Fixes to several issues in partial ordering of template template parameters, which - were documented in the test suite. - Fixed an assertion failure about a constraint of a friend function template references to a value with greater template depth than the friend function template. (#GH98258) - Clang now rebuilds the template parameters of out-of-line declarations and specializations in the context @@ -633,6 +647,9 @@ AST Matchers - Fixed a crash when traverse lambda expr with invalid captures. (#GH106444) +- Ensure ``hasName`` matches template specializations across inline namespaces, + making `matchesNodeFullSlow` and `matchesNodeFullFast` consistent. + clang-format ------------ diff --git a/clang/include/clang/AST/Attr.h b/clang/include/clang/AST/Attr.h index ac44e9fdd7c4e9..725498e132fc28 100644 --- a/clang/include/clang/AST/Attr.h +++ b/clang/include/clang/AST/Attr.h @@ -197,6 +197,23 @@ class InheritableParamAttr : public InheritableAttr { } }; +class InheritableParamOrStmtAttr : public InheritableParamAttr { +protected: + InheritableParamOrStmtAttr(ASTContext &Context, + const AttributeCommonInfo &CommonInfo, + attr::Kind AK, bool IsLateParsed, + bool InheritEvenIfAlreadyPresent) + : InheritableParamAttr(Context, CommonInfo, AK, IsLateParsed, + InheritEvenIfAlreadyPresent) {} + +public: + // Implement isa/cast/dyncast/etc. + static bool classof(const Attr *A) { + return A->getKind() >= attr::FirstInheritableParamOrStmtAttr && + A->getKind() <= attr::LastInheritableParamOrStmtAttr; + } +}; + class HLSLAnnotationAttr : public InheritableAttr { protected: HLSLAnnotationAttr(ASTContext &Context, const AttributeCommonInfo &CommonInfo, diff --git a/clang/include/clang/AST/PrettyPrinter.h b/clang/include/clang/AST/PrettyPrinter.h index 332ac3c6a004a9..91818776b770cf 100644 --- a/clang/include/clang/AST/PrettyPrinter.h +++ b/clang/include/clang/AST/PrettyPrinter.h @@ -55,15 +55,17 @@ class PrintingCallbacks { /// This type is intended to be small and suitable for passing by value. /// It is very frequently copied. struct PrintingPolicy { + enum SuppressInlineNamespaceMode : uint8_t { None, Redundant, All }; + /// Create a default printing policy for the specified language. PrintingPolicy(const LangOptions &LO) : Indentation(2), SuppressSpecifiers(false), SuppressTagKeyword(LO.CPlusPlus), IncludeTagDefinition(false), SuppressScope(false), SuppressUnwrittenScope(false), - SuppressInlineNamespace(true), SuppressElaboration(false), - SuppressInitializers(false), ConstantArraySizeAsWritten(false), - AnonymousTagLocations(true), SuppressStrongLifetime(false), - SuppressLifetimeQualifiers(false), + SuppressInlineNamespace(SuppressInlineNamespaceMode::Redundant), + SuppressElaboration(false), SuppressInitializers(false), + ConstantArraySizeAsWritten(false), AnonymousTagLocations(true), + SuppressStrongLifetime(false), SuppressLifetimeQualifiers(false), SuppressTemplateArgsInCXXConstructors(false), SuppressDefaultTemplateArgs(true), Bool(LO.Bool), Nullptr(LO.CPlusPlus11 || LO.C23), NullptrTypeInNamespace(LO.CPlusPlus), @@ -141,10 +143,12 @@ struct PrintingPolicy { unsigned SuppressUnwrittenScope : 1; /// Suppress printing parts of scope specifiers that correspond - /// to inline namespaces, where the name is unambiguous with the specifier + /// to inline namespaces. + /// If Redudant, where the name is unambiguous with the specifier removed. + /// If All, even if the name is ambiguous with the specifier /// removed. - LLVM_PREFERRED_TYPE(bool) - unsigned SuppressInlineNamespace : 1; + LLVM_PREFERRED_TYPE(SuppressInlineNamespaceMode) + unsigned SuppressInlineNamespace : 2; /// Ignore qualifiers and tag keywords as specified by elaborated type sugar, /// instead letting the underlying type print as normal. diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index fbcbf0ed416416..ec3d6e0079f630 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -759,6 +759,11 @@ class TargetSpecificAttr { /// redeclarations, even when it's written on a parameter. class InheritableParamAttr : InheritableAttr; +/// A attribute that is either a declaration attribute or a statement attribute, +/// and if used as a declaration attribute, is inherited by later +/// redeclarations, even when it's written on a parameter. +class InheritableParamOrStmtAttr : InheritableParamAttr; + /// An attribute which changes the ABI rules for a specific parameter. class ParameterABIAttr : InheritableParamAttr { let Subjects = SubjectList<[ParmVar]>; @@ -928,7 +933,7 @@ def AnalyzerNoReturn : InheritableAttr { let Documentation = [Undocumented]; } -def Annotate : InheritableParamAttr { +def Annotate : InheritableParamOrStmtAttr { let Spellings = [Clang<"annotate">]; let Args = [StringArgument<"Annotation">, VariadicExprArgument<"Args">]; // Ensure that the annotate attribute can be used with diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 9ebee81fcb0d3d..7068473a0e12ac 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -4745,6 +4745,12 @@ def HLSLCross: LangBuiltin<"HLSL_LANG"> { let Prototype = "void(...)"; } +def HLSLDegrees : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_elementwise_degrees"]; + let Attributes = [NoThrow, Const]; + let Prototype = "void(...)"; +} + def HLSLDotProduct : LangBuiltin<"HLSL_LANG"> { let Spellings = ["__builtin_hlsl_dot"]; let Attributes = [NoThrow, Const]; diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index 97573fcf20c1fb..68722ad9633120 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -147,6 +147,9 @@ def warn_drv_unsupported_option_for_processor : Warning< def warn_drv_unsupported_openmp_library : Warning< "the library '%0=%1' is not supported, OpenMP will not be enabled">, InGroup; +def warn_openmp_experimental : Warning< + "OpenMP support in flang is still experimental">, + InGroup; def err_drv_invalid_thread_model_for_target : Error< "invalid thread model '%0' in '%1' for this target">; diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 41e719d4d57816..8273701e7b0963 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -1583,3 +1583,7 @@ def ExtractAPIMisuse : DiagGroup<"extractapi-misuse">; // Warnings about using the non-standard extension having an explicit specialization // with a storage class specifier. def ExplicitSpecializationStorageClass : DiagGroup<"explicit-specialization-storage-class">; + +// A warning for options that enable a feature that is not yet complete +def ExperimentalOption : DiagGroup<"experimental-option">; + diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index f4a2d4a3f0656a..41cdd09e971651 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -439,7 +439,7 @@ def warn_reserved_extern_symbol: Warning< InGroup, DefaultIgnore; def warn_deprecated_literal_operator_id: Warning< "identifier %0 preceded by whitespace in a literal operator declaration " - "is deprecated">, InGroup, DefaultIgnore; + "is deprecated">, InGroup; def warn_reserved_module_name : Warning< "%0 is a reserved name for a module">, InGroup; def warn_import_implementation_partition_unit_in_interface_unit : Warning< @@ -5262,13 +5262,6 @@ def note_template_arg_refers_here_func : Note< def err_template_arg_template_params_mismatch : Error< "template template argument has different template parameters than its " "corresponding template template parameter">; -def note_template_arg_template_params_mismatch : Note< - "template template argument has different template parameters than its " - "corresponding template template parameter">; -def err_non_deduced_mismatch : Error< - "could not match %diff{$ against $|types}0,1">; -def err_inconsistent_deduction : Error< - "conflicting deduction %diff{$ against $|types}0,1 for parameter">; def err_template_arg_not_integral_or_enumeral : Error< "non-type template argument of type %0 must have an integral or enumeration" " type">; diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index ea493d0e6aede7..a2d4f4dfadc5ee 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -6077,7 +6077,7 @@ def _sysroot_EQ : Joined<["--"], "sysroot=">, Visibility<[ClangOption, FlangOpti def _sysroot : Separate<["--"], "sysroot">, Alias<_sysroot_EQ>; //===----------------------------------------------------------------------===// -// pie/pic options (clang + flang-new) +// pie/pic options (clang + flang) //===----------------------------------------------------------------------===// let Visibility = [ClangOption, FlangOption] in { @@ -6093,7 +6093,7 @@ def fno_pie : Flag<["-"], "fno-pie">, Group; } // let Vis = [Default, FlangOption] //===----------------------------------------------------------------------===// -// Target Options (clang + flang-new) +// Target Options (clang + flang) //===----------------------------------------------------------------------===// let Flags = [TargetSpecific] in { let Visibility = [ClangOption, FlangOption] in { diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h index d38278c5041118..c716a25bb673b8 100644 --- a/clang/include/clang/Sema/Overload.h +++ b/clang/include/clang/Sema/Overload.h @@ -925,11 +925,6 @@ class Sema; bool TookAddressOfOverload : 1; - /// Have we matched any packs on the parameter side, versus any non-packs on - /// the argument side, in a context where the opposite matching is also - /// allowed? - bool HasMatchedPackOnParmToNonPackOnArg : 1; - /// True if the candidate was found using ADL. CallExpr::ADLCallKind IsADLCandidate : 1; @@ -1004,9 +999,8 @@ class Sema; friend class OverloadCandidateSet; OverloadCandidate() : IsSurrogate(false), IgnoreObjectArgument(false), - TookAddressOfOverload(false), - HasMatchedPackOnParmToNonPackOnArg(false), - IsADLCandidate(CallExpr::NotADL), RewriteKind(CRK_None) {} + TookAddressOfOverload(false), IsADLCandidate(CallExpr::NotADL), + RewriteKind(CRK_None) {} }; /// OverloadCandidateSet - A set of overload candidates, used in C++ diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index ef010fafb1573e..24191fd688dc5a 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -4528,9 +4528,10 @@ class Sema final : public SemaBase { /// declaration. void AddAlignValueAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E); - /// AddAnnotationAttr - Adds an annotation Annot with Args arguments to D. - void AddAnnotationAttr(Decl *D, const AttributeCommonInfo &CI, - StringRef Annot, MutableArrayRef Args); + /// CreateAnnotationAttr - Creates an annotation Annot with Args arguments. + Attr *CreateAnnotationAttr(const AttributeCommonInfo &CI, StringRef Annot, + MutableArrayRef Args); + Attr *CreateAnnotationAttr(const ParsedAttr &AL); bool checkMSInheritanceAttrOnDefinition(CXXRecordDecl *RD, SourceRange Range, bool BestCase, @@ -10133,8 +10134,7 @@ class Sema final : public SemaBase { ADLCallKind IsADLCandidate = ADLCallKind::NotADL, ConversionSequenceList EarlyConversions = std::nullopt, OverloadCandidateParamOrder PO = {}, - bool AggregateCandidateDeduction = false, - bool HasMatchedPackOnParmToNonPackOnArg = false); + bool AggregateCandidateDeduction = false); /// Add all of the function declarations in the given function set to /// the overload candidate set. @@ -10169,8 +10169,7 @@ class Sema final : public SemaBase { bool SuppressUserConversions = false, bool PartialOverloading = false, ConversionSequenceList EarlyConversions = std::nullopt, - OverloadCandidateParamOrder PO = {}, - bool HasMatchedPackOnParmToNonPackOnArg = false); + OverloadCandidateParamOrder PO = {}); /// Add a C++ member function template as a candidate to the candidate /// set, using template argument deduction to produce an appropriate member @@ -10216,8 +10215,7 @@ class Sema final : public SemaBase { CXXConversionDecl *Conversion, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, Expr *From, QualType ToType, OverloadCandidateSet &CandidateSet, bool AllowObjCConversionOnExplicit, - bool AllowExplicit, bool AllowResultConversion = true, - bool HasMatchedPackOnParmToNonPackOnArg = false); + bool AllowExplicit, bool AllowResultConversion = true); /// Adds a conversion function template specialization /// candidate to the overload set, using template argument deduction @@ -11640,8 +11638,7 @@ class Sema final : public SemaBase { SourceLocation RAngleLoc, unsigned ArgumentPackIndex, SmallVectorImpl &SugaredConverted, SmallVectorImpl &CanonicalConverted, - CheckTemplateArgumentKind CTAK, bool PartialOrdering, - bool *MatchedPackOnParmToNonPackOnArg); + CheckTemplateArgumentKind CTAK); /// Check that the given template arguments can be provided to /// the given template, converting the arguments along the way. @@ -11688,8 +11685,7 @@ class Sema final : public SemaBase { SmallVectorImpl &SugaredConverted, SmallVectorImpl &CanonicalConverted, bool UpdateArgsWithConversions = true, - bool *ConstraintsNotSatisfied = nullptr, bool PartialOrderingTTP = false, - bool *MatchedPackOnParmToNonPackOnArg = nullptr); + bool *ConstraintsNotSatisfied = nullptr, bool PartialOrderingTTP = false); bool CheckTemplateTypeArgument( TemplateTypeParmDecl *Param, TemplateArgumentLoc &Arg, @@ -11723,9 +11719,7 @@ class Sema final : public SemaBase { /// It returns true if an error occurred, and false otherwise. bool CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param, TemplateParameterList *Params, - TemplateArgumentLoc &Arg, - bool PartialOrdering, - bool *MatchedPackOnParmToNonPackOnArg); + TemplateArgumentLoc &Arg, bool IsDeduced); void NoteTemplateLocation(const NamedDecl &Decl, std::optional ParamRange = {}); @@ -12236,8 +12230,8 @@ class Sema final : public SemaBase { SmallVectorImpl &Deduced, unsigned NumExplicitlySpecified, FunctionDecl *&Specialization, sema::TemplateDeductionInfo &Info, - SmallVectorImpl const *OriginalCallArgs, - bool PartialOverloading, bool PartialOrdering, + SmallVectorImpl const *OriginalCallArgs = nullptr, + bool PartialOverloading = false, llvm::function_ref CheckNonDependent = [] { return false; }); /// Perform template argument deduction from a function call @@ -12271,8 +12265,7 @@ class Sema final : public SemaBase { TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef Args, FunctionDecl *&Specialization, sema::TemplateDeductionInfo &Info, bool PartialOverloading, bool AggregateDeductionCandidate, - bool PartialOrdering, QualType ObjectType, - Expr::Classification ObjectClassification, + QualType ObjectType, Expr::Classification ObjectClassification, llvm::function_ref)> CheckNonDependent); /// Deduce template arguments when taking the address of a function @@ -12425,9 +12418,8 @@ class Sema final : public SemaBase { sema::TemplateDeductionInfo &Info); bool isTemplateTemplateParameterAtLeastAsSpecializedAs( - TemplateParameterList *PParam, TemplateDecl *PArg, TemplateDecl *AArg, - const DefaultArguments &DefaultArgs, SourceLocation ArgLoc, - bool PartialOrdering, bool *MatchedPackOnParmToNonPackOnArg); + TemplateParameterList *PParam, TemplateDecl *AArg, + const DefaultArguments &DefaultArgs, SourceLocation Loc, bool IsDeduced); /// Mark which template parameters are used in a given expression. /// @@ -12736,9 +12728,6 @@ class Sema final : public SemaBase { /// We are instantiating a type alias template declaration. TypeAliasTemplateInstantiation, - - /// We are performing partial ordering for template template parameters. - PartialOrderingTTP, } Kind; /// Was the enclosing context a non-instantiation SFINAE context? @@ -12960,12 +12949,6 @@ class Sema final : public SemaBase { TemplateDecl *Entity, BuildingDeductionGuidesTag, SourceRange InstantiationRange = SourceRange()); - struct PartialOrderingTTP {}; - /// \brief Note that we are partial ordering template template parameters. - InstantiatingTemplate(Sema &SemaRef, SourceLocation ArgLoc, - PartialOrderingTTP, TemplateDecl *PArg, - SourceRange InstantiationRange = SourceRange()); - /// Note that we have finished instantiating this template. void Clear(); @@ -13426,8 +13409,7 @@ class Sema final : public SemaBase { bool InstantiateClassTemplateSpecialization( SourceLocation PointOfInstantiation, ClassTemplateSpecializationDecl *ClassTemplateSpec, - TemplateSpecializationKind TSK, bool Complain = true, - bool PrimaryHasMatchedPackOnParmToNonPackOnArg = false); + TemplateSpecializationKind TSK, bool Complain = true); /// Instantiates the definitions of all of the member /// of the given class, which is an instantiation of a class template diff --git a/clang/include/clang/Sema/TemplateDeduction.h b/clang/include/clang/Sema/TemplateDeduction.h index 9c12eef5c42a06..28b014fd84e4b3 100644 --- a/clang/include/clang/Sema/TemplateDeduction.h +++ b/clang/include/clang/Sema/TemplateDeduction.h @@ -51,11 +51,6 @@ class TemplateDeductionInfo { /// Have we suppressed an error during deduction? bool HasSFINAEDiagnostic = false; - /// Have we matched any packs on the parameter side, versus any non-packs on - /// the argument side, in a context where the opposite matching is also - /// allowed? - bool MatchedPackOnParmToNonPackOnArg = false; - /// The template parameter depth for which we're performing deduction. unsigned DeducedDepth; @@ -92,14 +87,6 @@ class TemplateDeductionInfo { return DeducedDepth; } - bool hasMatchedPackOnParmToNonPackOnArg() const { - return MatchedPackOnParmToNonPackOnArg; - } - - void setMatchedPackOnParmToNonPackOnArg() { - MatchedPackOnParmToNonPackOnArg = true; - } - /// Get the number of explicitly-specified arguments. unsigned getNumExplicitArgs() const { return ExplicitArgs; diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index fe44238ea11869..b2663714340b93 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -2728,7 +2728,7 @@ bool Compiler::VisitMaterializeTemporaryExpr( const Expr *Inner = E->getSubExpr()->skipRValueSubobjectAdjustments(); if (std::optional LocalIndex = - allocateLocal(Inner, E->getExtendingDecl())) { + allocateLocal(E, Inner->getType(), E->getExtendingDecl())) { InitLinkScope ILS(this, InitLink::Temp(*LocalIndex)); if (!this->emitGetPtrLocal(*LocalIndex, E)) return false; @@ -2869,6 +2869,11 @@ bool Compiler::VisitPredefinedExpr(const PredefinedExpr *E) { if (DiscardResult) return true; + if (!Initializing) { + unsigned StringIndex = P.createGlobalString(E->getFunctionName(), E); + return this->emitGetPtrGlobal(StringIndex, E); + } + return this->delegate(E->getFunctionName()); } @@ -4029,7 +4034,8 @@ unsigned Compiler::allocateLocalPrimitive(DeclTy &&Src, PrimType Ty, template std::optional -Compiler::allocateLocal(DeclTy &&Src, const ValueDecl *ExtendingDecl) { +Compiler::allocateLocal(DeclTy &&Src, QualType Ty, + const ValueDecl *ExtendingDecl) { // Make sure we don't accidentally register the same decl twice. if ([[maybe_unused]] const auto *VD = dyn_cast_if_present(Src.dyn_cast())) { @@ -4037,7 +4043,6 @@ Compiler::allocateLocal(DeclTy &&Src, const ValueDecl *ExtendingDecl) { assert(!Locals.contains(VD)); } - QualType Ty; const ValueDecl *Key = nullptr; const Expr *Init = nullptr; bool IsTemporary = false; @@ -4050,7 +4055,8 @@ Compiler::allocateLocal(DeclTy &&Src, const ValueDecl *ExtendingDecl) { } if (auto *E = Src.dyn_cast()) { IsTemporary = true; - Ty = E->getType(); + if (Ty.isNull()) + Ty = E->getType(); } Descriptor *D = P.createDescriptor( @@ -6005,6 +6011,9 @@ bool Compiler::visitDeclRef(const ValueDecl *D, const Expr *E) { return this->emitGetPtrParam(It->second.Offset, E); } + + if (D->getType()->isReferenceType()) + return false; // FIXME: Do we need to emit InvalidDeclRef? } // In case we need to re-visit a declaration. @@ -6041,9 +6050,7 @@ bool Compiler::visitDeclRef(const ValueDecl *D, const Expr *E) { const auto typeShouldBeVisited = [&](QualType T) -> bool { if (T.isConstant(Ctx.getASTContext())) return true; - if (const auto *RT = T->getAs()) - return RT->getPointeeType().isConstQualified(); - return false; + return T->isReferenceType(); }; // DecompositionDecls are just proxies for us. @@ -6059,9 +6066,12 @@ bool Compiler::visitDeclRef(const ValueDecl *D, const Expr *E) { // 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); + VD->getInit() && !VD->getInit()->isValueDependent()) { + + if (VD->evaluateValue()) + return revisit(VD); + return this->emitInvalidDeclRef(cast(E), E); + } } } 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 22e078f3fe546f..4253e7b3248c9f 100644 --- a/clang/lib/AST/ByteCode/Compiler.h +++ b/clang/lib/AST/ByteCode/Compiler.h @@ -302,7 +302,8 @@ class Compiler : public ConstStmtVisitor, bool>, /// Allocates a space storing a local given its type. std::optional - allocateLocal(DeclTy &&Decl, const ValueDecl *ExtendingDecl = nullptr); + allocateLocal(DeclTy &&Decl, QualType Ty = QualType(), + const ValueDecl *ExtendingDecl = nullptr); unsigned allocateTemporary(const Expr *E); private: diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index 1765193f5bebbc..ec27aebf84bd80 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -38,7 +38,6 @@ static T getParam(const InterpFrame *Frame, unsigned Index) { return Frame->getParam(Offset); } -// static APSInt getAPSIntParam(InterpStack &Stk, size_t Offset = 0) { static APSInt getAPSIntParam(const InterpFrame *Frame, unsigned Index) { APSInt R; unsigned Offset = Frame->getFunction()->getParamOffset(Index); @@ -1162,6 +1161,71 @@ static bool interp__builtin_is_aligned_up_down(InterpState &S, CodePtr OpPC, return false; } +/// __builtin_assume_aligned(Ptr, Alignment[, ExtraOffset]) +static bool interp__builtin_assume_aligned(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, + const Function *Func, + const CallExpr *Call) { + assert(Call->getNumArgs() == 2 || Call->getNumArgs() == 3); + + // Might be called with function pointers in C. + std::optional PtrT = S.Ctx.classify(Call->getArg(0)); + if (PtrT != PT_Ptr) + return false; + + unsigned ArgSize = callArgSize(S, Call); + const Pointer &Ptr = S.Stk.peek(ArgSize); + std::optional ExtraOffset; + APSInt Alignment; + if (Call->getNumArgs() == 2) { + Alignment = peekToAPSInt(S.Stk, *S.Ctx.classify(Call->getArg(1))); + } else { + PrimType AlignmentT = *S.Ctx.classify(Call->getArg(1)); + PrimType ExtraOffsetT = *S.Ctx.classify(Call->getArg(2)); + Alignment = peekToAPSInt(S.Stk, *S.Ctx.classify(Call->getArg(1)), + align(primSize(AlignmentT)) + + align(primSize(ExtraOffsetT))); + ExtraOffset = peekToAPSInt(S.Stk, *S.Ctx.classify(Call->getArg(2))); + } + + CharUnits Align = CharUnits::fromQuantity(Alignment.getZExtValue()); + + // If there is a base object, then it must have the correct alignment. + if (Ptr.isBlockPointer()) { + CharUnits BaseAlignment; + if (const auto *VD = Ptr.getDeclDesc()->asValueDecl()) + BaseAlignment = S.getASTContext().getDeclAlign(VD); + else if (const auto *E = Ptr.getDeclDesc()->asExpr()) + BaseAlignment = GetAlignOfExpr(S.getASTContext(), E, UETT_AlignOf); + + if (BaseAlignment < Align) { + S.CCEDiag(Call->getArg(0), + diag::note_constexpr_baa_insufficient_alignment) + << 0 << BaseAlignment.getQuantity() << Align.getQuantity(); + return false; + } + } + + APValue AV = Ptr.toAPValue(S.getASTContext()); + CharUnits AVOffset = AV.getLValueOffset(); + if (ExtraOffset) + AVOffset -= CharUnits::fromQuantity(ExtraOffset->getZExtValue()); + if (AVOffset.alignTo(Align) != AVOffset) { + if (Ptr.isBlockPointer()) + S.CCEDiag(Call->getArg(0), + diag::note_constexpr_baa_insufficient_alignment) + << 1 << AVOffset.getQuantity() << Align.getQuantity(); + else + S.CCEDiag(Call->getArg(0), + diag::note_constexpr_baa_value_insufficient_alignment) + << AVOffset.getQuantity() << Align.getQuantity(); + return false; + } + + S.Stk.push(Ptr); + return true; +} + static bool interp__builtin_ia32_bextr(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const Function *Func, @@ -1287,7 +1351,7 @@ static bool interp__builtin_ia32_addcarry_subborrow(InterpState &S, const InterpFrame *Frame, const Function *Func, const CallExpr *Call) { - if (!Call->getArg(0)->getType()->isIntegerType() || + if (Call->getNumArgs() != 4 || !Call->getArg(0)->getType()->isIntegerType() || !Call->getArg(1)->getType()->isIntegerType() || !Call->getArg(2)->getType()->isIntegerType()) return false; @@ -1905,6 +1969,11 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, return false; break; + case Builtin::BI__builtin_assume_aligned: + if (!interp__builtin_assume_aligned(S, OpPC, Frame, F, Call)) + return false; + break; + case clang::X86::BI__builtin_ia32_bextr_u32: case clang::X86::BI__builtin_ia32_bextr_u64: case clang::X86::BI__builtin_ia32_bextri_u32: diff --git a/clang/lib/AST/ByteCode/Pointer.cpp b/clang/lib/AST/ByteCode/Pointer.cpp index a52f0e336ef298..75b00dcb2ab242 100644 --- a/clang/lib/AST/ByteCode/Pointer.cpp +++ b/clang/lib/AST/ByteCode/Pointer.cpp @@ -253,11 +253,6 @@ APValue Pointer::toAPValue(const ASTContext &ASTCtx) const { } } - // FIXME(perf): We compute the lvalue path above, but we can't supply it - // for dummy pointers (that causes crashes later in CheckConstantExpression). - if (isDummy()) - Path.clear(); - // We assemble the LValuePath starting from the innermost pointer to the // outermost one. SO in a.b.c, the first element in Path will refer to // the field 'c', while later code expects it to refer to 'a'. diff --git a/clang/lib/AST/ByteCode/Program.cpp b/clang/lib/AST/ByteCode/Program.cpp index 23245a66b578ae..cd2665f755d7cb 100644 --- a/clang/lib/AST/ByteCode/Program.cpp +++ b/clang/lib/AST/ByteCode/Program.cpp @@ -33,7 +33,7 @@ const void *Program::getNativePointer(unsigned Idx) { return NativePointers[Idx]; } -unsigned Program::createGlobalString(const StringLiteral *S) { +unsigned Program::createGlobalString(const StringLiteral *S, const Expr *Base) { const size_t CharWidth = S->getCharByteWidth(); const size_t BitWidth = CharWidth * Ctx.getCharBit(); @@ -52,12 +52,15 @@ unsigned Program::createGlobalString(const StringLiteral *S) { llvm_unreachable("unsupported character width"); } + if (!Base) + Base = S; + // Create a descriptor for the string. - Descriptor *Desc = - allocateDescriptor(S, CharType, Descriptor::GlobalMD, S->getLength() + 1, - /*isConst=*/true, - /*isTemporary=*/false, - /*isMutable=*/false); + Descriptor *Desc = allocateDescriptor(Base, CharType, Descriptor::GlobalMD, + S->getLength() + 1, + /*isConst=*/true, + /*isTemporary=*/false, + /*isMutable=*/false); // Allocate storage for the string. // The byte length does not include the null terminator. diff --git a/clang/lib/AST/ByteCode/Program.h b/clang/lib/AST/ByteCode/Program.h index be84c40714a60b..f676672fb7ced5 100644 --- a/clang/lib/AST/ByteCode/Program.h +++ b/clang/lib/AST/ByteCode/Program.h @@ -64,7 +64,8 @@ class Program final { const void *getNativePointer(unsigned Idx); /// Emits a string literal among global data. - unsigned createGlobalString(const StringLiteral *S); + unsigned createGlobalString(const StringLiteral *S, + const Expr *Base = nullptr); /// Returns a pointer to a global. Pointer getPtrGlobal(unsigned Idx) const; diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 84ef9f74582ef6..a2f5b4183bbd23 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -1737,9 +1737,17 @@ void NamedDecl::printNestedNameSpecifier(raw_ostream &OS, continue; // Suppress inline namespace if it doesn't make the result ambiguous. - if (P.SuppressInlineNamespace && Ctx->isInlineNamespace() && NameInScope && - cast(Ctx)->isRedundantInlineQualifierFor(NameInScope)) - continue; + if (Ctx->isInlineNamespace() && NameInScope) { + bool isRedundant = + cast(Ctx)->isRedundantInlineQualifierFor(NameInScope); + if (P.SuppressInlineNamespace == + PrintingPolicy::SuppressInlineNamespaceMode::All || + (P.SuppressInlineNamespace == + PrintingPolicy::SuppressInlineNamespaceMode::Redundant && + isRedundant)) { + continue; + } + } // Skip non-named contexts such as linkage specifications and ExportDecls. const NamedDecl *ND = dyn_cast(Ctx); diff --git a/clang/lib/AST/ExprConstShared.h b/clang/lib/AST/ExprConstShared.h index efe8ee986d29b3..401ae629c86bfd 100644 --- a/clang/lib/AST/ExprConstShared.h +++ b/clang/lib/AST/ExprConstShared.h @@ -14,12 +14,17 @@ #ifndef LLVM_CLANG_LIB_AST_EXPRCONSTSHARED_H #define LLVM_CLANG_LIB_AST_EXPRCONSTSHARED_H +#include "clang/Basic/TypeTraits.h" + namespace llvm { class APFloat; } namespace clang { class QualType; class LangOptions; +class ASTContext; +class CharUnits; +class Expr; } // namespace clang using namespace clang; /// Values returned by __builtin_classify_type, chosen to match the values @@ -66,4 +71,7 @@ void HandleComplexComplexDiv(llvm::APFloat A, llvm::APFloat B, llvm::APFloat C, llvm::APFloat D, llvm::APFloat &ResR, llvm::APFloat &ResI); +CharUnits GetAlignOfExpr(const ASTContext &Ctx, const Expr *E, + UnaryExprOrTypeTrait ExprKind); + #endif diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 4d5af96093cfeb..70b223596d8b9b 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -9620,7 +9620,7 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) { return ExprEvaluatorBaseTy::VisitCastExpr(E); } -static CharUnits GetAlignOfType(EvalInfo &Info, QualType T, +static CharUnits GetAlignOfType(const ASTContext &Ctx, QualType T, UnaryExprOrTypeTrait ExprKind) { // C++ [expr.alignof]p3: // When alignof is applied to a reference type, the result is the @@ -9631,23 +9631,22 @@ static CharUnits GetAlignOfType(EvalInfo &Info, QualType T, return CharUnits::One(); const bool AlignOfReturnsPreferred = - Info.Ctx.getLangOpts().getClangABICompat() <= LangOptions::ClangABI::Ver7; + Ctx.getLangOpts().getClangABICompat() <= LangOptions::ClangABI::Ver7; // __alignof is defined to return the preferred alignment. // Before 8, clang returned the preferred alignment for alignof and _Alignof // as well. if (ExprKind == UETT_PreferredAlignOf || AlignOfReturnsPreferred) - return Info.Ctx.toCharUnitsFromBits( - Info.Ctx.getPreferredTypeAlign(T.getTypePtr())); + return Ctx.toCharUnitsFromBits(Ctx.getPreferredTypeAlign(T.getTypePtr())); // alignof and _Alignof are defined to return the ABI alignment. else if (ExprKind == UETT_AlignOf) - return Info.Ctx.getTypeAlignInChars(T.getTypePtr()); + return Ctx.getTypeAlignInChars(T.getTypePtr()); else llvm_unreachable("GetAlignOfType on a non-alignment ExprKind"); } -static CharUnits GetAlignOfExpr(EvalInfo &Info, const Expr *E, - UnaryExprOrTypeTrait ExprKind) { +CharUnits GetAlignOfExpr(const ASTContext &Ctx, const Expr *E, + UnaryExprOrTypeTrait ExprKind) { E = E->IgnoreParens(); // The kinds of expressions that we have special-case logic here for @@ -9657,22 +9656,22 @@ static CharUnits GetAlignOfExpr(EvalInfo &Info, const Expr *E, // alignof decl is always accepted, even if it doesn't make sense: we default // to 1 in those cases. if (const DeclRefExpr *DRE = dyn_cast(E)) - return Info.Ctx.getDeclAlign(DRE->getDecl(), - /*RefAsPointee*/true); + return Ctx.getDeclAlign(DRE->getDecl(), + /*RefAsPointee*/ true); if (const MemberExpr *ME = dyn_cast(E)) - return Info.Ctx.getDeclAlign(ME->getMemberDecl(), - /*RefAsPointee*/true); + return Ctx.getDeclAlign(ME->getMemberDecl(), + /*RefAsPointee*/ true); - return GetAlignOfType(Info, E->getType(), ExprKind); + return GetAlignOfType(Ctx, E->getType(), ExprKind); } static CharUnits getBaseAlignment(EvalInfo &Info, const LValue &Value) { if (const auto *VD = Value.Base.dyn_cast()) return Info.Ctx.getDeclAlign(VD); if (const auto *E = Value.Base.dyn_cast()) - return GetAlignOfExpr(Info, E, UETT_AlignOf); - return GetAlignOfType(Info, Value.Base.getTypeInfoType(), UETT_AlignOf); + return GetAlignOfExpr(Info.Ctx, E, UETT_AlignOf); + return GetAlignOfType(Info.Ctx, Value.Base.getTypeInfoType(), UETT_AlignOf); } /// Evaluate the value of the alignment argument to __builtin_align_{up,down}, @@ -9768,11 +9767,8 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, if (BaseAlignment < Align) { Result.Designator.setInvalid(); - // FIXME: Add support to Diagnostic for long / long long. - CCEDiag(E->getArg(0), - diag::note_constexpr_baa_insufficient_alignment) << 0 - << (unsigned)BaseAlignment.getQuantity() - << (unsigned)Align.getQuantity(); + CCEDiag(E->getArg(0), diag::note_constexpr_baa_insufficient_alignment) + << 0 << BaseAlignment.getQuantity() << Align.getQuantity(); return false; } } @@ -9783,11 +9779,11 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, (OffsetResult.Base ? CCEDiag(E->getArg(0), - diag::note_constexpr_baa_insufficient_alignment) << 1 + diag::note_constexpr_baa_insufficient_alignment) + << 1 : CCEDiag(E->getArg(0), diag::note_constexpr_baa_value_insufficient_alignment)) - << (int)OffsetResult.Offset.getQuantity() - << (unsigned)Align.getQuantity(); + << OffsetResult.Offset.getQuantity() << Align.getQuantity(); return false; } @@ -14478,11 +14474,11 @@ bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr( case UETT_PreferredAlignOf: case UETT_AlignOf: { if (E->isArgumentType()) - return Success(GetAlignOfType(Info, E->getArgumentType(), E->getKind()), - E); + return Success( + GetAlignOfType(Info.Ctx, E->getArgumentType(), E->getKind()), E); else - return Success(GetAlignOfExpr(Info, E->getArgumentExpr(), E->getKind()), - E); + return Success( + GetAlignOfExpr(Info.Ctx, E->getArgumentExpr(), E->getKind()), E); } case UETT_PtrAuthTypeDiscriminator: { diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index ca75bb97c158e1..008e87e7e5c14b 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -1413,7 +1413,9 @@ void TypePrinter::AppendScope(DeclContext *DC, raw_ostream &OS, // Only suppress an inline namespace if the name has the same lookup // results in the enclosing namespace. - if (Policy.SuppressInlineNamespace && NS->isInline() && NameInScope && + if (Policy.SuppressInlineNamespace != + PrintingPolicy::SuppressInlineNamespaceMode::None && + NS->isInline() && NameInScope && NS->isRedundantInlineQualifierFor(NameInScope)) return AppendScope(DC->getParent(), OS, NameInScope); diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp index 06309d327896b3..46dd44e6f2b24f 100644 --- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -655,7 +655,9 @@ bool HasNameMatcher::matchesNodeFullSlow(const NamedDecl &Node) const { PrintingPolicy Policy = Node.getASTContext().getPrintingPolicy(); Policy.SuppressUnwrittenScope = SkipUnwritten; - Policy.SuppressInlineNamespace = SkipUnwritten; + Policy.SuppressInlineNamespace = + SkipUnwritten ? PrintingPolicy::SuppressInlineNamespaceMode::All + : PrintingPolicy::SuppressInlineNamespaceMode::None; Node.printQualifiedName(OS, Policy); const StringRef FullName = OS.str(); diff --git a/clang/lib/Analysis/ProgramPoint.cpp b/clang/lib/Analysis/ProgramPoint.cpp index 2a91749affd2a6..768345c8425f02 100644 --- a/clang/lib/Analysis/ProgramPoint.cpp +++ b/clang/lib/Analysis/ProgramPoint.cpp @@ -157,7 +157,7 @@ void ProgramPoint::printJson(llvm::raw_ostream &Out, const char *NL) const { LHS->printJson(Out, nullptr, PP, AddQuotes); } else { Out << "null"; - } + } Out << ", \"rhs\": "; if (const Stmt *RHS = C->getRHS()) { diff --git a/clang/lib/Basic/IdentifierTable.cpp b/clang/lib/Basic/IdentifierTable.cpp index c9c9d927a5902e..16151c94464f99 100644 --- a/clang/lib/Basic/IdentifierTable.cpp +++ b/clang/lib/Basic/IdentifierTable.cpp @@ -406,6 +406,9 @@ ReservedLiteralSuffixIdStatus IdentifierInfo::isReservedLiteralSuffixId() const { StringRef Name = getName(); + // Note: the diag::warn_deprecated_literal_operator_id diagnostic depends on + // this being the first check we do, so if this order changes, we have to fix + // that as well. if (Name[0] != '_') return ReservedLiteralSuffixIdStatus::NotStartsWithUnderscore; diff --git a/clang/lib/Basic/Targets/DirectX.h b/clang/lib/Basic/Targets/DirectX.h index cf7ea5e83503dc..19b61252409b09 100644 --- a/clang/lib/Basic/Targets/DirectX.h +++ b/clang/lib/Basic/Targets/DirectX.h @@ -62,7 +62,7 @@ class LLVM_LIBRARY_VISIBILITY DirectXTargetInfo : public TargetInfo { PlatformName = llvm::Triple::getOSTypeName(Triple.getOS()); resetDataLayout("e-m:e-p:32:32-i1:32-i8:8-i16:16-i32:32-i64:64-f16:16-f32:" "32-f64:64-n8:16:32:64"); - TheCXXABI.set(TargetCXXABI::Microsoft); + TheCXXABI.set(TargetCXXABI::GenericItanium); } bool useFP16ConversionIntrinsics() const override { return false; } void getTargetDefines(const LangOptions &Opts, diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 57705f2d2d0423..465afd04740d89 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -13648,7 +13648,7 @@ Value *CodeGenFunction::EmitBPFBuiltinExpr(unsigned BuiltinID, Value *InfoKind = ConstantInt::get(Int64Ty, C->getSExtValue()); // Built the IR for the preserve_field_info intrinsic. - llvm::Function *FnGetFieldInfo = llvm::Intrinsic::getDeclaration( + llvm::Function *FnGetFieldInfo = llvm::Intrinsic::getOrInsertDeclaration( &CGM.getModule(), llvm::Intrinsic::bpf_preserve_field_info, {FieldAddr->getType()}); return Builder.CreateCall(FnGetFieldInfo, {FieldAddr, InfoKind}); @@ -13670,10 +13670,10 @@ Value *CodeGenFunction::EmitBPFBuiltinExpr(unsigned BuiltinID, llvm::Function *FnDecl; if (BuiltinID == BPF::BI__builtin_btf_type_id) - FnDecl = llvm::Intrinsic::getDeclaration( + FnDecl = llvm::Intrinsic::getOrInsertDeclaration( &CGM.getModule(), llvm::Intrinsic::bpf_btf_type_id, {}); else - FnDecl = llvm::Intrinsic::getDeclaration( + FnDecl = llvm::Intrinsic::getOrInsertDeclaration( &CGM.getModule(), llvm::Intrinsic::bpf_preserve_type_info, {}); CallInst *Fn = Builder.CreateCall(FnDecl, {SeqNumVal, FlagValue}); Fn->setMetadata(LLVMContext::MD_preserve_access_index, DbgInfo); @@ -13708,7 +13708,7 @@ Value *CodeGenFunction::EmitBPFBuiltinExpr(unsigned BuiltinID, Value *FlagValue = ConstantInt::get(Int64Ty, Flag->getSExtValue()); Value *SeqNumVal = ConstantInt::get(Int32Ty, BuiltinSeqNum++); - llvm::Function *IntrinsicFn = llvm::Intrinsic::getDeclaration( + llvm::Function *IntrinsicFn = llvm::Intrinsic::getOrInsertDeclaration( &CGM.getModule(), llvm::Intrinsic::bpf_preserve_enum_value, {}); CallInst *Fn = Builder.CreateCall(IntrinsicFn, {SeqNumVal, EnumStrVal, FlagValue}); @@ -18755,6 +18755,16 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, CGM.getHLSLRuntime().getNormalizeIntrinsic(), ArrayRef{X}, nullptr, "hlsl.normalize"); } + case Builtin::BI__builtin_hlsl_elementwise_degrees: { + Value *X = EmitScalarExpr(E->getArg(0)); + + assert(E->getArg(0)->getType()->hasFloatingRepresentation() && + "degree operand must have a float representation"); + + return Builder.CreateIntrinsic( + /*ReturnType=*/X->getType(), CGM.getHLSLRuntime().getDegreesIntrinsic(), + ArrayRef{X}, nullptr, "hlsl.degrees"); + } case Builtin::BI__builtin_hlsl_elementwise_frac: { Value *Op0 = EmitScalarExpr(E->getArg(0)); if (!E->getArg(0)->getType()->hasFloatingRepresentation()) @@ -18867,27 +18877,47 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: { ArrayRef{Op0, Op1}, nullptr, "hlsl.step"); } case Builtin::BI__builtin_hlsl_wave_get_lane_index: { - return EmitRuntimeCall(CGM.CreateRuntimeFunction( - llvm::FunctionType::get(IntTy, {}, false), "__hlsl_wave_get_lane_index", - {}, false, true)); + // We don't define a SPIR-V intrinsic, instead it is a SPIR-V built-in + // defined in SPIRVBuiltins.td. So instead we manually get the matching name + // for the DirectX intrinsic and the demangled builtin name + switch (CGM.getTarget().getTriple().getArch()) { + case llvm::Triple::dxil: + return EmitRuntimeCall(Intrinsic::getOrInsertDeclaration( + &CGM.getModule(), Intrinsic::dx_wave_getlaneindex)); + case llvm::Triple::spirv: + return EmitRuntimeCall(CGM.CreateRuntimeFunction( + llvm::FunctionType::get(IntTy, {}, false), + "__hlsl_wave_get_lane_index", {}, false, true)); + default: + llvm_unreachable( + "Intrinsic WaveGetLaneIndex not supported by target architecture"); + } } case Builtin::BI__builtin_hlsl_wave_is_first_lane: { Intrinsic::ID ID = CGM.getHLSLRuntime().getWaveIsFirstLaneIntrinsic(); - return EmitRuntimeCall(Intrinsic::getDeclaration(&CGM.getModule(), ID)); + return EmitRuntimeCall( + Intrinsic::getOrInsertDeclaration(&CGM.getModule(), ID)); } case Builtin::BI__builtin_hlsl_elementwise_sign: { - Value *Op0 = EmitScalarExpr(E->getArg(0)); + auto *Arg0 = E->getArg(0); + Value *Op0 = EmitScalarExpr(Arg0); llvm::Type *Xty = Op0->getType(); llvm::Type *retType = llvm::Type::getInt32Ty(this->getLLVMContext()); if (Xty->isVectorTy()) { - auto *XVecTy = E->getArg(0)->getType()->getAs(); + auto *XVecTy = Arg0->getType()->getAs(); retType = llvm::VectorType::get( retType, ElementCount::getFixed(XVecTy->getNumElements())); } - assert((E->getArg(0)->getType()->hasFloatingRepresentation() || - E->getArg(0)->getType()->hasSignedIntegerRepresentation()) && + assert((Arg0->getType()->hasFloatingRepresentation() || + Arg0->getType()->hasIntegerRepresentation()) && "sign operand must have a float or int representation"); + if (Arg0->getType()->hasUnsignedIntegerRepresentation()) { + Value *Cmp = Builder.CreateICmpEQ(Op0, ConstantInt::get(Xty, 0)); + return Builder.CreateSelect(Cmp, ConstantInt::get(retType, 0), + ConstantInt::get(retType, 1), "hlsl.sign"); + } + return Builder.CreateIntrinsic( retType, CGM.getHLSLRuntime().getSignIntrinsic(), ArrayRef{Op0}, nullptr, "hlsl.sign"); diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 609957b75d6e7e..06015a9e541ea2 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -287,7 +287,8 @@ PrintingPolicy CGDebugInfo::getPrintingPolicy() const { PP.SplitTemplateClosers = true; } - PP.SuppressInlineNamespace = false; + PP.SuppressInlineNamespace = + PrintingPolicy::SuppressInlineNamespaceMode::None; PP.PrintCanonicalTypes = true; PP.UsePreferredNames = false; PP.AlwaysIncludeTypeForTemplateArgument = true; diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index 563f728e29d781..30af9268b30e2e 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -2509,8 +2509,8 @@ void CodeGenFunction::pushRegularPartialArrayCleanup(llvm::Value *arrayBegin, llvm::Function *CodeGenModule::getLLVMLifetimeStartFn() { if (LifetimeStartFn) return LifetimeStartFn; - LifetimeStartFn = llvm::Intrinsic::getDeclaration(&getModule(), - llvm::Intrinsic::lifetime_start, AllocaInt8PtrTy); + LifetimeStartFn = llvm::Intrinsic::getOrInsertDeclaration( + &getModule(), llvm::Intrinsic::lifetime_start, AllocaInt8PtrTy); return LifetimeStartFn; } @@ -2518,8 +2518,8 @@ llvm::Function *CodeGenModule::getLLVMLifetimeStartFn() { llvm::Function *CodeGenModule::getLLVMLifetimeEndFn() { if (LifetimeEndFn) return LifetimeEndFn; - LifetimeEndFn = llvm::Intrinsic::getDeclaration(&getModule(), - llvm::Intrinsic::lifetime_end, AllocaInt8PtrTy); + LifetimeEndFn = llvm::Intrinsic::getOrInsertDeclaration( + &getModule(), llvm::Intrinsic::lifetime_end, AllocaInt8PtrTy); return LifetimeEndFn; } diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp index bb2ed237ee9f35..44a45413dbc45a 100644 --- a/clang/lib/CodeGen/CGException.cpp +++ b/clang/lib/CodeGen/CGException.cpp @@ -1843,7 +1843,7 @@ Address CodeGenFunction::recoverAddrOfEscapedLocal(CodeGenFunction &ParentCGF, std::make_pair(ParentAlloca, ParentCGF.EscapedLocals.size())); int FrameEscapeIdx = InsertPair.first->second; // call ptr @llvm.localrecover(ptr @parentFn, ptr %fp, i32 N) - llvm::Function *FrameRecoverFn = llvm::Intrinsic::getDeclaration( + llvm::Function *FrameRecoverFn = llvm::Intrinsic::getOrInsertDeclaration( &CGM.getModule(), llvm::Intrinsic::localrecover); RecoverCall = Builder.CreateCall( FrameRecoverFn, {ParentCGF.CurFn, ParentFP, @@ -1942,7 +1942,7 @@ void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF, // %1 = call ptr @llvm.localrecover(@"?fin$0@0@main@@",..) // %2 = load ptr, ptr %1, align 8 // ==> %2 is the frame-pointer of outermost host function - llvm::Function *FrameRecoverFn = llvm::Intrinsic::getDeclaration( + llvm::Function *FrameRecoverFn = llvm::Intrinsic::getOrInsertDeclaration( &CGM.getModule(), llvm::Intrinsic::localrecover); ParentFP = Builder.CreateCall( FrameRecoverFn, {ParentCGF.CurFn, ParentFP, diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index 05ff325216f55b..282fa44af212fb 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -75,6 +75,7 @@ class CGHLSLRuntime { GENERATE_HLSL_INTRINSIC_FUNCTION(All, all) GENERATE_HLSL_INTRINSIC_FUNCTION(Any, any) GENERATE_HLSL_INTRINSIC_FUNCTION(Cross, cross) + GENERATE_HLSL_INTRINSIC_FUNCTION(Degrees, degrees) GENERATE_HLSL_INTRINSIC_FUNCTION(Frac, frac) GENERATE_HLSL_INTRINSIC_FUNCTION(Length, length) GENERATE_HLSL_INTRINSIC_FUNCTION(Lerp, lerp) diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index e1fd9b72b8d7b2..f3023c7a20c405 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -463,7 +463,7 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) { EscapeArgs.resize(EscapedLocals.size()); for (auto &Pair : EscapedLocals) EscapeArgs[Pair.second] = Pair.first; - llvm::Function *FrameEscapeFn = llvm::Intrinsic::getDeclaration( + llvm::Function *FrameEscapeFn = llvm::Intrinsic::getOrInsertDeclaration( &CGM.getModule(), llvm::Intrinsic::localescape); CGBuilderTy(*this, AllocaInsertPt).CreateCall(FrameEscapeFn, EscapeArgs); } @@ -3130,7 +3130,7 @@ void CodeGenFunction::emitAlignmentAssumptionCheck( llvm::Instruction *Assumption) { assert(isa_and_nonnull(Assumption) && cast(Assumption)->getCalledOperand() == - llvm::Intrinsic::getDeclaration( + llvm::Intrinsic::getOrInsertDeclaration( Builder.GetInsertBlock()->getParent()->getParent(), llvm::Intrinsic::assume) && "Assumption should be a call to llvm.assume()."); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 5ba098144a74e7..7a7dea4668ad09 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -6218,8 +6218,8 @@ void CodeGenModule::emitIFuncDefinition(GlobalDecl GD) { llvm::Function *CodeGenModule::getIntrinsic(unsigned IID, ArrayRef Tys) { - return llvm::Intrinsic::getDeclaration(&getModule(), (llvm::Intrinsic::ID)IID, - Tys); + return llvm::Intrinsic::getOrInsertDeclaration(&getModule(), + (llvm::Intrinsic::ID)IID, Tys); } static llvm::StringMapEntry & diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp index 0b486a644f57b1..339632090a5b71 100644 --- a/clang/lib/CodeGen/CodeGenTypes.cpp +++ b/clang/lib/CodeGen/CodeGenTypes.cpp @@ -60,7 +60,8 @@ void CodeGenTypes::addRecordTypeName(const RecordDecl *RD, // example, we should probably enable PrintCanonicalTypes and // FullyQualifiedNames. PrintingPolicy Policy = RD->getASTContext().getPrintingPolicy(); - Policy.SuppressInlineNamespace = false; + Policy.SuppressInlineNamespace = + PrintingPolicy::SuppressInlineNamespaceMode::None; // Name the codegen type after the typedef name // if there is no tag type name available diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index 965e09a7a760ec..75dab596e1b2c4 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -2997,6 +2997,10 @@ void ItaniumCXXABI::registerGlobalDtor(CodeGenFunction &CGF, const VarDecl &D, if (D.isNoDestroy(CGM.getContext())) return; + // HLSL doesn't support atexit. + if (CGM.getLangOpts().HLSL) + return CGM.AddCXXDtorEntry(dtor, addr); + // OpenMP offloading supports C++ constructors and destructors but we do not // always have 'atexit' available. Instead lower these to use the LLVM global // destructors which we can handle directly in the runtime. Note that this is diff --git a/clang/lib/CodeGen/Targets/SystemZ.cpp b/clang/lib/CodeGen/Targets/SystemZ.cpp index 56129622f48dbd..23c96fa5cf98cb 100644 --- a/clang/lib/CodeGen/Targets/SystemZ.cpp +++ b/clang/lib/CodeGen/Targets/SystemZ.cpp @@ -110,8 +110,8 @@ class SystemZTargetCodeGenInfo : public TargetCodeGenInfo { if (Ty->isFloatTy() || Ty->isDoubleTy() || Ty->isFP128Ty()) { llvm::Module &M = CGM.getModule(); auto &Ctx = M.getContext(); - llvm::Function *TDCFunc = - llvm::Intrinsic::getDeclaration(&M, llvm::Intrinsic::s390_tdc, Ty); + llvm::Function *TDCFunc = llvm::Intrinsic::getOrInsertDeclaration( + &M, llvm::Intrinsic::s390_tdc, Ty); unsigned TDCBits = 0; switch (BuiltinID) { case Builtin::BI__builtin_isnan: diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index a5d43bdac23735..ba850cf3803e9b 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -2029,7 +2029,7 @@ void Driver::PrintHelp(bool ShowHidden) const { void Driver::PrintVersion(const Compilation &C, raw_ostream &OS) const { if (IsFlangMode()) { - OS << getClangToolFullVersion("flang-new") << '\n'; + OS << getClangToolFullVersion("flang") << '\n'; } else { // FIXME: The following handlers should use a callback mechanism, we don't // know what the client would like to do. diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp index de250322b3b34d..4df31770950858 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -386,6 +386,9 @@ static const DriverSuffix *FindDriverSuffix(StringRef ProgName, size_t &Pos) { {"cl", "--driver-mode=cl"}, {"++", "--driver-mode=g++"}, {"flang", "--driver-mode=flang"}, + // For backwards compatibility, we create a symlink for `flang` called + // `flang-new`. This will be removed in the future. + {"flang-new", "--driver-mode=flang"}, {"clang-dxc", "--driver-mode=dxc"}, }; diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp index 3703832992bcb1..e5042327bbde4c 100644 --- a/clang/lib/Driver/ToolChains/Flang.cpp +++ b/clang/lib/Driver/ToolChains/Flang.cpp @@ -788,6 +788,9 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_fopenmp_force_usm)) CmdArgs.push_back("-fopenmp-force-usm"); + // TODO: OpenMP support isn't "done" yet, so for now we warn that it + // is experimental. + D.Diag(diag::warn_openmp_experimental); // FIXME: Clang supports a whole bunch more flags here. break; @@ -882,14 +885,12 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Input.getFilename()); - // TODO: Replace flang-new with flang once the new driver replaces the - // throwaway driver - const char *Exec = Args.MakeArgString(D.GetProgramPath("flang-new", TC)); + const char *Exec = Args.MakeArgString(D.GetProgramPath("flang", TC)); C.addCommand(std::make_unique(JA, *this, ResponseFileSupport::AtFileUTF8(), Exec, CmdArgs, Inputs, Output)); } -Flang::Flang(const ToolChain &TC) : Tool("flang-new", "flang frontend", TC) {} +Flang::Flang(const ToolChain &TC) : Tool("flang", "flang frontend", TC) {} Flang::~Flang() {} diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp index e4b462b9b0fd81..64f90c493c1055 100644 --- a/clang/lib/Frontend/FrontendActions.cpp +++ b/clang/lib/Frontend/FrontendActions.cpp @@ -457,8 +457,6 @@ class DefaultTemplateInstCallback : public TemplateInstantiationCallback { return "BuildingDeductionGuides"; case CodeSynthesisContext::TypeAliasTemplateInstantiation: return "TypeAliasTemplateInstantiation"; - case CodeSynthesisContext::PartialOrderingTTP: - return "PartialOrderingTTP"; } return ""; } diff --git a/clang/lib/Headers/emmintrin.h b/clang/lib/Headers/emmintrin.h index d2121408c114b5..d6494762169b25 100644 --- a/clang/lib/Headers/emmintrin.h +++ b/clang/lib/Headers/emmintrin.h @@ -86,8 +86,8 @@ typedef __bf16 __m128bh __attribute__((__vector_size__(16), __aligned__(16))); /// \returns A 128-bit vector of [2 x double] whose lower 64 bits contain the /// sum of the lower 64 bits of both operands. The upper 64 bits are copied /// from the upper 64 bits of the first source operand. -static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_add_sd(__m128d __a, - __m128d __b) { +static __inline__ __m128d __DEFAULT_FN_ATTRS_CONSTEXPR _mm_add_sd(__m128d __a, + __m128d __b) { __a[0] += __b[0]; return __a; } @@ -104,8 +104,8 @@ static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_add_sd(__m128d __a, /// A 128-bit vector of [2 x double] containing one of the source operands. /// \returns A 128-bit vector of [2 x double] containing the sums of both /// operands. -static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_add_pd(__m128d __a, - __m128d __b) { +static __inline__ __m128d __DEFAULT_FN_ATTRS_CONSTEXPR _mm_add_pd(__m128d __a, + __m128d __b) { return (__m128d)((__v2df)__a + (__v2df)__b); } @@ -126,8 +126,8 @@ static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_add_pd(__m128d __a, /// \returns A 128-bit vector of [2 x double] whose lower 64 bits contain the /// difference of the lower 64 bits of both operands. The upper 64 bits are /// copied from the upper 64 bits of the first source operand. -static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_sub_sd(__m128d __a, - __m128d __b) { +static __inline__ __m128d __DEFAULT_FN_ATTRS_CONSTEXPR _mm_sub_sd(__m128d __a, + __m128d __b) { __a[0] -= __b[0]; return __a; } @@ -144,8 +144,8 @@ static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_sub_sd(__m128d __a, /// A 128-bit vector of [2 x double] containing the subtrahend. /// \returns A 128-bit vector of [2 x double] containing the differences between /// both operands. -static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_sub_pd(__m128d __a, - __m128d __b) { +static __inline__ __m128d __DEFAULT_FN_ATTRS_CONSTEXPR _mm_sub_pd(__m128d __a, + __m128d __b) { return (__m128d)((__v2df)__a - (__v2df)__b); } @@ -165,8 +165,8 @@ static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_sub_pd(__m128d __a, /// \returns A 128-bit vector of [2 x double] whose lower 64 bits contain the /// product of the lower 64 bits of both operands. The upper 64 bits are /// copied from the upper 64 bits of the first source operand. -static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_mul_sd(__m128d __a, - __m128d __b) { +static __inline__ __m128d __DEFAULT_FN_ATTRS_CONSTEXPR _mm_mul_sd(__m128d __a, + __m128d __b) { __a[0] *= __b[0]; return __a; } @@ -183,8 +183,8 @@ static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_mul_sd(__m128d __a, /// A 128-bit vector of [2 x double] containing one of the operands. /// \returns A 128-bit vector of [2 x double] containing the products of both /// operands. -static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_mul_pd(__m128d __a, - __m128d __b) { +static __inline__ __m128d __DEFAULT_FN_ATTRS_CONSTEXPR _mm_mul_pd(__m128d __a, + __m128d __b) { return (__m128d)((__v2df)__a * (__v2df)__b); } @@ -205,8 +205,8 @@ static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_mul_pd(__m128d __a, /// \returns A 128-bit vector of [2 x double] whose lower 64 bits contain the /// quotient of the lower 64 bits of both operands. The upper 64 bits are /// copied from the upper 64 bits of the first source operand. -static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_div_sd(__m128d __a, - __m128d __b) { +static __inline__ __m128d __DEFAULT_FN_ATTRS_CONSTEXPR _mm_div_sd(__m128d __a, + __m128d __b) { __a[0] /= __b[0]; return __a; } @@ -224,8 +224,8 @@ static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_div_sd(__m128d __a, /// A 128-bit vector of [2 x double] containing the divisor. /// \returns A 128-bit vector of [2 x double] containing the quotients of both /// operands. -static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_div_pd(__m128d __a, - __m128d __b) { +static __inline__ __m128d __DEFAULT_FN_ATTRS_CONSTEXPR _mm_div_pd(__m128d __a, + __m128d __b) { return (__m128d)((__v2df)__a / (__v2df)__b); } @@ -373,8 +373,8 @@ static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_max_pd(__m128d __a, /// A 128-bit vector of [2 x double] containing one of the source operands. /// \returns A 128-bit vector of [2 x double] containing the bitwise AND of the /// values between both operands. -static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_and_pd(__m128d __a, - __m128d __b) { +static __inline__ __m128d __DEFAULT_FN_ATTRS_CONSTEXPR _mm_and_pd(__m128d __a, + __m128d __b) { return (__m128d)((__v2du)__a & (__v2du)__b); } @@ -393,8 +393,8 @@ static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_and_pd(__m128d __a, /// \returns A 128-bit vector of [2 x double] containing the bitwise AND of the /// values in the second operand and the one's complement of the first /// operand. -static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_andnot_pd(__m128d __a, - __m128d __b) { +static __inline__ __m128d __DEFAULT_FN_ATTRS_CONSTEXPR +_mm_andnot_pd(__m128d __a, __m128d __b) { return (__m128d)(~(__v2du)__a & (__v2du)__b); } @@ -410,8 +410,8 @@ static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_andnot_pd(__m128d __a, /// A 128-bit vector of [2 x double] containing one of the source operands. /// \returns A 128-bit vector of [2 x double] containing the bitwise OR of the /// values between both operands. -static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_or_pd(__m128d __a, - __m128d __b) { +static __inline__ __m128d __DEFAULT_FN_ATTRS_CONSTEXPR _mm_or_pd(__m128d __a, + __m128d __b) { return (__m128d)((__v2du)__a | (__v2du)__b); } @@ -427,8 +427,8 @@ static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_or_pd(__m128d __a, /// A 128-bit vector of [2 x double] containing one of the source operands. /// \returns A 128-bit vector of [2 x double] containing the bitwise XOR of the /// values between both operands. -static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_xor_pd(__m128d __a, - __m128d __b) { +static __inline__ __m128d __DEFAULT_FN_ATTRS_CONSTEXPR _mm_xor_pd(__m128d __a, + __m128d __b) { return (__m128d)((__v2du)__a ^ (__v2du)__b); } @@ -1306,7 +1306,8 @@ static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_cvtpd_ps(__m128d __a) { /// floating-point elements are converted to double-precision values. The /// upper two elements are unused. /// \returns A 128-bit vector of [2 x double] containing the converted values. -static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_cvtps_pd(__m128 __a) { +static __inline__ __m128d __DEFAULT_FN_ATTRS_CONSTEXPR +_mm_cvtps_pd(__m128 __a) { return (__m128d) __builtin_convertvector( __builtin_shufflevector((__v4sf)__a, (__v4sf)__a, 0, 1), __v2df); } @@ -1327,7 +1328,8 @@ static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_cvtps_pd(__m128 __a) { /// /// The upper two elements are unused. /// \returns A 128-bit vector of [2 x double] containing the converted values. -static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_cvtepi32_pd(__m128i __a) { +static __inline__ __m128d __DEFAULT_FN_ATTRS_CONSTEXPR +_mm_cvtepi32_pd(__m128i __a) { return (__m128d) __builtin_convertvector( __builtin_shufflevector((__v4si)__a, (__v4si)__a, 0, 1), __v2df); } @@ -1413,8 +1415,8 @@ static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_cvtsd_ss(__m128 __a, /// \returns A 128-bit vector of [2 x double]. The lower 64 bits contain the /// converted value from the second parameter. The upper 64 bits are copied /// from the upper 64 bits of the first parameter. -static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_cvtsi32_sd(__m128d __a, - int __b) { +static __inline__ __m128d __DEFAULT_FN_ATTRS_CONSTEXPR +_mm_cvtsi32_sd(__m128d __a, int __b) { __a[0] = __b; return __a; } @@ -1438,8 +1440,8 @@ static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_cvtsi32_sd(__m128d __a, /// \returns A 128-bit vector of [2 x double]. The lower 64 bits contain the /// converted value from the second parameter. The upper 64 bits are copied /// from the upper 64 bits of the first parameter. -static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_cvtss_sd(__m128d __a, - __m128 __b) { +static __inline__ __m128d __DEFAULT_FN_ATTRS_CONSTEXPR +_mm_cvtss_sd(__m128d __a, __m128 __b) { __a[0] = __b[0]; return __a; } @@ -1535,7 +1537,8 @@ static __inline__ __m64 __DEFAULT_FN_ATTRS _mm_cvttpd_pi32(__m128d __a) { /// \param __a /// A 64-bit vector of [2 x i32]. /// \returns A 128-bit vector of [2 x double] containing the converted values. -static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_cvtpi32_pd(__m64 __a) { +static __inline__ __m128d __DEFAULT_FN_ATTRS_CONSTEXPR +_mm_cvtpi32_pd(__m64 __a) { return (__m128d) __builtin_convertvector((__v2si)__a, __v2df); } @@ -1550,7 +1553,8 @@ static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_cvtpi32_pd(__m64 __a) { /// A 128-bit vector of [2 x double]. The lower 64 bits are returned. /// \returns A double-precision floating-point value copied from the lower 64 /// bits of \a __a. -static __inline__ double __DEFAULT_FN_ATTRS _mm_cvtsd_f64(__m128d __a) { +static __inline__ double __DEFAULT_FN_ATTRS_CONSTEXPR +_mm_cvtsd_f64(__m128d __a) { return __a[0]; } @@ -1785,7 +1789,7 @@ static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_undefined_pd(void) { /// \returns An initialized 128-bit floating-point vector of [2 x double]. The /// lower 64 bits contain the value of the parameter. The upper 64 bits are /// set to zero. -static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_set_sd(double __w) { +static __inline__ __m128d __DEFAULT_FN_ATTRS_CONSTEXPR _mm_set_sd(double __w) { return __extension__(__m128d){__w, 0.0}; } @@ -1801,7 +1805,7 @@ static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_set_sd(double __w) { /// A double-precision floating-point value used to initialize each vector /// element of the result. /// \returns An initialized 128-bit floating-point vector of [2 x double]. -static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_set1_pd(double __w) { +static __inline__ __m128d __DEFAULT_FN_ATTRS_CONSTEXPR _mm_set1_pd(double __w) { return __extension__(__m128d){__w, __w}; } @@ -1817,7 +1821,7 @@ static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_set1_pd(double __w) { /// A double-precision floating-point value used to initialize each vector /// element of the result. /// \returns An initialized 128-bit floating-point vector of [2 x double]. -static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_set_pd1(double __w) { +static __inline__ __m128d __DEFAULT_FN_ATTRS_CONSTEXPR _mm_set_pd1(double __w) { return _mm_set1_pd(__w); } @@ -1835,8 +1839,8 @@ static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_set_pd1(double __w) { /// A double-precision floating-point value used to initialize the lower 64 /// bits of the result. /// \returns An initialized 128-bit floating-point vector of [2 x double]. -static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_set_pd(double __w, - double __x) { +static __inline__ __m128d __DEFAULT_FN_ATTRS_CONSTEXPR _mm_set_pd(double __w, + double __x) { return __extension__(__m128d){__x, __w}; } @@ -1855,8 +1859,8 @@ static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_set_pd(double __w, /// A double-precision floating-point value used to initialize the upper 64 /// bits of the result. /// \returns An initialized 128-bit floating-point vector of [2 x double]. -static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_setr_pd(double __w, - double __x) { +static __inline__ __m128d __DEFAULT_FN_ATTRS_CONSTEXPR _mm_setr_pd(double __w, + double __x) { return __extension__(__m128d){__w, __x}; } @@ -1888,8 +1892,8 @@ static __inline__ __m128d __DEFAULT_FN_ATTRS_CONSTEXPR _mm_setzero_pd(void) { /// A 128-bit vector of [2 x double]. The lower 64 bits are written to the /// lower 64 bits of the result. /// \returns A 128-bit vector of [2 x double] containing the moved values. -static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_move_sd(__m128d __a, - __m128d __b) { +static __inline__ __m128d __DEFAULT_FN_ATTRS_CONSTEXPR +_mm_move_sd(__m128d __a, __m128d __b) { __a[0] = __b[0]; return __a; } @@ -3323,7 +3327,8 @@ static __inline__ long long __DEFAULT_FN_ATTRS _mm_cvttsd_si64(__m128d __a) { /// \param __a /// A 128-bit integer vector. /// \returns A 128-bit vector of [4 x float] containing the converted values. -static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_cvtepi32_ps(__m128i __a) { +static __inline__ __m128 __DEFAULT_FN_ATTRS_CONSTEXPR +_mm_cvtepi32_ps(__m128i __a) { return (__m128) __builtin_convertvector((__v4si)__a, __v4sf); } @@ -4651,8 +4656,8 @@ static __inline__ __m128i __DEFAULT_FN_ATTRS _mm_move_epi64(__m128i __a) { /// A 128-bit vector of [2 x double]. \n /// Bits [127:64] are written to bits [127:64] of the destination. /// \returns A 128-bit vector of [2 x double] containing the interleaved values. -static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_unpackhi_pd(__m128d __a, - __m128d __b) { +static __inline__ __m128d __DEFAULT_FN_ATTRS_CONSTEXPR +_mm_unpackhi_pd(__m128d __a, __m128d __b) { return __builtin_shufflevector((__v2df)__a, (__v2df)__b, 1, 2 + 1); } @@ -4671,8 +4676,8 @@ static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_unpackhi_pd(__m128d __a, /// A 128-bit vector of [2 x double]. \n /// Bits [63:0] are written to bits [127:64] of the destination. /// \returns A 128-bit vector of [2 x double] containing the interleaved values. -static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_unpacklo_pd(__m128d __a, - __m128d __b) { +static __inline__ __m128d __DEFAULT_FN_ATTRS_CONSTEXPR +_mm_unpacklo_pd(__m128d __a, __m128d __b) { return __builtin_shufflevector((__v2df)__a, (__v2df)__b, 0, 2 + 0); } @@ -4735,7 +4740,8 @@ static __inline__ int __DEFAULT_FN_ATTRS _mm_movemask_pd(__m128d __a) { /// A 128-bit floating-point vector of [2 x double]. /// \returns A 128-bit floating-point vector of [4 x float] containing the same /// bitwise pattern as the parameter. -static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_castpd_ps(__m128d __a) { +static __inline__ __m128 __DEFAULT_FN_ATTRS_CONSTEXPR +_mm_castpd_ps(__m128d __a) { return (__m128)__a; } @@ -4750,7 +4756,8 @@ static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_castpd_ps(__m128d __a) { /// A 128-bit floating-point vector of [2 x double]. /// \returns A 128-bit integer vector containing the same bitwise pattern as the /// parameter. -static __inline__ __m128i __DEFAULT_FN_ATTRS _mm_castpd_si128(__m128d __a) { +static __inline__ __m128i __DEFAULT_FN_ATTRS_CONSTEXPR +_mm_castpd_si128(__m128d __a) { return (__m128i)__a; } diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h index f39a68ba847e98..137467e5a782ce 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -766,6 +766,36 @@ uint64_t3 countbits(uint64_t3); _HLSL_BUILTIN_ALIAS(__builtin_elementwise_popcount) uint64_t4 countbits(uint64_t4); +//===----------------------------------------------------------------------===// +// degrees builtins +//===----------------------------------------------------------------------===// + +/// \fn T degrees(T x) +/// \brief Converts the specified value from radians to degrees. +/// \param x The specified input value. + +_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_degrees) +half degrees(half); +_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_degrees) +half2 degrees(half2); +_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_degrees) +half3 degrees(half3); +_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_degrees) +half4 degrees(half4); + +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_degrees) +float degrees(float); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_degrees) +float2 degrees(float2); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_degrees) +float3 degrees(float3); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_degrees) +float4 degrees(float4); + //===----------------------------------------------------------------------===// // dot product builtins //===----------------------------------------------------------------------===// @@ -2088,6 +2118,19 @@ int3 sign(int16_t3); _HLSL_AVAILABILITY(shadermodel, 6.2) _HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign) int4 sign(int16_t4); + +_HLSL_AVAILABILITY(shadermodel, 6.2) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign) +int sign(uint16_t); +_HLSL_AVAILABILITY(shadermodel, 6.2) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign) +int2 sign(uint16_t2); +_HLSL_AVAILABILITY(shadermodel, 6.2) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign) +int3 sign(uint16_t3); +_HLSL_AVAILABILITY(shadermodel, 6.2) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign) +int4 sign(uint16_t4); #endif _HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) @@ -2112,6 +2155,15 @@ int3 sign(int3); _HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign) int4 sign(int4); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign) +int sign(uint); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign) +int2 sign(uint2); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign) +int3 sign(uint3); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign) +int4 sign(uint4); + _HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign) int sign(float); _HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign) @@ -2130,6 +2182,15 @@ int3 sign(int64_t3); _HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign) int4 sign(int64_t4); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign) +int sign(uint64_t); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign) +int2 sign(uint64_t2); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign) +int3 sign(uint64_t3); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign) +int4 sign(uint64_t4); + _HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign) int sign(double); _HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_sign) diff --git a/clang/lib/Headers/xmmintrin.h b/clang/lib/Headers/xmmintrin.h index 2aa688adefc25a..20e66d190113a3 100644 --- a/clang/lib/Headers/xmmintrin.h +++ b/clang/lib/Headers/xmmintrin.h @@ -1618,9 +1618,8 @@ _mm_cvtt_ps2pi(__m128 __a) /// \returns A 128-bit vector of [4 x float] whose lower 32 bits contain the /// converted value of the second operand. The upper 96 bits are copied from /// the upper 96 bits of the first operand. -static __inline__ __m128 __DEFAULT_FN_ATTRS -_mm_cvtsi32_ss(__m128 __a, int __b) -{ +static __inline__ __m128 __DEFAULT_FN_ATTRS_CONSTEXPR _mm_cvtsi32_ss(__m128 __a, + int __b) { __a[0] = __b; return __a; } @@ -1641,9 +1640,8 @@ _mm_cvtsi32_ss(__m128 __a, int __b) /// \returns A 128-bit vector of [4 x float] whose lower 32 bits contain the /// converted value of the second operand. The upper 96 bits are copied from /// the upper 96 bits of the first operand. -static __inline__ __m128 __DEFAULT_FN_ATTRS -_mm_cvt_si2ss(__m128 __a, int __b) -{ +static __inline__ __m128 __DEFAULT_FN_ATTRS_CONSTEXPR _mm_cvt_si2ss(__m128 __a, + int __b) { return _mm_cvtsi32_ss(__a, __b); } @@ -1665,9 +1663,8 @@ _mm_cvt_si2ss(__m128 __a, int __b) /// \returns A 128-bit vector of [4 x float] whose lower 32 bits contain the /// converted value of the second operand. The upper 96 bits are copied from /// the upper 96 bits of the first operand. -static __inline__ __m128 __DEFAULT_FN_ATTRS -_mm_cvtsi64_ss(__m128 __a, long long __b) -{ +static __inline__ __m128 __DEFAULT_FN_ATTRS_CONSTEXPR +_mm_cvtsi64_ss(__m128 __a, long long __b) { __a[0] = __b; return __a; } diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp index f0b4593e0cc22e..ecc5166d7b814c 100644 --- a/clang/lib/Lex/Preprocessor.cpp +++ b/clang/lib/Lex/Preprocessor.cpp @@ -902,6 +902,10 @@ void Preprocessor::Lex(Token &Result) { case tok::r_brace: StdCXXImportSeqState.handleCloseBrace(); break; +#define PRAGMA_ANNOTATION(X) case tok::annot_##X: +// For `#pragma ...` mimic ';'. +#include "clang/Basic/TokenKinds.def" +#undef PRAGMA_ANNOTATION // This token is injected to represent the translation of '#include "a.h"' // into "import a.h;". Mimic the notional ';'. case tok::annot_module_include: diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index f05760428458b1..9f91ee9a39f2f9 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -2777,3 +2777,31 @@ bool Sema::isDeclaratorFunctionLike(Declarator &D) { }); return Result; } + +Attr *Sema::CreateAnnotationAttr(const AttributeCommonInfo &CI, StringRef Annot, + MutableArrayRef Args) { + + auto *A = AnnotateAttr::Create(Context, Annot, Args.data(), Args.size(), CI); + if (!ConstantFoldAttrArgs( + CI, MutableArrayRef(A->args_begin(), A->args_end()))) { + return nullptr; + } + return A; +} + +Attr *Sema::CreateAnnotationAttr(const ParsedAttr &AL) { + // Make sure that there is a string literal as the annotation's first + // argument. + StringRef Str; + if (!checkStringLiteralArgumentAttr(AL, 0, Str)) + return nullptr; + + llvm::SmallVector Args; + Args.reserve(AL.getNumArgs() - 1); + for (unsigned Idx = 1; Idx < AL.getNumArgs(); Idx++) { + assert(!AL.isArgIdent(Idx)); + Args.push_back(AL.getArgAsExpr(Idx)); + } + + return CreateAnnotationAttr(AL, Str, Args); +} diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index e2174ba926f17f..6759aae37afac1 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -3958,30 +3958,11 @@ static void handleTransparentUnionAttr(Sema &S, Decl *D, const ParsedAttr &AL) { RD->addAttr(::new (S.Context) TransparentUnionAttr(S.Context, AL)); } -void Sema::AddAnnotationAttr(Decl *D, const AttributeCommonInfo &CI, - StringRef Str, MutableArrayRef Args) { - auto *Attr = AnnotateAttr::Create(Context, Str, Args.data(), Args.size(), CI); - if (ConstantFoldAttrArgs( - CI, MutableArrayRef(Attr->args_begin(), Attr->args_end()))) { - D->addAttr(Attr); - } -} - static void handleAnnotateAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - // Make sure that there is a string literal as the annotation's first - // argument. - StringRef Str; - if (!S.checkStringLiteralArgumentAttr(AL, 0, Str)) - return; - - llvm::SmallVector Args; - Args.reserve(AL.getNumArgs() - 1); - for (unsigned Idx = 1; Idx < AL.getNumArgs(); Idx++) { - assert(!AL.isArgIdent(Idx)); - Args.push_back(AL.getArgAsExpr(Idx)); + auto *Attr = S.CreateAnnotationAttr(AL); + if (Attr) { + D->addAttr(Attr); } - - S.AddAnnotationAttr(D, AL, Str, Args); } static void handleAlignValueAttr(Sema &S, Decl *D, const ParsedAttr &AL) { diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index e2141e03ca4230..4e37385710af5e 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -5649,6 +5649,8 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) { runWithSufficientStackSpace(Loc, [&] { MarkDeclarationsReferencedInExpr(E, /*SkipLocalVariables=*/false); }); + if (isInLifetimeExtendingContext()) + DiscardCleanupsInEvaluationContext(); // C++11 [class.base.init]p7: // The initialization of each base and member constitutes a // full-expression. diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 8e9bcb10a80b46..d39a545b66c151 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -503,17 +503,23 @@ bool Sema::checkLiteralOperatorId(const CXXScopeSpec &SS, const IdentifierInfo *II = Name.Identifier; ReservedIdentifierStatus Status = II->isReserved(PP.getLangOpts()); SourceLocation Loc = Name.getEndLoc(); - if (!PP.getSourceManager().isInSystemHeader(Loc)) { - if (auto Hint = FixItHint::CreateReplacement( - Name.getSourceRange(), - (StringRef("operator\"\"") + II->getName()).str()); - isReservedInAllContexts(Status)) { - Diag(Loc, diag::warn_reserved_extern_symbol) - << II << static_cast(Status) << Hint; - } else { - Diag(Loc, diag::warn_deprecated_literal_operator_id) << II << Hint; - } - } + + auto Hint = FixItHint::CreateReplacement( + Name.getSourceRange(), + (StringRef("operator\"\"") + II->getName()).str()); + + // Only emit this diagnostic if we start with an underscore, else the + // diagnostic for C++11 requiring a space between the quotes and the + // identifier conflicts with this and gets confusing. The diagnostic stating + // this is a reserved name should force the underscore, which gets this + // back. + if (II->isReservedLiteralSuffixId() != + ReservedLiteralSuffixIdStatus::NotStartsWithUnderscore) + Diag(Loc, diag::warn_deprecated_literal_operator_id) << II << Hint; + + if (isReservedInAllContexts(Status)) + Diag(Loc, diag::warn_reserved_extern_symbol) + << II << static_cast(Status) << Hint; } if (!SS.isValid()) diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index d2d2df829e7b11..137b15c8fcfe98 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -1708,9 +1708,9 @@ static bool CheckNoDoubleVectors(Sema *S, CallExpr *TheCall) { return CheckArgsTypesAreCorrect(S, TheCall, S->Context.FloatTy, checkDoubleVector); } -static bool CheckFloatingOrSignedIntRepresentation(Sema *S, CallExpr *TheCall) { +static bool CheckFloatingOrIntRepresentation(Sema *S, CallExpr *TheCall) { auto checkAllSignedTypes = [](clang::QualType PassedType) -> bool { - return !PassedType->hasSignedIntegerRepresentation() && + return !PassedType->hasIntegerRepresentation() && !PassedType->hasFloatingRepresentation(); }; return CheckArgsTypesAreCorrect(S, TheCall, S->Context.IntTy, @@ -1896,6 +1896,7 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { return true; break; } + case Builtin::BI__builtin_hlsl_elementwise_degrees: case Builtin::BI__builtin_hlsl_elementwise_radians: case Builtin::BI__builtin_hlsl_elementwise_rsqrt: case Builtin::BI__builtin_hlsl_elementwise_frac: { @@ -1966,7 +1967,7 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { break; } case Builtin::BI__builtin_hlsl_elementwise_sign: { - if (CheckFloatingOrSignedIntRepresentation(&SemaRef, TheCall)) + if (CheckFloatingOrIntRepresentation(&SemaRef, TheCall)) return true; if (SemaRef.PrepareBuiltinElementwiseMathOneArgCall(TheCall)) return true; @@ -1992,6 +1993,11 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { return true; break; } + case Builtin::BI__builtin_hlsl_wave_get_lane_index: { + if (SemaRef.checkArgCount(TheCall, 0)) + return true; + break; + } case Builtin::BI__builtin_elementwise_acos: case Builtin::BI__builtin_elementwise_asin: case Builtin::BI__builtin_elementwise_atan: diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index edd1fe40fdf278..5d6a586fe5a2cf 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -763,6 +763,8 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field, SemaRef.currentEvaluationContext().DelayedDefaultInitializationContext = SemaRef.parentEvaluationContext() .DelayedDefaultInitializationContext; + SemaRef.currentEvaluationContext().InLifetimeExtendingContext = + SemaRef.parentEvaluationContext().InLifetimeExtendingContext; DIE = SemaRef.BuildCXXDefaultInitExpr(Loc, Field); } if (DIE.isInvalid()) { diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 60fa195221c938..f3f62474d06441 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -3666,9 +3666,7 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R, TemplateArgumentLoc Arg(TemplateArgument(StringLit), StringLit); if (CheckTemplateArgument( Params->getParam(0), Arg, FD, R.getNameLoc(), R.getNameLoc(), - 0, SugaredChecked, CanonicalChecked, CTAK_Specified, - /*PartialOrdering=*/false, - /*MatchedPackOnParmToNonPackOnArg=*/nullptr) || + 0, SugaredChecked, CanonicalChecked, CTAK_Specified) || Trap.hasErrorOccurred()) IsTemplate = false; } diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index f545e9341e1ae6..2cde8131108fbe 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -6864,8 +6864,7 @@ void Sema::AddOverloadCandidate( OverloadCandidateSet &CandidateSet, bool SuppressUserConversions, bool PartialOverloading, bool AllowExplicit, bool AllowExplicitConversions, ADLCallKind IsADLCandidate, ConversionSequenceList EarlyConversions, - OverloadCandidateParamOrder PO, bool AggregateCandidateDeduction, - bool HasMatchedPackOnParmToNonPackOnArg) { + OverloadCandidateParamOrder PO, bool AggregateCandidateDeduction) { const FunctionProtoType *Proto = dyn_cast(Function->getType()->getAs()); assert(Proto && "Functions without a prototype cannot be overloaded"); @@ -6884,8 +6883,7 @@ void Sema::AddOverloadCandidate( AddMethodCandidate(Method, FoundDecl, Method->getParent(), QualType(), Expr::Classification::makeSimpleLValue(), Args, CandidateSet, SuppressUserConversions, - PartialOverloading, EarlyConversions, PO, - HasMatchedPackOnParmToNonPackOnArg); + PartialOverloading, EarlyConversions, PO); return; } // We treat a constructor like a non-member function, since its object @@ -6928,8 +6926,6 @@ void Sema::AddOverloadCandidate( CandidateSet.getRewriteInfo().getRewriteKind(Function, PO); Candidate.IsADLCandidate = IsADLCandidate; Candidate.ExplicitCallArguments = Args.size(); - Candidate.HasMatchedPackOnParmToNonPackOnArg = - HasMatchedPackOnParmToNonPackOnArg; // Explicit functions are not actually candidates at all if we're not // allowing them in this context, but keep them around so we can point @@ -7457,13 +7453,16 @@ void Sema::AddMethodCandidate(DeclAccessPair FoundDecl, QualType ObjectType, } } -void Sema::AddMethodCandidate( - CXXMethodDecl *Method, DeclAccessPair FoundDecl, - CXXRecordDecl *ActingContext, QualType ObjectType, - Expr::Classification ObjectClassification, ArrayRef Args, - OverloadCandidateSet &CandidateSet, bool SuppressUserConversions, - bool PartialOverloading, ConversionSequenceList EarlyConversions, - OverloadCandidateParamOrder PO, bool HasMatchedPackOnParmToNonPackOnArg) { +void +Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, + CXXRecordDecl *ActingContext, QualType ObjectType, + Expr::Classification ObjectClassification, + ArrayRef Args, + OverloadCandidateSet &CandidateSet, + bool SuppressUserConversions, + bool PartialOverloading, + ConversionSequenceList EarlyConversions, + OverloadCandidateParamOrder PO) { const FunctionProtoType *Proto = dyn_cast(Method->getType()->getAs()); assert(Proto && "Methods without a prototype cannot be overloaded"); @@ -7494,8 +7493,6 @@ void Sema::AddMethodCandidate( Candidate.TookAddressOfOverload = CandidateSet.getKind() == OverloadCandidateSet::CSK_AddressOfOverloadSet; Candidate.ExplicitCallArguments = Args.size(); - Candidate.HasMatchedPackOnParmToNonPackOnArg = - HasMatchedPackOnParmToNonPackOnArg; bool IgnoreExplicitObject = (Method->isExplicitObjectMemberFunction() && @@ -7666,8 +7663,8 @@ void Sema::AddMethodTemplateCandidate( ConversionSequenceList Conversions; if (TemplateDeductionResult Result = DeduceTemplateArguments( MethodTmpl, ExplicitTemplateArgs, Args, Specialization, Info, - PartialOverloading, /*AggregateDeductionCandidate=*/false, - /*PartialOrdering=*/false, ObjectType, ObjectClassification, + PartialOverloading, /*AggregateDeductionCandidate=*/false, ObjectType, + ObjectClassification, [&](ArrayRef ParamTypes) { return CheckNonDependentConversions( MethodTmpl, ParamTypes, Args, CandidateSet, Conversions, @@ -7705,8 +7702,7 @@ void Sema::AddMethodTemplateCandidate( AddMethodCandidate(cast(Specialization), FoundDecl, ActingContext, ObjectType, ObjectClassification, Args, CandidateSet, SuppressUserConversions, PartialOverloading, - Conversions, PO, - Info.hasMatchedPackOnParmToNonPackOnArg()); + Conversions, PO); } /// Determine whether a given function template has a simple explicit specifier @@ -7752,7 +7748,6 @@ void Sema::AddTemplateOverloadCandidate( if (TemplateDeductionResult Result = DeduceTemplateArguments( FunctionTemplate, ExplicitTemplateArgs, Args, Specialization, Info, PartialOverloading, AggregateCandidateDeduction, - /*PartialOrdering=*/false, /*ObjectType=*/QualType(), /*ObjectClassification=*/Expr::Classification(), [&](ArrayRef ParamTypes) { @@ -7793,8 +7788,7 @@ void Sema::AddTemplateOverloadCandidate( Specialization, FoundDecl, Args, CandidateSet, SuppressUserConversions, PartialOverloading, AllowExplicit, /*AllowExplicitConversions=*/false, IsADLCandidate, Conversions, PO, - Info.AggregateDeductionCandidateHasMismatchedArity, - Info.hasMatchedPackOnParmToNonPackOnArg()); + Info.AggregateDeductionCandidateHasMismatchedArity); } bool Sema::CheckNonDependentConversions( @@ -7916,8 +7910,7 @@ void Sema::AddConversionCandidate( CXXConversionDecl *Conversion, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, Expr *From, QualType ToType, OverloadCandidateSet &CandidateSet, bool AllowObjCConversionOnExplicit, - bool AllowExplicit, bool AllowResultConversion, - bool HasMatchedPackOnParmToNonPackOnArg) { + bool AllowExplicit, bool AllowResultConversion) { assert(!Conversion->getDescribedFunctionTemplate() && "Conversion function templates use AddTemplateConversionCandidate"); QualType ConvType = Conversion->getConversionType().getNonReferenceType(); @@ -7962,8 +7955,6 @@ void Sema::AddConversionCandidate( Candidate.FinalConversion.setAllToTypes(ToType); Candidate.Viable = true; Candidate.ExplicitCallArguments = 1; - Candidate.HasMatchedPackOnParmToNonPackOnArg = - HasMatchedPackOnParmToNonPackOnArg; // Explicit functions are not actually candidates at all if we're not // allowing them in this context, but keep them around so we can point @@ -8165,8 +8156,7 @@ void Sema::AddTemplateConversionCandidate( assert(Specialization && "Missing function template specialization?"); AddConversionCandidate(Specialization, FoundDecl, ActingDC, From, ToType, CandidateSet, AllowObjCConversionOnExplicit, - AllowExplicit, AllowResultConversion, - Info.hasMatchedPackOnParmToNonPackOnArg()); + AllowExplicit, AllowResultConversion); } void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, @@ -10519,10 +10509,6 @@ bool clang::isBetterOverloadCandidate( isa(Cand2.Function)) return isa(Cand1.Function); - if (Cand1.HasMatchedPackOnParmToNonPackOnArg != - Cand2.HasMatchedPackOnParmToNonPackOnArg) - return Cand2.HasMatchedPackOnParmToNonPackOnArg; - // -- F1 is a non-template function and F2 is a function template // specialization, or, if not that, bool Cand1IsSpecialization = Cand1.Function && diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp index b9b3b4063bc383..d81c6de3428dc7 100644 --- a/clang/lib/Sema/SemaStmtAttr.cpp +++ b/clang/lib/Sema/SemaStmtAttr.cpp @@ -679,6 +679,8 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A, return handleMSConstexprAttr(S, St, A, Range); case ParsedAttr::AT_NoConvergent: return handleNoConvergentAttr(S, St, A, Range); + case ParsedAttr::AT_Annotate: + return S.CreateAnnotationAttr(A); default: // N.B., ClangAttrEmitter.cpp emits a diagnostic helper that ensures a // declaration attribute is not written on a statement, but this code is diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 62d0d0914fa306..c7d48b81bc0347 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -5179,8 +5179,7 @@ bool Sema::CheckTemplateArgument( unsigned ArgumentPackIndex, SmallVectorImpl &SugaredConverted, SmallVectorImpl &CanonicalConverted, - CheckTemplateArgumentKind CTAK, bool PartialOrdering, - bool *MatchedPackOnParmToNonPackOnArg) { + CheckTemplateArgumentKind CTAK) { // Check template type parameters. if (TemplateTypeParmDecl *TTP = dyn_cast(Param)) return CheckTemplateTypeArgument(TTP, Arg, SugaredConverted, @@ -5395,8 +5394,8 @@ bool Sema::CheckTemplateArgument( case TemplateArgument::Template: case TemplateArgument::TemplateExpansion: - if (CheckTemplateTemplateArgument(TempParm, Params, Arg, PartialOrdering, - MatchedPackOnParmToNonPackOnArg)) + if (CheckTemplateTemplateArgument(TempParm, Params, Arg, + /*IsDeduced=*/CTAK != CTAK_Specified)) return true; SugaredConverted.push_back(Arg.getArgument()); @@ -5470,7 +5469,7 @@ bool Sema::CheckTemplateArgumentList( SmallVectorImpl &SugaredConverted, SmallVectorImpl &CanonicalConverted, bool UpdateArgsWithConversions, bool *ConstraintsNotSatisfied, - bool PartialOrderingTTP, bool *MatchedPackOnParmToNonPackOnArg) { + bool PartialOrderingTTP) { if (ConstraintsNotSatisfied) *ConstraintsNotSatisfied = false; @@ -5503,7 +5502,8 @@ bool Sema::CheckTemplateArgumentList( DefaultArgs && ParamIdx >= DefaultArgs.StartPos) { // All written arguments should have been consumed by this point. assert(ArgIdx == NumArgs && "bad default argument deduction"); - if (ParamIdx == DefaultArgs.StartPos) { + // 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) { @@ -5549,8 +5549,7 @@ bool Sema::CheckTemplateArgumentList( if (CheckTemplateArgument(*Param, NewArgs[ArgIdx], Template, TemplateLoc, RAngleLoc, SugaredArgumentPack.size(), SugaredConverted, CanonicalConverted, - CTAK_Specified, /*PartialOrdering=*/false, - MatchedPackOnParmToNonPackOnArg)) + CTAK_Specified)) return true; CanonicalConverted.back().setIsDefaulted( @@ -5708,8 +5707,7 @@ bool Sema::CheckTemplateArgumentList( // Check the default template argument. if (CheckTemplateArgument(*Param, Arg, Template, TemplateLoc, RAngleLoc, 0, SugaredConverted, CanonicalConverted, - CTAK_Specified, /*PartialOrdering=*/false, - /*MatchedPackOnParmToNonPackOnArg=*/nullptr)) + CTAK_Specified)) return true; SugaredConverted.back().setIsDefaulted(true); @@ -5730,9 +5728,8 @@ bool Sema::CheckTemplateArgumentList( // pack expansions; they might be empty. This can happen even if // PartialTemplateArgs is false (the list of arguments is complete but // still dependent). - if (PartialOrderingTTP || - (CurrentInstantiationScope && - CurrentInstantiationScope->getPartiallySubstitutedPack())) { + if (ArgIdx < NumArgs && CurrentInstantiationScope && + CurrentInstantiationScope->getPartiallySubstitutedPack()) { while (ArgIdx < NumArgs && NewArgs[ArgIdx].getArgument().isPackExpansion()) { const TemplateArgument &Arg = NewArgs[ArgIdx++].getArgument(); @@ -7292,10 +7289,10 @@ static void DiagnoseTemplateParameterListArityMismatch( Sema &S, TemplateParameterList *New, TemplateParameterList *Old, Sema::TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc); -bool Sema::CheckTemplateTemplateArgument( - TemplateTemplateParmDecl *Param, TemplateParameterList *Params, - TemplateArgumentLoc &Arg, bool PartialOrdering, - bool *MatchedPackOnParmToNonPackOnArg) { +bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param, + TemplateParameterList *Params, + TemplateArgumentLoc &Arg, + bool IsDeduced) { TemplateName Name = Arg.getArgument().getAsTemplateOrTemplatePattern(); auto [Template, DefaultArgs] = Name.getTemplateDeclAndDefaultArgs(); if (!Template) { @@ -7330,47 +7327,64 @@ bool Sema::CheckTemplateTemplateArgument( << Template; } - if (!getLangOpts().RelaxedTemplateTemplateArgs) - return !TemplateParameterListsAreEqual( - Template->getTemplateParameters(), Params, /*Complain=*/true, - TPL_TemplateTemplateArgumentMatch, Arg.getLocation()); - // C++1z [temp.arg.template]p3: (DR 150) // A template-argument matches a template template-parameter P when P // is at least as specialized as the template-argument A. - if (!isTemplateTemplateParameterAtLeastAsSpecializedAs( - Params, Param, Template, DefaultArgs, Arg.getLocation(), - PartialOrdering, MatchedPackOnParmToNonPackOnArg)) - return true; - // P2113 - // C++20[temp.func.order]p2 - // [...] If both deductions succeed, the partial ordering selects the - // more constrained template (if one exists) as determined below. - SmallVector ParamsAC, TemplateAC; - Params->getAssociatedConstraints(ParamsAC); - // C++20[temp.arg.template]p3 - // [...] In this comparison, if P is unconstrained, the constraints on A - // are not considered. - if (ParamsAC.empty()) - return false; + if (getLangOpts().RelaxedTemplateTemplateArgs) { + // Quick check for the common case: + // If P contains a parameter pack, then A [...] matches P if each of A's + // template parameters matches the corresponding template parameter in + // the template-parameter-list of P. + if (TemplateParameterListsAreEqual( + Template->getTemplateParameters(), Params, false, + TPL_TemplateTemplateArgumentMatch, Arg.getLocation()) && + // If the argument has no associated constraints, then the parameter is + // definitely at least as specialized as the argument. + // Otherwise - we need a more thorough check. + !Template->hasAssociatedConstraints()) + return false; - Template->getAssociatedConstraints(TemplateAC); + if (isTemplateTemplateParameterAtLeastAsSpecializedAs( + Params, Template, DefaultArgs, Arg.getLocation(), IsDeduced)) { + // P2113 + // C++20[temp.func.order]p2 + // [...] If both deductions succeed, the partial ordering selects the + // more constrained template (if one exists) as determined below. + SmallVector ParamsAC, TemplateAC; + Params->getAssociatedConstraints(ParamsAC); + // C++2a[temp.arg.template]p3 + // [...] In this comparison, if P is unconstrained, the constraints on A + // are not considered. + if (ParamsAC.empty()) + return false; - bool IsParamAtLeastAsConstrained; - if (IsAtLeastAsConstrained(Param, ParamsAC, Template, TemplateAC, - IsParamAtLeastAsConstrained)) - return true; - if (!IsParamAtLeastAsConstrained) { - Diag(Arg.getLocation(), - diag::err_template_template_parameter_not_at_least_as_constrained) - << Template << Param << Arg.getSourceRange(); - Diag(Param->getLocation(), diag::note_entity_declared_at) << Param; - Diag(Template->getLocation(), diag::note_entity_declared_at) << Template; - MaybeEmitAmbiguousAtomicConstraintsDiagnostic(Param, ParamsAC, Template, - TemplateAC); - return true; + Template->getAssociatedConstraints(TemplateAC); + + bool IsParamAtLeastAsConstrained; + if (IsAtLeastAsConstrained(Param, ParamsAC, Template, TemplateAC, + IsParamAtLeastAsConstrained)) + return true; + if (!IsParamAtLeastAsConstrained) { + Diag(Arg.getLocation(), + diag::err_template_template_parameter_not_at_least_as_constrained) + << Template << Param << Arg.getSourceRange(); + Diag(Param->getLocation(), diag::note_entity_declared_at) << Param; + Diag(Template->getLocation(), diag::note_entity_declared_at) + << Template; + MaybeEmitAmbiguousAtomicConstraintsDiagnostic(Param, ParamsAC, Template, + TemplateAC); + return true; + } + return false; + } + // FIXME: Produce better diagnostics for deduction failures. } - return false; + + return !TemplateParameterListsAreEqual(Template->getTemplateParameters(), + Params, + true, + TPL_TemplateTemplateArgumentMatch, + Arg.getLocation()); } static Sema::SemaDiagnosticBuilder noteLocation(Sema &S, const NamedDecl &Decl, @@ -9758,14 +9772,11 @@ DeclResult Sema::ActOnExplicitInstantiation( // Check that the template argument list is well-formed for this // template. - bool PrimaryHasMatchedPackOnParmToNonPackOnArg = false; SmallVector SugaredConverted, CanonicalConverted; - if (CheckTemplateArgumentList( - ClassTemplate, TemplateNameLoc, TemplateArgs, - /*DefaultArgs=*/{}, false, SugaredConverted, CanonicalConverted, - /*UpdateArgsWithConversions=*/true, - /*ConstraintsNotSatisfied=*/nullptr, /*PartialOrderingTTP=*/false, - &PrimaryHasMatchedPackOnParmToNonPackOnArg)) + if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, TemplateArgs, + /*DefaultArgs=*/{}, false, SugaredConverted, + CanonicalConverted, + /*UpdateArgsWithConversions=*/true)) return true; // Find the class template specialization declaration that @@ -9886,9 +9897,7 @@ DeclResult Sema::ActOnExplicitInstantiation( = cast_or_null( Specialization->getDefinition()); if (!Def) - InstantiateClassTemplateSpecialization( - TemplateNameLoc, Specialization, TSK, - /*Complain=*/true, PrimaryHasMatchedPackOnParmToNonPackOnArg); + InstantiateClassTemplateSpecialization(TemplateNameLoc, Specialization, TSK); else if (TSK == TSK_ExplicitInstantiationDefinition) { MarkVTableUsed(TemplateNameLoc, Specialization, true); Specialization->setPointOfInstantiation(Def->getPointOfInstantiation()); diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index e49d315f7186bc..d106874c4c5bda 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -145,9 +145,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( PartialOrderingKind POK, bool DeducedFromArrayBound, bool *HasDeducedAnyParam); -/// What directions packs are allowed to match non-packs. -enum class PackFold { ParameterToArgument, ArgumentToParameter, Both }; - +enum class PackFold { ParameterToArgument, ArgumentToParameter }; static TemplateDeductionResult DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, ArrayRef Ps, @@ -1713,21 +1711,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context, Deduced[Index], NewDeduced); if (Result.isNull()) { - // We can also get inconsistencies when matching NTTP type. - switch (NamedDecl *Param = TemplateParams->getParam(Index); - Param->getKind()) { - case Decl::TemplateTypeParm: - Info.Param = cast(Param); - break; - case Decl::NonTypeTemplateParm: - Info.Param = cast(Param); - break; - case Decl::TemplateTemplateParm: - Info.Param = cast(Param); - break; - default: - llvm_unreachable("unexpected kind"); - } + Info.Param = cast(TemplateParams->getParam(Index)); Info.FirstArg = Deduced[Index]; Info.SecondArg = NewDeduced; return TemplateDeductionResult::Inconsistent; @@ -2565,31 +2549,8 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, if (const NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr(Info, P.getAsExpr())) { switch (A.getKind()) { - case TemplateArgument::Expression: { - const Expr *E = A.getAsExpr(); - // When checking NTTP, if either the parameter or the argument is - // dependent, as there would be otherwise nothing to deduce, we force - // the argument to the parameter type using this dependent implicit - // cast, in order to maintain invariants. Now we can deduce the - // resulting type from the original type, and deduce the original type - // against the parameter we are checking. - if (const auto *ICE = dyn_cast(E); - ICE && ICE->getCastKind() == clang::CK_Dependent) { - E = ICE->getSubExpr(); - if (auto Result = DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, ICE->getType(), E->getType(), Info, - Deduced, TDF_SkipNonDependent, - PartialOrdering ? PartialOrderingKind::NonCall - : PartialOrderingKind::None, - /*DeducedFromArrayBound=*/false, HasDeducedAnyParam); - Result != TemplateDeductionResult::Success) - return Result; - } - return DeduceNonTypeTemplateArgument( - S, TemplateParams, NTTP, DeducedTemplateArgument(A), E->getType(), - Info, PartialOrdering, Deduced, HasDeducedAnyParam); - } case TemplateArgument::Integral: + case TemplateArgument::Expression: case TemplateArgument::StructuralValue: return DeduceNonTypeTemplateArgument( S, TemplateParams, NTTP, DeducedTemplateArgument(A), @@ -2678,75 +2639,50 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, SmallVectorImpl &Deduced, bool NumberOfArgumentsMustMatch, bool PartialOrdering, PackFold PackFold, bool *HasDeducedAnyParam) { - bool FoldPackParameter = PackFold == PackFold::ParameterToArgument || - PackFold == PackFold::Both, - FoldPackArgument = PackFold == PackFold::ArgumentToParameter || - PackFold == PackFold::Both; - + if (PackFold == PackFold::ArgumentToParameter) + std::swap(Ps, As); // C++0x [temp.deduct.type]p9: // If the template argument list of P contains a pack expansion that is not // the last template argument, the entire template argument list is a // non-deduced context. - if (FoldPackParameter && hasPackExpansionBeforeEnd(Ps)) - return TemplateDeductionResult::Success; - - if (FoldPackArgument && hasPackExpansionBeforeEnd(As)) + if (hasPackExpansionBeforeEnd(Ps)) return TemplateDeductionResult::Success; // C++0x [temp.deduct.type]p9: // If P has a form that contains or , then each argument Pi of the // respective template argument list P is compared with the corresponding // argument Ai of the corresponding template argument list of A. - for (unsigned ArgIdx = 0, ParamIdx = 0; /**/; /**/) { - if (!hasTemplateArgumentForDeduction(Ps, ParamIdx)) - return !FoldPackParameter && hasTemplateArgumentForDeduction(As, ArgIdx) - ? TemplateDeductionResult::MiscellaneousDeductionFailure - : TemplateDeductionResult::Success; - - if (!Ps[ParamIdx].isPackExpansion()) { + unsigned ArgIdx = 0, ParamIdx = 0; + for (; hasTemplateArgumentForDeduction(Ps, ParamIdx); ++ParamIdx) { + const TemplateArgument &P = Ps[ParamIdx]; + if (!P.isPackExpansion()) { // The simple case: deduce template arguments by matching Pi and Ai. // Check whether we have enough arguments. if (!hasTemplateArgumentForDeduction(As, ArgIdx)) - return !FoldPackArgument && NumberOfArgumentsMustMatch + return NumberOfArgumentsMustMatch ? TemplateDeductionResult::MiscellaneousDeductionFailure : TemplateDeductionResult::Success; - if (As[ArgIdx].isPackExpansion()) { - // C++1z [temp.deduct.type]p9: - // During partial ordering, if Ai was originally a pack expansion - // [and] Pi is not a pack expansion, template argument deduction - // fails. - if (!FoldPackArgument) - return TemplateDeductionResult::MiscellaneousDeductionFailure; - - TemplateArgument Pattern = As[ArgIdx].getPackExpansionPattern(); - for (;;) { - // Deduce template parameters from the pattern. - if (auto Result = DeduceTemplateArguments( - S, TemplateParams, Ps[ParamIdx], Pattern, Info, - PartialOrdering, Deduced, HasDeducedAnyParam); - Result != TemplateDeductionResult::Success) - return Result; + // C++1z [temp.deduct.type]p9: + // During partial ordering, if Ai was originally a pack expansion [and] + // Pi is not a pack expansion, template argument deduction fails. + if (As[ArgIdx].isPackExpansion()) + return TemplateDeductionResult::MiscellaneousDeductionFailure; - ++ParamIdx; - if (!hasTemplateArgumentForDeduction(Ps, ParamIdx)) - return TemplateDeductionResult::Success; - if (Ps[ParamIdx].isPackExpansion()) - break; - } - } else { - // Perform deduction for this Pi/Ai pair. - if (auto Result = DeduceTemplateArguments( - S, TemplateParams, Ps[ParamIdx], As[ArgIdx], Info, - PartialOrdering, Deduced, HasDeducedAnyParam); - Result != TemplateDeductionResult::Success) - return Result; + // Perform deduction for this Pi/Ai pair. + TemplateArgument Pi = P, Ai = As[ArgIdx]; + if (PackFold == PackFold::ArgumentToParameter) + std::swap(Pi, Ai); + if (auto Result = DeduceTemplateArguments(S, TemplateParams, Pi, Ai, Info, + PartialOrdering, Deduced, + HasDeducedAnyParam); + Result != TemplateDeductionResult::Success) + return Result; - ++ArgIdx; - ++ParamIdx; - continue; - } + // Move to the next argument. + ++ArgIdx; + continue; } // The parameter is a pack expansion. @@ -2756,7 +2692,7 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, // each remaining argument in the template argument list of A. Each // comparison deduces template arguments for subsequent positions in the // template parameter packs expanded by Pi. - TemplateArgument Pattern = Ps[ParamIdx].getPackExpansionPattern(); + TemplateArgument Pattern = P.getPackExpansionPattern(); // Prepare to deduce the packs within the pattern. PackDeductionScope PackScope(S, TemplateParams, Deduced, Info, Pattern); @@ -2767,16 +2703,13 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, for (; hasTemplateArgumentForDeduction(As, ArgIdx) && PackScope.hasNextElement(); ++ArgIdx) { - if (!As[ArgIdx].isPackExpansion()) { - if (!FoldPackParameter) - return TemplateDeductionResult::MiscellaneousDeductionFailure; - if (FoldPackArgument) - Info.setMatchedPackOnParmToNonPackOnArg(); - } + TemplateArgument Pi = Pattern, Ai = As[ArgIdx]; + if (PackFold == PackFold::ArgumentToParameter) + std::swap(Pi, Ai); // Deduce template arguments from the pattern. - if (auto Result = DeduceTemplateArguments( - S, TemplateParams, Pattern, As[ArgIdx], Info, PartialOrdering, - Deduced, HasDeducedAnyParam); + if (auto Result = DeduceTemplateArguments(S, TemplateParams, Pi, Ai, Info, + PartialOrdering, Deduced, + HasDeducedAnyParam); Result != TemplateDeductionResult::Success) return Result; @@ -2785,8 +2718,12 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, // Build argument packs for each of the parameter packs expanded by this // pack expansion. - return PackScope.finish(); + if (auto Result = PackScope.finish(); + Result != TemplateDeductionResult::Success) + return Result; } + + return TemplateDeductionResult::Success; } TemplateDeductionResult Sema::DeduceTemplateArguments( @@ -2955,7 +2892,7 @@ Sema::getIdentityTemplateArgumentLoc(NamedDecl *TemplateParm, /// fully-converted template arguments. static bool ConvertDeducedTemplateArgument( Sema &S, NamedDecl *Param, DeducedTemplateArgument Arg, NamedDecl *Template, - TemplateDeductionInfo &Info, bool IsDeduced, bool PartialOrdering, + TemplateDeductionInfo &Info, bool IsDeduced, SmallVectorImpl &SugaredOutput, SmallVectorImpl &CanonicalOutput) { auto ConvertArg = [&](DeducedTemplateArgument Arg, @@ -2966,20 +2903,15 @@ static bool ConvertDeducedTemplateArgument( TemplateArgumentLoc ArgLoc = S.getTrivialTemplateArgumentLoc( Arg, QualType(), Info.getLocation(), Param); - bool MatchedPackOnParmToNonPackOnArg = false; // Check the template argument, converting it as necessary. - auto Res = S.CheckTemplateArgument( + return S.CheckTemplateArgument( Param, ArgLoc, Template, Template->getLocation(), Template->getSourceRange().getEnd(), ArgumentPackIndex, SugaredOutput, CanonicalOutput, IsDeduced ? (Arg.wasDeducedFromArrayBound() ? Sema::CTAK_DeducedFromArrayBound : Sema::CTAK_Deduced) - : Sema::CTAK_Specified, - PartialOrdering, &MatchedPackOnParmToNonPackOnArg); - if (MatchedPackOnParmToNonPackOnArg) - Info.setMatchedPackOnParmToNonPackOnArg(); - return Res; + : Sema::CTAK_Specified); }; if (Arg.getKind() == TemplateArgument::Pack) { @@ -3062,9 +2994,9 @@ static TemplateDeductionResult ConvertDeducedTemplateArguments( SmallVectorImpl &Deduced, TemplateDeductionInfo &Info, SmallVectorImpl &SugaredBuilder, - SmallVectorImpl &CanonicalBuilder, bool PartialOrdering, - LocalInstantiationScope *CurrentInstantiationScope, - unsigned NumAlreadyConverted, bool *IsIncomplete) { + SmallVectorImpl &CanonicalBuilder, + LocalInstantiationScope *CurrentInstantiationScope = nullptr, + unsigned NumAlreadyConverted = 0, bool *IsIncomplete = nullptr) { TemplateParameterList *TemplateParams = Template->getTemplateParameters(); for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) { @@ -3107,8 +3039,8 @@ static TemplateDeductionResult ConvertDeducedTemplateArguments( // We may have deduced this argument, so it still needs to be // checked and converted. if (ConvertDeducedTemplateArgument(S, Param, Deduced[I], Template, Info, - IsDeduced, PartialOrdering, - SugaredBuilder, CanonicalBuilder)) { + IsDeduced, SugaredBuilder, + CanonicalBuilder)) { Info.Param = makeTemplateParameter(Param); // FIXME: These template arguments are temporary. Free them! Info.reset( @@ -3174,9 +3106,7 @@ static TemplateDeductionResult ConvertDeducedTemplateArguments( // Check whether we can actually use the default argument. if (S.CheckTemplateArgument( Param, DefArg, TD, TD->getLocation(), TD->getSourceRange().getEnd(), - /*ArgumentPackIndex=*/0, SugaredBuilder, CanonicalBuilder, - Sema::CTAK_Specified, /*PartialOrdering=*/false, - /*MatchedPackOnParmToNonPackOnArg=*/nullptr)) { + 0, SugaredBuilder, CanonicalBuilder, Sema::CTAK_Specified)) { Info.Param = makeTemplateParameter( const_cast(TemplateParams->getParam(I))); // FIXME: These template arguments are temporary. Free them! @@ -3284,9 +3214,7 @@ FinishTemplateArgumentDeduction( SmallVector SugaredBuilder, CanonicalBuilder; if (auto Result = ConvertDeducedTemplateArguments( S, Partial, IsPartialOrdering, Deduced, Info, SugaredBuilder, - CanonicalBuilder, IsPartialOrdering, - /*CurrentInstantiationScope=*/nullptr, /*NumAlreadyConverted=*/0, - /*IsIncomplete=*/nullptr); + CanonicalBuilder); Result != TemplateDeductionResult::Success) return Result; @@ -3327,20 +3255,16 @@ FinishTemplateArgumentDeduction( return TemplateDeductionResult::SubstitutionFailure; } - bool MatchedPackOnParmToNonPackOnArg = false; bool ConstraintsNotSatisfied; SmallVector SugaredConvertedInstArgs, CanonicalConvertedInstArgs; if (S.CheckTemplateArgumentList( Template, Partial->getLocation(), InstArgs, /*DefaultArgs=*/{}, false, SugaredConvertedInstArgs, CanonicalConvertedInstArgs, - /*UpdateArgsWithConversions=*/true, &ConstraintsNotSatisfied, - /*PartialOrderingTTP=*/false, &MatchedPackOnParmToNonPackOnArg)) + /*UpdateArgsWithConversions=*/true, &ConstraintsNotSatisfied)) return ConstraintsNotSatisfied ? TemplateDeductionResult::ConstraintsNotSatisfied : TemplateDeductionResult::SubstitutionFailure; - if (MatchedPackOnParmToNonPackOnArg) - Info.setMatchedPackOnParmToNonPackOnArg(); TemplateParameterList *TemplateParams = Template->getTemplateParameters(); for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) { @@ -3378,6 +3302,7 @@ static TemplateDeductionResult FinishTemplateArgumentDeduction( // Unevaluated SFINAE context. EnterExpressionEvaluationContext Unevaluated( S, Sema::ExpressionEvaluationContext::Unevaluated); + Sema::SFINAETrap Trap(S); Sema::ContextRAII SavedContext(S, getAsDeclContextOrEnclosing(Template)); @@ -3386,45 +3311,29 @@ static TemplateDeductionResult FinishTemplateArgumentDeduction( // explicitly specified, template argument deduction fails. SmallVector SugaredBuilder, CanonicalBuilder; if (auto Result = ConvertDeducedTemplateArguments( - S, Template, /*IsDeduced=*/PartialOrdering, Deduced, Info, - SugaredBuilder, CanonicalBuilder, PartialOrdering, + S, Template, /*IsDeduced*/ PartialOrdering, Deduced, Info, + SugaredBuilder, CanonicalBuilder, /*CurrentInstantiationScope=*/nullptr, - /*NumAlreadyConverted=*/0U, /*IsIncomplete=*/nullptr); + /*NumAlreadyConverted=*/0U); Result != TemplateDeductionResult::Success) return Result; // Check that we produced the correct argument list. TemplateParameterList *TemplateParams = Template->getTemplateParameters(); - auto isSame = [&](unsigned I, const TemplateArgument &P, - const TemplateArgument &A) { - if (isSameTemplateArg(S.Context, P, A, PartialOrdering, - /*PackExpansionMatchesPack=*/true)) - return true; - Info.Param = makeTemplateParameter(TemplateParams->getParam(I)); - Info.FirstArg = P; - Info.SecondArg = A; - return false; - }; for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) { - const TemplateArgument &P = TemplateArgs[I]; - if (P.isPackExpansion()) { - assert(I == TemplateArgs.size() - 1); - for (/**/; I != E; ++I) { - const TemplateArgument &A = CanonicalBuilder[I]; - if (A.getKind() == TemplateArgument::Pack) { - for (const TemplateArgument &Ai : A.getPackAsArray()) - if (!isSame(I, P, Ai)) - return TemplateDeductionResult::NonDeducedMismatch; - } else if (!isSame(I, P, A)) { - return TemplateDeductionResult::NonDeducedMismatch; - } - } - break; - } - if (!isSame(I, P, CanonicalBuilder[I])) + TemplateArgument InstArg = CanonicalBuilder[I]; + if (!isSameTemplateArg(S.Context, TemplateArgs[I], InstArg, PartialOrdering, + /*PackExpansionMatchesPack=*/true)) { + Info.Param = makeTemplateParameter(TemplateParams->getParam(I)); + Info.FirstArg = TemplateArgs[I]; + Info.SecondArg = InstArg; return TemplateDeductionResult::NonDeducedMismatch; + } } + if (Trap.hasErrorOccurred()) + return TemplateDeductionResult::SubstitutionFailure; + if (!PartialOrdering) { if (auto Result = CheckDeducedArgumentConstraints( S, Template, SugaredBuilder, CanonicalBuilder, Info); @@ -3445,6 +3354,7 @@ static TemplateDeductionResult FinishTemplateArgumentDeduction( // Unevaluated SFINAE context. EnterExpressionEvaluationContext Unevaluated( S, Sema::ExpressionEvaluationContext::Unevaluated); + Sema::SFINAETrap Trap(S); Sema::ContextRAII SavedContext(S, getAsDeclContextOrEnclosing(TD)); @@ -3453,15 +3363,20 @@ static TemplateDeductionResult FinishTemplateArgumentDeduction( // explicitly specified, template argument deduction fails. SmallVector SugaredBuilder, CanonicalBuilder; if (auto Result = ConvertDeducedTemplateArguments( - S, TD, /*IsDeduced=*/false, Deduced, Info, SugaredBuilder, - CanonicalBuilder, /*PartialOrdering=*/false, - /*CurrentInstantiationScope=*/nullptr, /*NumAlreadyConverted=*/0, - /*IsIncomplete=*/nullptr); + S, TD, /*IsPartialOrdering=*/false, Deduced, Info, SugaredBuilder, + CanonicalBuilder); Result != TemplateDeductionResult::Success) return Result; - return ::CheckDeducedArgumentConstraints(S, TD, SugaredBuilder, - CanonicalBuilder, Info); + if (Trap.hasErrorOccurred()) + return TemplateDeductionResult::SubstitutionFailure; + + if (auto Result = CheckDeducedArgumentConstraints(S, TD, SugaredBuilder, + CanonicalBuilder, Info); + Result != TemplateDeductionResult::Success) + return Result; + + return TemplateDeductionResult::Success; } /// Perform template argument deduction to determine whether the given template @@ -3508,20 +3423,16 @@ DeduceTemplateArguments(Sema &S, T *Partial, if (Inst.isInvalid()) return TemplateDeductionResult::InstantiationDepth; + if (Trap.hasErrorOccurred()) + return TemplateDeductionResult::SubstitutionFailure; + TemplateDeductionResult Result; S.runWithSufficientStackSpace(Info.getLocation(), [&] { Result = ::FinishTemplateArgumentDeduction(S, Partial, /*IsPartialOrdering=*/false, TemplateArgs, Deduced, Info); }); - - if (Result != TemplateDeductionResult::Success) - return Result; - - if (Trap.hasErrorOccurred()) - return TemplateDeductionResult::SubstitutionFailure; - - return TemplateDeductionResult::Success; + return Result; } TemplateDeductionResult @@ -3577,18 +3488,14 @@ Sema::DeduceTemplateArgumentsFromType(TemplateDecl *TD, QualType FromType, if (Inst.isInvalid()) return TemplateDeductionResult::InstantiationDepth; + if (Trap.hasErrorOccurred()) + return TemplateDeductionResult::SubstitutionFailure; + TemplateDeductionResult Result; runWithSufficientStackSpace(Info.getLocation(), [&] { Result = ::FinishTemplateArgumentDeduction(*this, TD, Deduced, Info); }); - - if (Result != TemplateDeductionResult::Success) - return Result; - - if (Trap.hasErrorOccurred()) - return TemplateDeductionResult::SubstitutionFailure; - - return TemplateDeductionResult::Success; + return Result; } /// Determine whether the given type T is a simple-template-id type. @@ -3994,8 +3901,7 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction( unsigned NumExplicitlySpecified, FunctionDecl *&Specialization, TemplateDeductionInfo &Info, SmallVectorImpl const *OriginalCallArgs, - bool PartialOverloading, bool PartialOrdering, - llvm::function_ref CheckNonDependent) { + bool PartialOverloading, llvm::function_ref CheckNonDependent) { // Unevaluated SFINAE context. EnterExpressionEvaluationContext Unevaluated( *this, Sema::ExpressionEvaluationContext::Unevaluated); @@ -4018,10 +3924,9 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction( bool IsIncomplete = false; SmallVector SugaredBuilder, CanonicalBuilder; if (auto Result = ConvertDeducedTemplateArguments( - *this, FunctionTemplate, /*IsDeduced=*/true, Deduced, Info, - SugaredBuilder, CanonicalBuilder, PartialOrdering, - CurrentInstantiationScope, NumExplicitlySpecified, - PartialOverloading ? &IsIncomplete : nullptr); + *this, FunctionTemplate, /*IsDeduced*/ true, Deduced, Info, + SugaredBuilder, CanonicalBuilder, CurrentInstantiationScope, + NumExplicitlySpecified, PartialOverloading ? &IsIncomplete : nullptr); Result != TemplateDeductionResult::Success) return Result; @@ -4553,8 +4458,7 @@ TemplateDeductionResult Sema::DeduceTemplateArguments( TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef Args, FunctionDecl *&Specialization, TemplateDeductionInfo &Info, bool PartialOverloading, bool AggregateDeductionCandidate, - bool PartialOrdering, QualType ObjectType, - Expr::Classification ObjectClassification, + QualType ObjectType, Expr::Classification ObjectClassification, llvm::function_ref)> CheckNonDependent) { if (FunctionTemplate->isInvalidDecl()) return TemplateDeductionResult::Invalid; @@ -4769,8 +4673,7 @@ TemplateDeductionResult Sema::DeduceTemplateArguments( runWithSufficientStackSpace(Info.getLocation(), [&] { Result = FinishTemplateArgumentDeduction( FunctionTemplate, Deduced, NumExplicitlySpecified, Specialization, Info, - &OriginalCallArgs, PartialOverloading, PartialOrdering, - [&, CallingCtx]() { + &OriginalCallArgs, PartialOverloading, [&, CallingCtx]() { ContextRAII SavedContext(*this, CallingCtx); return CheckNonDependent(ParamTypesForArgChecking); }); @@ -4882,10 +4785,9 @@ TemplateDeductionResult Sema::DeduceTemplateArguments( TemplateDeductionResult Result; runWithSufficientStackSpace(Info.getLocation(), [&] { - Result = FinishTemplateArgumentDeduction( - FunctionTemplate, Deduced, NumExplicitlySpecified, Specialization, Info, - /*OriginalCallArgs=*/nullptr, /*PartialOverloading=*/false, - /*PartialOrdering=*/true); + Result = FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, + NumExplicitlySpecified, + Specialization, Info); }); if (Result != TemplateDeductionResult::Success) return Result; @@ -5065,10 +4967,9 @@ TemplateDeductionResult Sema::DeduceTemplateArguments( FunctionDecl *ConversionSpecialized = nullptr; TemplateDeductionResult Result; runWithSufficientStackSpace(Info.getLocation(), [&] { - Result = FinishTemplateArgumentDeduction( - ConversionTemplate, Deduced, 0, ConversionSpecialized, Info, - &OriginalCallArgs, /*PartialOverloading=*/false, - /*PartialOrdering=*/false); + Result = FinishTemplateArgumentDeduction(ConversionTemplate, Deduced, 0, + ConversionSpecialized, Info, + &OriginalCallArgs); }); Specialization = cast_or_null(ConversionSpecialized); return Result; @@ -5645,8 +5546,7 @@ static TemplateDeductionResult FinishTemplateArgumentDeduction( SmallVector SugaredBuilder, CanonicalBuilder; if (auto Result = ConvertDeducedTemplateArguments( S, FTD, /*IsDeduced=*/true, Deduced, Info, SugaredBuilder, - CanonicalBuilder, /*PartialOrdering=*/true, - /*CurrentInstantiationScope=*/nullptr, + CanonicalBuilder, /*CurrentInstantiationScope=*/nullptr, /*NumAlreadyConverted=*/0, &IsIncomplete); Result != TemplateDeductionResult::Success) return Result; @@ -6236,23 +6136,14 @@ static bool isAtLeastAsSpecializedAs(Sema &S, QualType T1, QualType T2, return false; const auto *TST1 = cast(T1); - - Sema::SFINAETrap Trap(S); - - TemplateDeductionResult Result; + bool AtLeastAsSpecialized; S.runWithSufficientStackSpace(Info.getLocation(), [&] { - Result = ::FinishTemplateArgumentDeduction( - S, P2, /*IsPartialOrdering=*/true, TST1->template_arguments(), Deduced, - Info); + AtLeastAsSpecialized = + FinishTemplateArgumentDeduction( + S, P2, /*IsPartialOrdering=*/true, TST1->template_arguments(), + Deduced, Info) == TemplateDeductionResult::Success; }); - - if (Result != TemplateDeductionResult::Success) - return false; - - if (Trap.hasErrorOccurred()) - return false; - - return true; + return AtLeastAsSpecialized; } namespace { @@ -6490,9 +6381,8 @@ bool Sema::isMoreSpecializedThanPrimary( } bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs( - TemplateParameterList *P, TemplateDecl *PArg, TemplateDecl *AArg, - const DefaultArguments &DefaultArgs, SourceLocation ArgLoc, - bool PartialOrdering, bool *MatchedPackOnParmToNonPackOnArg) { + 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 @@ -6504,12 +6394,6 @@ bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs( // TemplateParameterList *A = AArg->getTemplateParameters(); - Sema::InstantiatingTemplate Inst( - *this, ArgLoc, Sema::InstantiatingTemplate::PartialOrderingTTP(), PArg, - SourceRange(P->getTemplateLoc(), P->getRAngleLoc())); - if (Inst.isInvalid()) - return false; - // Given an invented class template X with the template parameter list of // A (including default arguments): // - Each function template has a single function parameter whose type is @@ -6524,6 +6408,8 @@ bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs( // templates. SmallVector PArgs; { + SFINAETrap Trap(*this); + Context.getInjectedTemplateArgs(P, PArgs); TemplateArgumentListInfo PArgList(P->getLAngleLoc(), P->getRAngleLoc()); @@ -6543,17 +6429,18 @@ bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs( // C++1z [temp.arg.template]p3: // If the rewrite produces an invalid type, then P is not at least as // specialized as A. - SmallVector CanonicalPArgs; - if (CheckTemplateArgumentList( - AArg, ArgLoc, PArgList, DefaultArgs, false, PArgs, CanonicalPArgs, - /*UpdateArgsWithConversions=*/true, - /*ConstraintsNotSatisfied=*/nullptr, - /*PartialOrderingTTP=*/true, MatchedPackOnParmToNonPackOnArg)) + SmallVector SugaredPArgs; + if (CheckTemplateArgumentList(AArg, Loc, PArgList, DefaultArgs, false, + SugaredPArgs, PArgs, + /*UpdateArgsWithConversions=*/true, + /*ConstraintsNotSatisfied=*/nullptr, + /*PartialOrderTTP=*/true) || + Trap.hasErrorOccurred()) return false; } // Determine whether P1 is at least as specialized as P2. - TemplateDeductionInfo Info(ArgLoc, A->getDepth()); + TemplateDeductionInfo Info(Loc, A->getDepth()); SmallVector Deduced; Deduced.resize(A->size()); @@ -6568,92 +6455,29 @@ bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs( // be inverted between Ps and As. On non-deduced context, matching needs to // happen both ways, according to [temp.arg.template]p3, but this is // currently implemented as a special case elsewhere. - switch (::DeduceTemplateArguments( - *this, A, AArgs, PArgs, Info, Deduced, - /*NumberOfArgumentsMustMatch=*/false, /*PartialOrdering=*/true, - PartialOrdering ? PackFold::ArgumentToParameter : PackFold::Both, - /*HasDeducedAnyParam=*/nullptr)) { - case clang::TemplateDeductionResult::Success: - if (MatchedPackOnParmToNonPackOnArg && - Info.hasMatchedPackOnParmToNonPackOnArg()) - *MatchedPackOnParmToNonPackOnArg = true; - break; - - case TemplateDeductionResult::MiscellaneousDeductionFailure: - Diag(AArg->getLocation(), diag::err_template_param_list_different_arity) - << (A->size() > P->size()) << /*isTemplateTemplateParameter=*/true - << SourceRange(A->getTemplateLoc(), P->getRAngleLoc()); + if (::DeduceTemplateArguments(*this, A, AArgs, PArgs, Info, Deduced, + /*NumberOfArgumentsMustMatch=*/false, + /*PartialOrdering=*/true, + IsDeduced ? PackFold::ArgumentToParameter + : PackFold::ParameterToArgument, + /*HasDeducedAnyParam=*/nullptr) != + TemplateDeductionResult::Success) return false; - case TemplateDeductionResult::NonDeducedMismatch: - Diag(AArg->getLocation(), diag::err_non_deduced_mismatch) - << Info.FirstArg << Info.SecondArg; - return false; - case TemplateDeductionResult::Inconsistent: - Diag(getAsNamedDecl(Info.Param)->getLocation(), - diag::err_inconsistent_deduction) - << Info.FirstArg << Info.SecondArg; - return false; - case TemplateDeductionResult::AlreadyDiagnosed: - return false; - - // None of these should happen for a plain deduction. - case TemplateDeductionResult::Invalid: - case TemplateDeductionResult::InstantiationDepth: - case TemplateDeductionResult::Incomplete: - case TemplateDeductionResult::IncompletePack: - case TemplateDeductionResult::Underqualified: - case TemplateDeductionResult::SubstitutionFailure: - case TemplateDeductionResult::DeducedMismatch: - case TemplateDeductionResult::DeducedMismatchNested: - case TemplateDeductionResult::TooManyArguments: - case TemplateDeductionResult::TooFewArguments: - case TemplateDeductionResult::InvalidExplicitArguments: - case TemplateDeductionResult::NonDependentConversionFailure: - case TemplateDeductionResult::ConstraintsNotSatisfied: - case TemplateDeductionResult::CUDATargetMismatch: - llvm_unreachable("Unexpected Result"); - } SmallVector DeducedArgs(Deduced.begin(), Deduced.end()); + Sema::InstantiatingTemplate Inst(*this, Info.getLocation(), AArg, DeducedArgs, + Info); + if (Inst.isInvalid()) + return false; - TemplateDeductionResult TDK; + bool AtLeastAsSpecialized; runWithSufficientStackSpace(Info.getLocation(), [&] { - TDK = ::FinishTemplateArgumentDeduction( - *this, AArg, /*IsPartialOrdering=*/true, PArgs, Deduced, Info); + AtLeastAsSpecialized = + ::FinishTemplateArgumentDeduction( + *this, AArg, /*IsPartialOrdering=*/true, PArgs, Deduced, Info) == + TemplateDeductionResult::Success; }); - switch (TDK) { - case TemplateDeductionResult::Success: - return true; - - // It doesn't seem possible to get a non-deduced mismatch when partial - // ordering TTPs. - case TemplateDeductionResult::NonDeducedMismatch: - llvm_unreachable("Unexpected NonDeducedMismatch"); - - // Substitution failures should have already been diagnosed. - case TemplateDeductionResult::AlreadyDiagnosed: - case TemplateDeductionResult::SubstitutionFailure: - case TemplateDeductionResult::InstantiationDepth: - return false; - - // None of these should happen when just converting deduced arguments. - case TemplateDeductionResult::Invalid: - case TemplateDeductionResult::Incomplete: - case TemplateDeductionResult::IncompletePack: - case TemplateDeductionResult::Inconsistent: - case TemplateDeductionResult::Underqualified: - case TemplateDeductionResult::DeducedMismatch: - case TemplateDeductionResult::DeducedMismatchNested: - case TemplateDeductionResult::TooManyArguments: - case TemplateDeductionResult::TooFewArguments: - case TemplateDeductionResult::InvalidExplicitArguments: - case TemplateDeductionResult::NonDependentConversionFailure: - case TemplateDeductionResult::ConstraintsNotSatisfied: - case TemplateDeductionResult::MiscellaneousDeductionFailure: - case TemplateDeductionResult::CUDATargetMismatch: - llvm_unreachable("Unexpected Result"); - } - llvm_unreachable("Unexpected TDK"); + return AtLeastAsSpecialized; } namespace { diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp index 545da21183c3c4..2d3e58548fb7ac 100644 --- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp +++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp @@ -70,8 +70,8 @@ class ExtractTypeForDeductionGuide ExtractTypeForDeductionGuide( Sema &SemaRef, llvm::SmallVectorImpl &MaterializedTypedefs, - ClassTemplateDecl *NestedPattern, - const MultiLevelTemplateArgumentList *OuterInstantiationArgs) + ClassTemplateDecl *NestedPattern = nullptr, + const MultiLevelTemplateArgumentList *OuterInstantiationArgs = nullptr) : Base(SemaRef), MaterializedTypedefs(MaterializedTypedefs), NestedPattern(NestedPattern), OuterInstantiationArgs(OuterInstantiationArgs) { @@ -1228,10 +1228,25 @@ FunctionTemplateDecl *DeclareAggregateDeductionGuideForTypeAlias( getRHSTemplateDeclAndArgs(SemaRef, AliasTemplate).first; if (!RHSTemplate) return nullptr; + + llvm::SmallVector TypedefDecls; + llvm::SmallVector NewParamTypes; + ExtractTypeForDeductionGuide TypeAliasTransformer(SemaRef, TypedefDecls); + for (QualType P : ParamTypes) { + QualType Type = TypeAliasTransformer.TransformType(P); + if (Type.isNull()) + return nullptr; + NewParamTypes.push_back(Type); + } + auto *RHSDeductionGuide = SemaRef.DeclareAggregateDeductionGuideFromInitList( - RHSTemplate, ParamTypes, Loc); + RHSTemplate, NewParamTypes, Loc); if (!RHSDeductionGuide) return nullptr; + + for (TypedefNameDecl *TD : TypedefDecls) + TD->setDeclContext(RHSDeductionGuide->getTemplatedDecl()); + return BuildDeductionGuideForTypeAlias(SemaRef, AliasTemplate, RHSDeductionGuide, Loc); } diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 74252bd7513cd7..2263b76520ca25 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -572,7 +572,6 @@ bool Sema::CodeSynthesisContext::isInstantiationRecord() const { case LambdaExpressionSubstitution: case BuildingDeductionGuides: case TypeAliasTemplateInstantiation: - case PartialOrderingTTP: return false; // This function should never be called when Kind's value is Memoization. @@ -805,11 +804,6 @@ Sema::InstantiatingTemplate::InstantiatingTemplate( SemaRef, CodeSynthesisContext::BuildingDeductionGuides, PointOfInstantiation, InstantiationRange, Entity) {} -Sema::InstantiatingTemplate::InstantiatingTemplate( - Sema &SemaRef, SourceLocation ArgLoc, PartialOrderingTTP, - TemplateDecl *PArg, SourceRange InstantiationRange) - : InstantiatingTemplate(SemaRef, CodeSynthesisContext::PartialOrderingTTP, - ArgLoc, InstantiationRange, PArg) {} void Sema::pushCodeSynthesisContext(CodeSynthesisContext Ctx) { Ctx.SavedInNonInstantiationSFINAEContext = InNonInstantiationSFINAEContext; @@ -1249,14 +1243,6 @@ void Sema::PrintInstantiationStack() { << cast(Active->Entity) << Active->InstantiationRange; break; - case CodeSynthesisContext::PartialOrderingTTP: - Diags.Report(Active->PointOfInstantiation, - diag::note_template_arg_template_params_mismatch); - if (SourceLocation ParamLoc = Active->Entity->getLocation(); - ParamLoc.isValid()) - Diags.Report(ParamLoc, diag::note_template_prev_declaration) - << /*isTemplateTemplateParam=*/true << Active->InstantiationRange; - break; } } } @@ -1299,7 +1285,6 @@ std::optional Sema::isSFINAEContext() const { case CodeSynthesisContext::PriorTemplateArgumentSubstitution: case CodeSynthesisContext::DefaultTemplateArgumentChecking: case CodeSynthesisContext::RewritingOperatorAsSpaceship: - case CodeSynthesisContext::PartialOrderingTTP: // A default template argument instantiation and substitution into // template parameters with arguments for prior parameters may or may // not be a SFINAE context; look further up the stack. @@ -1552,6 +1537,7 @@ namespace { NamedDecl *FirstQualifierInScope = nullptr, bool AllowInjectedClassName = false); + const AnnotateAttr *TransformAnnotateAttr(const AnnotateAttr *AA); const CXXAssumeAttr *TransformCXXAssumeAttr(const CXXAssumeAttr *AA); const LoopHintAttr *TransformLoopHintAttr(const LoopHintAttr *LH); const NoInlineAttr *TransformStmtNoInlineAttr(const Stmt *OrigS, @@ -2182,6 +2168,18 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E, Arg, PackIndex); } +const AnnotateAttr * +TemplateInstantiator::TransformAnnotateAttr(const AnnotateAttr *AA) { + SmallVector Args; + for (Expr *Arg : AA->args()) { + ExprResult Res = getDerived().TransformExpr(Arg); + if (Res.isUsable()) + Args.push_back(Res.get()); + } + return AnnotateAttr::CreateImplicit(getSema().Context, AA->getAnnotation(), + Args.data(), Args.size(), AA->getRange()); +} + const CXXAssumeAttr * TemplateInstantiator::TransformCXXAssumeAttr(const CXXAssumeAttr *AA) { ExprResult Res = getDerived().TransformExpr(AA->getAssumption()); @@ -4004,11 +4002,11 @@ bool Sema::usesPartialOrExplicitSpecialization( /// Get the instantiation pattern to use to instantiate the definition of a /// given ClassTemplateSpecializationDecl (either the pattern of the primary /// template or of a partial specialization). -static ActionResult getPatternForClassTemplateSpecialization( +static ActionResult +getPatternForClassTemplateSpecialization( Sema &S, SourceLocation PointOfInstantiation, ClassTemplateSpecializationDecl *ClassTemplateSpec, - TemplateSpecializationKind TSK, - bool PrimaryHasMatchedPackOnParmToNonPackOnArg) { + TemplateSpecializationKind TSK) { Sema::InstantiatingTemplate Inst(S, PointOfInstantiation, ClassTemplateSpec); if (Inst.isInvalid()) return {/*Invalid=*/true}; @@ -4031,7 +4029,7 @@ static ActionResult getPatternForClassTemplateSpecialization( // specialization with the template argument lists of the partial // specializations. typedef PartialSpecMatchResult MatchResult; - SmallVector Matched, ExtraMatched; + SmallVector Matched; SmallVector PartialSpecs; Template->getPartialSpecializations(PartialSpecs); TemplateSpecCandidateSet FailedCandidates(PointOfInstantiation); @@ -4048,13 +4046,11 @@ static ActionResult getPatternForClassTemplateSpecialization( MakeDeductionFailureInfo(S.Context, Result, Info)); (void)Result; } else { - auto &List = - Info.hasMatchedPackOnParmToNonPackOnArg() ? ExtraMatched : Matched; - List.push_back(MatchResult{Partial, Info.takeCanonical()}); + Matched.push_back(PartialSpecMatchResult()); + Matched.back().Partial = Partial; + Matched.back().Args = Info.takeCanonical(); } } - if (Matched.empty() && PrimaryHasMatchedPackOnParmToNonPackOnArg) - Matched = std::move(ExtraMatched); // If we're dealing with a member template where the template parameters // have been instantiated, this provides the original template parameters @@ -4157,8 +4153,7 @@ static ActionResult getPatternForClassTemplateSpecialization( bool Sema::InstantiateClassTemplateSpecialization( SourceLocation PointOfInstantiation, ClassTemplateSpecializationDecl *ClassTemplateSpec, - TemplateSpecializationKind TSK, bool Complain, - bool PrimaryHasMatchedPackOnParmToNonPackOnArg) { + TemplateSpecializationKind TSK, bool Complain) { // Perform the actual instantiation on the canonical declaration. ClassTemplateSpec = cast( ClassTemplateSpec->getCanonicalDecl()); @@ -4166,9 +4161,8 @@ bool Sema::InstantiateClassTemplateSpecialization( return true; ActionResult Pattern = - getPatternForClassTemplateSpecialization( - *this, PointOfInstantiation, ClassTemplateSpec, TSK, - PrimaryHasMatchedPackOnParmToNonPackOnArg); + getPatternForClassTemplateSpecialization(*this, PointOfInstantiation, + ClassTemplateSpec, TSK); if (!Pattern.isUsable()) return Pattern.isInvalid(); diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 34558e1a005d5a..6b1af35f5c80a8 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -230,7 +230,10 @@ static void instantiateDependentAnnotationAttr( ActualArgs.insert(ActualArgs.begin(), Args.begin() + 1, Args.end()); std::swap(Args, ActualArgs); } - S.AddAnnotationAttr(New, *Attr, Str, Args); + auto *AA = S.CreateAnnotationAttr(*Attr, Str, Args); + if (AA) { + New->addAttr(AA); + } } static Expr *instantiateDependentFunctionAttrCondition( diff --git a/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp index f0dc5efd75f7d6..7a85d9e2073068 100644 --- a/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp @@ -61,6 +61,10 @@ void PointerSubChecker::checkPreStmt(const BinaryOperator *B, if (LR->getSymbolicBase() || RR->getSymbolicBase()) return; + if (!B->getLHS()->getType()->isPointerType() || + !B->getRHS()->getType()->isPointerType()) + return; + const auto *ElemLR = dyn_cast(LR); const auto *ElemRR = dyn_cast(RR); diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp index 394cb26f03cf99..b7b2f8a16f07b3 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp @@ -101,6 +101,11 @@ bool tryToFindPtrOrigin( if (isSingleton(callee)) return callback(E, true); + if (callee->isInStdNamespace() && safeGetName(callee) == "forward") { + E = call->getArg(0); + continue; + } + if (isPtrConversion(callee)) { E = call->getArg(0); continue; diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp index 4d145be808f6d8..2298fe39850de5 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp @@ -177,14 +177,10 @@ std::optional isUncounted(const CXXRecordDecl* Class) return (*IsRefCountable); } -std::optional isUncountedPtr(const Type* T) -{ - assert(T); - +std::optional isUncountedPtr(const QualType T) { if (T->isPointerType() || T->isReferenceType()) { - if (auto *CXXRD = T->getPointeeCXXRecordDecl()) { + if (auto *CXXRD = T->getPointeeCXXRecordDecl()) return isUncounted(CXXRD); - } } return false; } @@ -208,12 +204,8 @@ std::optional isGetterOfRefCounted(const CXXMethodDecl* M) // Ref -> T conversion // FIXME: Currently allowing any Ref -> whatever cast. if (isRefType(className)) { - if (auto *maybeRefToRawOperator = dyn_cast(M)) { - if (auto *targetConversionType = - maybeRefToRawOperator->getConversionType().getTypePtrOrNull()) { - return isUncountedPtr(targetConversionType); - } - } + if (auto *maybeRefToRawOperator = dyn_cast(M)) + return isUncountedPtr(maybeRefToRawOperator->getConversionType()); } } return false; @@ -508,6 +500,10 @@ class TrivialFunctionAnalysisVisitor return IsFunctionTrivial(CE->getConstructor()); } + bool VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *E) { + return IsFunctionTrivial(E->getConstructor()); + } + bool VisitCXXNewExpr(const CXXNewExpr *NE) { return VisitChildren(NE); } bool VisitImplicitCastExpr(const ImplicitCastExpr *ICE) { diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h index 3528c52a7d659d..8e6aadf63b6d67 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h @@ -61,7 +61,7 @@ std::optional isUncounted(const clang::CXXRecordDecl* Class); /// \returns true if \p T is either a raw pointer or reference to an uncounted /// class, false if not, std::nullopt if inconclusive. -std::optional isUncountedPtr(const clang::Type* T); +std::optional isUncountedPtr(const clang::QualType T); /// \returns true if Name is a RefPtr, Ref, or its variant, false if not. bool isRefType(const std::string &Name); diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp index 0ed93ab26bf5ca..cea3503fa2c314 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp @@ -115,12 +115,8 @@ class UncountedCallArgsChecker // continue; QualType ArgType = (*P)->getType().getCanonicalType(); - const auto *TypePtr = ArgType.getTypePtrOrNull(); - if (!TypePtr) - continue; // FIXME? Should we bail? - // FIXME: more complex types (arrays, references to raw pointers, etc) - std::optional IsUncounted = isUncountedPtr(TypePtr); + std::optional IsUncounted = isUncountedPtr(ArgType); if (!IsUncounted || !(*IsUncounted)) continue; diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp index a226a01ec0a579..998bd4ccee07db 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp @@ -59,11 +59,11 @@ class UncountedLambdaCapturesChecker for (const LambdaCapture &C : L->captures()) { if (C.capturesVariable()) { ValueDecl *CapturedVar = C.getCapturedVar(); - if (auto *CapturedVarType = CapturedVar->getType().getTypePtrOrNull()) { - std::optional IsUncountedPtr = isUncountedPtr(CapturedVarType); - if (IsUncountedPtr && *IsUncountedPtr) { - reportBug(C, CapturedVar, CapturedVarType); - } + QualType CapturedVarQualType = CapturedVar->getType(); + if (auto *CapturedVarType = CapturedVarQualType.getTypePtrOrNull()) { + auto IsUncountedPtr = isUncountedPtr(CapturedVarQualType); + if (IsUncountedPtr && *IsUncountedPtr) + reportBug(C, CapturedVar, CapturedVarType); } } } diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLocalVarsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLocalVarsChecker.cpp index 9d0a3bb5da7325..81d21100de878d 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLocalVarsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLocalVarsChecker.cpp @@ -199,11 +199,7 @@ class UncountedLocalVarsChecker if (shouldSkipVarDecl(V)) return; - const auto *ArgType = V->getType().getTypePtr(); - if (!ArgType) - return; - - std::optional IsUncountedPtr = isUncountedPtr(ArgType); + std::optional IsUncountedPtr = isUncountedPtr(V->getType()); if (IsUncountedPtr && *IsUncountedPtr) { if (tryToFindPtrOrigin( Value, /*StopAtFirstRefCountedObj=*/false, diff --git a/clang/test/AST/ByteCode/cxx1z.cpp b/clang/test/AST/ByteCode/cxx1z.cpp new file mode 100644 index 00000000000000..57f99235a2b201 --- /dev/null +++ b/clang/test/AST/ByteCode/cxx1z.cpp @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++17 -verify=expected,both %s +// RUN: %clang_cc1 -std=c++17 -verify=ref,both %s + +template struct A {}; +namespace Temp { + struct S { int n; }; + constexpr S &addr(S &&s) { return s; } + A a; // both-error {{reference to temporary object}} + A b; // both-error {{pointer to temporary object}} + A c; // both-error {{reference to subobject of temporary object}} + A d; // both-error {{pointer to subobject of temporary object}} +} + +char arr[3]; +A d; // both-error {{refers to subobject '&arr[1]'}} + +void Func() { + A a; // both-error {{pointer to subobject of predefined '__func__' variable}} +} diff --git a/clang/test/AST/ast-dump-for-range-lifetime.cpp b/clang/test/AST/ast-dump-for-range-lifetime.cpp index 0e92b6990ed504..ee046be19ab632 100644 --- a/clang/test/AST/ast-dump-for-range-lifetime.cpp +++ b/clang/test/AST/ast-dump-for-range-lifetime.cpp @@ -449,4 +449,63 @@ void test13() { for (auto e : dg().r().g().r().g().r().g()) bar(e); } + +extern "C" void exit(int); + +struct A14 { + int arr[1]; + ~A14() noexcept(false) { throw 42; } +}; + +struct B14 { + int x; + const A14 &a = A14{{0}}; + const int *begin() { return a.arr; } + const int *end() { return &a.arr[1]; } +}; + +void test14() { + // The ExprWithCleanups in CXXDefaultInitExpr will be ignored. + + // CHECK: FunctionDecl {{.*}} test14 'void ()' + // CHECK: -CXXForRangeStmt {{.*}} + // CHECK-NEXT: |-<<>> + // CHECK-NEXT: |-DeclStmt {{.*}} + // CHECK-NEXT: | `-VarDecl {{.*}} implicit used __range1 'const int (&)[1]' cinit + // CHECK-NEXT: | `-ExprWithCleanups {{.*}} 'const int[1]' lvalue + // CHECK-NEXT: | `-MemberExpr {{.*}} 'const int[1]' lvalue .arr {{.*}} + // CHECK-NEXT: | `-MemberExpr {{.*}} 'const A14':'const P2718R0::A14' lvalue .a {{.*}} + // CHECK-NEXT: | `-MaterializeTemporaryExpr {{.*}} 'B14':'P2718R0::B14' xvalue extended by Var {{.*}} '__range1' 'const int (&)[1]' + // CHECK-NEXT: | `-CXXFunctionalCastExpr {{.*}} 'B14':'P2718R0::B14' functional cast to B14 + // CHECK-NEXT: | `-InitListExpr {{.*}} 'B14':'P2718R0::B14' + // CHECK-NEXT: | |-IntegerLiteral {{.*}} 'int' 0 + // CHECK-NEXT: | `-CXXDefaultInitExpr {{.*}} 'const A14':'const P2718R0::A14' lvalue has rewritten init + // CHECK-NEXT: | `-MaterializeTemporaryExpr {{.*}} 'const A14':'const P2718R0::A14' lvalue extended by Var {{.*}} '__range1' 'const int (&)[1]' + // CHECK-NEXT: | `-ImplicitCastExpr {{.*}} 'const A14':'const P2718R0::A14' + // CHECK-NEXT: | `-CXXFunctionalCastExpr {{.*}} 'A14':'P2718R0::A14' functional cast to A14 + // CHECK-NEXT: | `-CXXBindTemporaryExpr {{.*}} 'A14':'P2718R0::A14' (CXXTemporary {{.*}}) + // CHECK-NEXT: | `-InitListExpr {{.*}} 'A14':'P2718R0::A14' + // CHECK-NEXT: | `-InitListExpr {{.*}} 'int[1]' + // CHECK-NEXT: | `-IntegerLiteral {{.*}} 'int' 0 + for (auto &&x : B14{0}.a.arr) { exit(0); } + + // CHECK: -CXXForRangeStmt {{.*}} + // CHECK-NEXT: |-<<>> + // CHECK-NEXT: |-DeclStmt {{.*}} + // CHECK-NEXT: | `-VarDecl {{.*}} col:19 implicit used __range1 'B14 &&' cinit + // CHECK-NEXT: | `-ExprWithCleanups {{.*}} 'B14':'P2718R0::B14' xvalue + // CHECK-NEXT: | `-MaterializeTemporaryExpr {{.*}} 'B14':'P2718R0::B14' xvalue extended by Var {{.*}} '__range1' 'B14 &&' + // CHECK-NEXT: | `-CXXFunctionalCastExpr {{.*}} 'B14':'P2718R0::B14' functional cast to B14 + // CHECK-NEXT: | `-InitListExpr {{.*}} 'B14':'P2718R0::B14' + // CHECK-NEXT: | |-IntegerLiteral {{.*}} 'int' 0 + // CHECK-NEXT: | `-CXXDefaultInitExpr {{.*}} 'const A14':'const P2718R0::A14' lvalue has rewritten init + // CHECK-NEXT: | `-MaterializeTemporaryExpr {{.*}} 'const A14':'const P2718R0::A14' lvalue extended by Var {{.*}} '__range1' 'B14 &&' + // CHECK-NEXT: | `-ImplicitCastExpr {{.*}} 'const A14':'const P2718R0::A14' + // CHECK-NEXT: | `-CXXFunctionalCastExpr {{.*}} 'A14':'P2718R0::A14' functional cast to A14 + // CHECK-NEXT: | `-CXXBindTemporaryExpr {{.*}} 'A14':'P2718R0::A14' (CXXTemporary {{.*}}) + // CHECK-NEXT: | `-InitListExpr {{.*}} 'A14':'P2718R0::A14' + // CHECK-NEXT: | `-InitListExpr {{.*}} 'int[1]' + // CHECK-NEXT: | `-IntegerLiteral {{.*}} 'int' 0 + for (auto &&x : B14{0}) { exit(0); } +} } // namespace P2718R0 diff --git a/clang/test/AST/attr-print-emit.cpp b/clang/test/AST/attr-print-emit.cpp index d8e62ed5f6cd11..a9bca6778d0f1a 100644 --- a/clang/test/AST/attr-print-emit.cpp +++ b/clang/test/AST/attr-print-emit.cpp @@ -78,6 +78,9 @@ class C { ANNOTATE_ATTR int annotated_attr ANNOTATE_ATTR = 0; // CHECK: __attribute__((annotate("Annotated"))) int annotated_attr __attribute__((annotate("Annotated"))) = 0; +void increment() { [[clang::annotate("Annotated")]] annotated_attr++; } +// CHECK: {{\[\[}}clang::annotate("Annotated")]] annotated_attr++; + // FIXME: We do not print the attribute as written after the type specifier. int ANNOTATE_ATTR annotated_attr_fixme = 0; // CHECK: __attribute__((annotate("Annotated"))) int annotated_attr_fixme = 0; diff --git a/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp b/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp index 97efb354f0371d..1a42de90105a55 100644 --- a/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp +++ b/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp @@ -224,6 +224,20 @@ class ObjectWithMutatingDestructor { Number n; }; +class BaseType { +public: + BaseType() : n(0) { } + BaseType(int v) : n(v) { } + BaseType(const char*); +private: + Number n; +}; + +class SomeType : public BaseType { +public: + using BaseType::BaseType; +}; + class RefCounted { public: void ref() const; @@ -336,6 +350,8 @@ class RefCounted { unsigned trivial60() { return ObjectWithNonTrivialDestructor { 5 }.value(); } unsigned trivial61() { return DerivedNumber('7').value(); } void trivial62() { WTFReportBacktrace(); } + SomeType trivial63() { return SomeType(0); } + SomeType trivial64() { return SomeType(); } static RefCounted& singleton() { static RefCounted s_RefCounted; @@ -425,6 +441,7 @@ class RefCounted { unsigned nonTrivial21() { return Number("123").value(); } unsigned nonTrivial22() { return ComplexNumber(123, "456").real().value(); } unsigned nonTrivial23() { return DerivedNumber("123").value(); } + SomeType nonTrivial24() { return SomeType("123"); } static unsigned s_v; unsigned v { 0 }; @@ -515,6 +532,8 @@ class UnrelatedClass { getFieldTrivial().trivial60(); // no-warning getFieldTrivial().trivial61(); // no-warning getFieldTrivial().trivial62(); // no-warning + getFieldTrivial().trivial63(); // no-warning + getFieldTrivial().trivial64(); // no-warning RefCounted::singleton().trivial18(); // no-warning RefCounted::singleton().someFunction(); // no-warning @@ -587,7 +606,11 @@ class UnrelatedClass { // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}} getFieldTrivial().nonTrivial23(); // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}} + getFieldTrivial().nonTrivial24(); + // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}} } + + void setField(RefCounted*); }; class UnrelatedClass2 { @@ -598,11 +621,24 @@ class UnrelatedClass2 { RefCounted &getFieldTrivialRecursively() { return getFieldTrivial().getFieldTrivial(); } RefCounted *getFieldTrivialTernary() { return Field ? Field->getFieldTernary() : nullptr; } + template + void callSetField(T&& item, AdditionalArgs&&... args) + { + item.setField(std::forward(args)...); + } + + template + void callSetField2(T&& item, AdditionalArgs&&... args) + { + item.setField(std::move(args)...); + } + void test() { getFieldTrivialRecursively().trivial1(); // no-warning getFieldTrivialTernary()->trivial2(); // no-warning getFieldTrivialRecursively().someFunction(); // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}} + callSetField(getFieldTrivial(), refCountedObj()); // no-warning } }; diff --git a/clang/test/Analysis/pointer-sub.c b/clang/test/Analysis/pointer-sub.c index 1c9d676ebb8f24..25fb7f043d468c 100644 --- a/clang/test/Analysis/pointer-sub.c +++ b/clang/test/Analysis/pointer-sub.c @@ -1,5 +1,7 @@ // RUN: %clang_analyze_cc1 -analyzer-checker=security.PointerSub -analyzer-output=text-minimal -verify %s +typedef int * Ptr; + void f1(void) { int x, y, z[10]; int d = &y - &x; // expected-warning{{Subtraction of two pointers that do not point into the same array is undefined behavior}} @@ -10,6 +12,12 @@ void f1(void) { d = &x - (&x + 1); // no-warning d = (&x + 0) - &x; // no-warning d = (z + 10) - z; // no-warning + d = (long long)&y - (long long)&x; // no-warning + long long l = 1; + d = l - (long long)&y; // no-warning + Ptr p1 = &x; + Ptr p2 = &y; + d = p1 - p2; // expected-warning{{Subtraction of two pointers that do not point into the same array is undefined behavior}} } void f2(void) { @@ -28,6 +36,10 @@ void f2(void) { d = (int *)((char *)(&a[4]) + sizeof(int)) - &a[4]; // no-warning (pointers into the same array data) d = (int *)((char *)(&a[4]) + 1) - &a[4]; // expected-warning{{Subtraction of two pointers that}} + + long long a1 = (long long)&a[1]; + long long b1 = (long long)&b[1]; + d = a1 - b1; } void f3(void) { diff --git a/clang/test/CXX/drs/cwg14xx.cpp b/clang/test/CXX/drs/cwg14xx.cpp index 5301185d046982..cb2f34bf5e427f 100644 --- a/clang/test/CXX/drs/cwg14xx.cpp +++ b/clang/test/CXX/drs/cwg14xx.cpp @@ -627,7 +627,7 @@ int i = N::f(); namespace cwg1479 { // cwg1479: 3.1 #if __cplusplus >= 201103L - int operator"" _a(const char*, std::size_t = 0); + int operator""_a(const char*, std::size_t = 0); // since-cxx11-error@-1 {{literal operator cannot have a default argument}} #endif } diff --git a/clang/test/CXX/drs/cwg25xx.cpp b/clang/test/CXX/drs/cwg25xx.cpp index 1924008f15ba58..87a728088ee6e4 100644 --- a/clang/test/CXX/drs/cwg25xx.cpp +++ b/clang/test/CXX/drs/cwg25xx.cpp @@ -88,6 +88,9 @@ operator"" _div(); using ::cwg2521::operator"" _\u03C0___; using ::cwg2521::operator""_div; // since-cxx11-warning@-2 {{identifier '_Ï€___' preceded by whitespace in a literal operator declaration is deprecated}} + +long double operator"" _RESERVED(long double); +// since-cxx11-warning@-1 {{identifier '_RESERVED' preceded by whitespace in a literal operator declaration is deprecated}} #pragma clang diagnostic pop #endif } // namespace cwg2521 diff --git a/clang/test/CXX/lex/lex.literal/lex.ext/p1.cpp b/clang/test/CXX/lex/lex.literal/lex.ext/p1.cpp index 1c227a1b10d385..ec478fbba60a18 100644 --- a/clang/test/CXX/lex/lex.literal/lex.ext/p1.cpp +++ b/clang/test/CXX/lex/lex.literal/lex.ext/p1.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s +// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wno-deprecated-literal-operator -verify %s void operator "" p31(long double); // expected-warning{{user-defined literal suffixes not starting with '_' are reserved}} void operator "" _p31(long double); diff --git a/clang/test/CXX/lex/lex.literal/lex.ext/p10.cpp b/clang/test/CXX/lex/lex.literal/lex.ext/p10.cpp index 1b5d3880cb6129..6a9d713ca72d2e 100644 --- a/clang/test/CXX/lex/lex.literal/lex.ext/p10.cpp +++ b/clang/test/CXX/lex/lex.literal/lex.ext/p10.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++11 -verify %s +// RUN: %clang_cc1 -std=c++11 -Wno-deprecated-literal-operator -verify %s using size_t = decltype(sizeof(int)); void operator "" wibble(const char *); // expected-warning {{user-defined literal suffixes not starting with '_' are reserved; no literal will invoke this operator}} diff --git a/clang/test/CXX/lex/lex.literal/lex.ext/p11.cpp b/clang/test/CXX/lex/lex.literal/lex.ext/p11.cpp index 8b5fcf4b609b65..d69a58a7dfad20 100644 --- a/clang/test/CXX/lex/lex.literal/lex.ext/p11.cpp +++ b/clang/test/CXX/lex/lex.literal/lex.ext/p11.cpp @@ -6,16 +6,16 @@ template struct same_type; template struct same_type {}; template using X = T; template...> -int operator "" _x(); // expected-warning {{string literal operator templates are a GNU extension}} +int operator ""_x(); // expected-warning {{string literal operator templates are a GNU extension}} template -double operator "" _x(); +double operator ""_x(); auto a="string"_x; auto b=42_x; same_type test_a; same_type test_b; -char operator "" _x(const char *begin, size_t size); +char operator ""_x(const char *begin, size_t size); auto c="string"_x; auto d=L"string"_x; same_type test_c; diff --git a/clang/test/CXX/lex/lex.literal/lex.ext/p3.cpp b/clang/test/CXX/lex/lex.literal/lex.ext/p3.cpp index d764989312c246..e5ab09c628bcfa 100644 --- a/clang/test/CXX/lex/lex.literal/lex.ext/p3.cpp +++ b/clang/test/CXX/lex/lex.literal/lex.ext/p3.cpp @@ -1,18 +1,18 @@ // RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s -int &operator "" _x1 (unsigned long long); +int &operator ""_x1 (unsigned long long); int &i1 = 0x123_x1; -double &operator "" _x1 (const char *); +double &operator ""_x1 (const char *); int &i2 = 45_x1; -template char &operator "" _x1 (); +template char &operator ""_x1 (); int &i3 = 0377_x1; int &i4 = 90000000000000000000000000000000000000000000000_x1; // expected-error {{integer literal is too large to be represented in any integer type}} -double &operator "" _x2 (const char *); +double &operator ""_x2 (const char *); double &i5 = 123123123123123123123123123123123123123123123_x2; -template constexpr int operator "" _x3() { return sizeof...(Cs); } +template constexpr int operator ""_x3() { return sizeof...(Cs); } static_assert(123456789012345678901234567890123456789012345678901234567890_x3 == 60, ""); diff --git a/clang/test/CXX/lex/lex.literal/lex.ext/p4.cpp b/clang/test/CXX/lex/lex.literal/lex.ext/p4.cpp index 011e832c69d729..7dbe70ce084e76 100644 --- a/clang/test/CXX/lex/lex.literal/lex.ext/p4.cpp +++ b/clang/test/CXX/lex/lex.literal/lex.ext/p4.cpp @@ -1,18 +1,18 @@ // RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s -int &operator "" _x1 (long double); +int &operator ""_x1 (long double); int &i1 = 0.123_x1; -double &operator "" _x1 (const char *); +double &operator ""_x1 (const char *); int &i2 = 45._x1; -template char &operator "" _x1 (); +template char &operator ""_x1 (); int &i3 = 0377e-1_x1; int &i4 = 1e1000000_x1; // expected-warning {{too large for type 'long double'}} -double &operator "" _x2 (const char *); +double &operator ""_x2 (const char *); double &i5 = 1e1000000_x2; -template constexpr int operator "" _x3() { return sizeof...(Cs); } +template constexpr int operator ""_x3() { return sizeof...(Cs); } static_assert(1e1000000_x3 == 9, ""); diff --git a/clang/test/CXX/lex/lex.literal/lex.ext/p5.cpp b/clang/test/CXX/lex/lex.literal/lex.ext/p5.cpp index aee20545ececfc..afadba282e626c 100644 --- a/clang/test/CXX/lex/lex.literal/lex.ext/p5.cpp +++ b/clang/test/CXX/lex/lex.literal/lex.ext/p5.cpp @@ -3,19 +3,19 @@ using size_t = decltype(sizeof(int)); -int &operator "" _x1 (const char *); -double &operator "" _x1 (const char *, size_t); +int &operator ""_x1 (const char *); +double &operator ""_x1 (const char *, size_t); double &i1 = "foo"_x1; #if __cplusplus >= 202002L using char8 = float; -float &operator "" _x1 (const char8_t *, size_t); +float &operator ""_x1 (const char8_t *, size_t); #else using char8 = double; #endif char8 &i2 = u8"foo"_x1; double &i3 = L"foo"_x1; // expected-error {{no matching literal operator for call to 'operator""_x1' with arguments of types 'const wchar_t *' and 'unsigned long'}} -char &operator "" _x1(const wchar_t *, size_t); +char &operator ""_x1(const wchar_t *, size_t); char &i4 = L"foo"_x1; // ok double &i5 = R"(foo)"_x1; // ok char8 &i6 = u\ diff --git a/clang/test/CXX/lex/lex.literal/lex.ext/p6.cpp b/clang/test/CXX/lex/lex.literal/lex.ext/p6.cpp index 23cd7081d5e3ee..b1df641f2dc43c 100644 --- a/clang/test/CXX/lex/lex.literal/lex.ext/p6.cpp +++ b/clang/test/CXX/lex/lex.literal/lex.ext/p6.cpp @@ -2,13 +2,13 @@ using size_t = decltype(sizeof(int)); -int &operator "" _x1 (const char *); +int &operator ""_x1 (const char *); double &i1 = 'a'_x1; // expected-error {{no matching literal operator}} -double &operator "" _x1 (wchar_t); +double &operator ""_x1 (wchar_t); double &i2 = L'a'_x1; double &i3 = 'a'_x1; // expected-error {{no matching literal operator}} -double &i4 = operator"" _x1('a'); // ok +double &i4 = operator""_x1('a'); // ok -char &operator "" _x1(char16_t); +char &operator ""_x1(char16_t); char &i5 = u'a'_x1; // ok double &i6 = L'a'_x1; // ok diff --git a/clang/test/CXX/lex/lex.literal/lex.ext/p7.cpp b/clang/test/CXX/lex/lex.literal/lex.ext/p7.cpp index 0b40ecdc143fcb..d571fcb8697eb0 100644 --- a/clang/test/CXX/lex/lex.literal/lex.ext/p7.cpp +++ b/clang/test/CXX/lex/lex.literal/lex.ext/p7.cpp @@ -10,9 +10,9 @@ template struct same_type {}; namespace std_example { -long double operator "" _w(long double); -std::string operator "" _w(const char16_t*, size_t); -unsigned operator "" _w(const char*); +long double operator ""_w(long double); +std::string operator ""_w(const char16_t*, size_t); +unsigned operator ""_w(const char*); int main() { auto v1 = 1.2_w; // calls operator""_w(1.2L) auto v2 = u"one"_w; // calls operator""_w(u"one", 3) diff --git a/clang/test/CXX/lex/lex.literal/lex.ext/p8.cpp b/clang/test/CXX/lex/lex.literal/lex.ext/p8.cpp index d9078221ff5e3a..67d976263e0167 100644 --- a/clang/test/CXX/lex/lex.literal/lex.ext/p8.cpp +++ b/clang/test/CXX/lex/lex.literal/lex.ext/p8.cpp @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -std=c++11 -verify %s using size_t = decltype(sizeof(int)); -constexpr const char *operator "" _id(const char *p, size_t) { return p; } +constexpr const char *operator ""_id(const char *p, size_t) { return p; } constexpr const char *s = "foo"_id "bar" "baz"_id "quux"; constexpr bool streq(const char *p, const char *q) { @@ -9,8 +9,8 @@ constexpr bool streq(const char *p, const char *q) { } static_assert(streq(s, "foobarbazquux"), ""); -constexpr const char *operator "" _trim(const char *p, size_t n) { - return *p == ' ' ? operator "" _trim(p + 1, n - 1) : p; +constexpr const char *operator ""_trim(const char *p, size_t n) { + return *p == ' ' ? operator ""_trim(p + 1, n - 1) : p; } constexpr const char *t = " " " "_trim " foo"; static_assert(streq(t, "foo"), ""); diff --git a/clang/test/CXX/lex/lex.literal/lex.ext/p9.cpp b/clang/test/CXX/lex/lex.literal/lex.ext/p9.cpp index 65e27b41b06680..fbdedd119d3d68 100644 --- a/clang/test/CXX/lex/lex.literal/lex.ext/p9.cpp +++ b/clang/test/CXX/lex/lex.literal/lex.ext/p9.cpp @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s using size_t = decltype(sizeof(int)); -void operator "" _x(const wchar_t *, size_t); +void operator ""_x(const wchar_t *, size_t); namespace std_example { diff --git a/clang/test/CXX/over/over.oper/over.literal/p2.cpp b/clang/test/CXX/over/over.oper/over.literal/p2.cpp index f3ebadd2b8b9bc..cf26806e9e7d75 100644 --- a/clang/test/CXX/over/over.oper/over.literal/p2.cpp +++ b/clang/test/CXX/over/over.oper/over.literal/p2.cpp @@ -1,43 +1,43 @@ // RUN: %clang_cc1 -std=c++11 %s -verify -void operator "" _a(const char *); +void operator ""_a(const char *); namespace N { - using ::operator "" _a; + using ::operator ""_a; - void operator "" _b(const char *); + void operator ""_b(const char *); } -using N::operator "" _b; +using N::operator ""_b; class C { - void operator "" _c(const char *); // expected-error {{must be in a namespace or global scope}} + void operator ""_c(const char *); // expected-error {{must be in a namespace or global scope}} - static void operator "" _c(unsigned long long); // expected-error {{must be in a namespace or global scope}} + static void operator ""_c(unsigned long long); // expected-error {{must be in a namespace or global scope}} - friend void operator "" _d(const char *); + friend void operator ""_d(const char *); }; -int operator "" _e; // expected-error {{cannot be the name of a variable}} +int operator ""_e; // expected-error {{cannot be the name of a variable}} void f() { - int operator "" _f; // expected-error {{cannot be the name of a variable}} + int operator ""_f; // expected-error {{cannot be the name of a variable}} } extern "C++" { - void operator "" _g(const char *); + void operator ""_g(const char *); } -template void operator "" _h() {} +template void operator ""_h() {} -template<> void operator "" _h<'a', 'b', 'c'>() {} +template<> void operator ""_h<'a', 'b', 'c'>() {} -template void operator "" _h<'a', 'b', 'c', 'd'>(); +template void operator ""_h<'a', 'b', 'c', 'd'>(); namespace rdar13605348 { class C { - double operator"" _x(long double value) { return double(value); } // expected-error{{literal operator 'operator""_x' must be in a namespace or global scope}} + double operator""_x(long double value) { return double(value); } // expected-error{{literal operator 'operator""_x' must be in a namespace or global scope}} double value() { return 3.2_x; } // expected-error{{no matching literal operator for call to}} }; diff --git a/clang/test/CXX/over/over.oper/over.literal/p3.cpp b/clang/test/CXX/over/over.oper/over.literal/p3.cpp index 674ace9aee1929..53ebe102630843 100644 --- a/clang/test/CXX/over/over.oper/over.literal/p3.cpp +++ b/clang/test/CXX/over/over.oper/over.literal/p3.cpp @@ -3,38 +3,38 @@ using size_t = decltype(sizeof(int)); // Acceptable parameter declarations -char operator "" _a(const char *); -char operator "" _a(const char []); -char operator "" _a(unsigned long long); -char operator "" _a(long double); -char operator "" _a(char); -char operator "" _a(const volatile char); -char operator "" _a(wchar_t); -char operator "" _a(char16_t); -char operator "" _a(char32_t); -char operator "" _a(const char *, size_t); -char operator "" _a(const wchar_t *, size_t); -char operator "" _a(const char16_t *, size_t); -char operator "" _a(const char32_t *, size_t); -char operator "" _a(const char [32], size_t); +char operator ""_a(const char *); +char operator ""_a(const char []); +char operator ""_a(unsigned long long); +char operator ""_a(long double); +char operator ""_a(char); +char operator ""_a(const volatile char); +char operator ""_a(wchar_t); +char operator ""_a(char16_t); +char operator ""_a(char32_t); +char operator ""_a(const char *, size_t); +char operator ""_a(const wchar_t *, size_t); +char operator ""_a(const char16_t *, size_t); +char operator ""_a(const char32_t *, size_t); +char operator ""_a(const char [32], size_t); // Unacceptable parameter declarations -char operator "" _b(); // expected-error {{parameter}} -char operator "" _b(const wchar_t *); // expected-error {{parameter}} -char operator "" _b(long long); // expected-error {{parameter}} -char operator "" _b(double); // expected-error {{parameter}} -char operator "" _b(short); // expected-error {{parameter}} -char operator "" _a(char, int = 0); // expected-error {{parameter}} -char operator "" _b(unsigned short); // expected-error {{parameter}} -char operator "" _b(signed char); // expected-error {{parameter}} -char operator "" _b(unsigned char); // expected-error {{parameter}} -char operator "" _b(const short *, size_t); // expected-error {{parameter}} -char operator "" _b(const unsigned short *, size_t); // expected-error {{parameter}} -char operator "" _b(const signed char *, size_t); // expected-error {{parameter}} -char operator "" _b(const unsigned char *, size_t); // expected-error {{parameter}} -char operator "" _a(const volatile char *, size_t); // expected-error {{parameter}} -char operator "" _a(volatile wchar_t *, size_t); // expected-error {{parameter}} -char operator "" _a(char16_t *, size_t); // expected-error {{parameter}} -char operator "" _a(const char32_t *, size_t, bool = false); // expected-error {{parameter}} -char operator "" _a(const char *, signed long); // expected-error {{parameter}} -char operator "" _a(const char *, size_t = 0); // expected-error {{default argument}} +char operator ""_b(); // expected-error {{parameter}} +char operator ""_b(const wchar_t *); // expected-error {{parameter}} +char operator ""_b(long long); // expected-error {{parameter}} +char operator ""_b(double); // expected-error {{parameter}} +char operator ""_b(short); // expected-error {{parameter}} +char operator ""_a(char, int = 0); // expected-error {{parameter}} +char operator ""_b(unsigned short); // expected-error {{parameter}} +char operator ""_b(signed char); // expected-error {{parameter}} +char operator ""_b(unsigned char); // expected-error {{parameter}} +char operator ""_b(const short *, size_t); // expected-error {{parameter}} +char operator ""_b(const unsigned short *, size_t); // expected-error {{parameter}} +char operator ""_b(const signed char *, size_t); // expected-error {{parameter}} +char operator ""_b(const unsigned char *, size_t); // expected-error {{parameter}} +char operator ""_a(const volatile char *, size_t); // expected-error {{parameter}} +char operator ""_a(volatile wchar_t *, size_t); // expected-error {{parameter}} +char operator ""_a(char16_t *, size_t); // expected-error {{parameter}} +char operator ""_a(const char32_t *, size_t, bool = false); // expected-error {{parameter}} +char operator ""_a(const char *, signed long); // expected-error {{parameter}} +char operator ""_a(const char *, size_t = 0); // expected-error {{default argument}} diff --git a/clang/test/CXX/over/over.oper/over.literal/p5.cpp b/clang/test/CXX/over/over.oper/over.literal/p5.cpp index bfad5f00cf6c75..593aa57b76a81c 100644 --- a/clang/test/CXX/over/over.oper/over.literal/p5.cpp +++ b/clang/test/CXX/over/over.oper/over.literal/p5.cpp @@ -3,20 +3,20 @@ using size_t = decltype(sizeof(int)); template struct S {}; -template void operator "" _a(); -template S operator "" _a(); +template void operator ""_a(); +template S operator ""_a(); template struct U { - friend int operator "" _a(const char *, size_t); + friend int operator ""_a(const char *, size_t); // FIXME: It's not entirely clear whether this is intended to be legal. - friend U operator "" _a(const T *, size_t); // expected-error {{parameter}} + friend U operator ""_a(const T *, size_t); // expected-error {{parameter}} }; template struct V { - friend void operator "" _b(); // expected-error {{parameters}} + friend void operator ""_b(); // expected-error {{parameters}} }; -template void operator "" _b(); // expected-error {{template}} -template void operator "" _b(int N = 0); // expected-error {{template}} -template void operator "" _b(); // expected-error {{template}} -template T operator "" _b(const char *); // expected-error {{template}} -template int operator "" _b(const T *, size_t); // expected-error {{template}} +template void operator ""_b(); // expected-error {{template}} +template void operator ""_b(int N = 0); // expected-error {{template}} +template void operator ""_b(); // expected-error {{template}} +template T operator ""_b(const char *); // expected-error {{template}} +template int operator ""_b(const T *, size_t); // expected-error {{template}} diff --git a/clang/test/CXX/over/over.oper/over.literal/p6.cpp b/clang/test/CXX/over/over.oper/over.literal/p6.cpp index 9ecf9ccccb14c6..265050e0a00967 100644 --- a/clang/test/CXX/over/over.oper/over.literal/p6.cpp +++ b/clang/test/CXX/over/over.oper/over.literal/p6.cpp @@ -1,15 +1,15 @@ // RUN: %clang_cc1 -std=c++11 %s -verify // expected-note@+1 {{extern "C" language linkage specification begins here}} -extern "C" void operator "" _a(const char *); // expected-error {{must have C++ linkage}} -extern "C" template void operator "" _b(); // expected-error {{must have C++ linkage}} +extern "C" void operator ""_a(const char *); // expected-error {{must have C++ linkage}} +extern "C" template void operator ""_b(); // expected-error {{must have C++ linkage}} // expected-note@-1 {{extern "C" language linkage specification begins here}} extern "C" { // expected-note 4 {{extern "C" language linkage specification begins here}} - void operator "" _c(const char *); // expected-error {{must have C++ linkage}} - template void operator "" _d(); // expected-error {{must have C++ linkage}} + void operator ""_c(const char *); // expected-error {{must have C++ linkage}} + template void operator ""_d(); // expected-error {{must have C++ linkage}} namespace N { - void operator "" _e(const char *); // expected-error {{must have C++ linkage}} - template void operator "" _f(); // expected-error {{must have C++ linkage}} + void operator ""_e(const char *); // expected-error {{must have C++ linkage}} + template void operator ""_f(); // expected-error {{must have C++ linkage}} } } diff --git a/clang/test/CXX/over/over.oper/over.literal/p7.cpp b/clang/test/CXX/over/over.oper/over.literal/p7.cpp index 74e9457bb55c38..244f043d4412e7 100644 --- a/clang/test/CXX/over/over.oper/over.literal/p7.cpp +++ b/clang/test/CXX/over/over.oper/over.literal/p7.cpp @@ -1,17 +1,17 @@ // RUN: %clang_cc1 -std=c++11 %s -verify // expected-no-diagnostics -constexpr int operator "" _a(const char *c) { +constexpr int operator ""_a(const char *c) { return c[0]; } -static_assert(operator "" _a("foo") == 'f', ""); +static_assert(operator ""_a("foo") == 'f', ""); void puts(const char *); -static inline void operator "" _puts(const char *c) { +static inline void operator ""_puts(const char *c) { puts(c); } void f() { - operator "" _puts("foo"); - operator "" _puts("bar"); + operator ""_puts("foo"); + operator ""_puts("bar"); } diff --git a/clang/test/CXX/over/over.oper/over.literal/p8.cpp b/clang/test/CXX/over/over.oper/over.literal/p8.cpp index 6644bae7e610d1..8aa31e1acd6e15 100644 --- a/clang/test/CXX/over/over.oper/over.literal/p8.cpp +++ b/clang/test/CXX/over/over.oper/over.literal/p8.cpp @@ -5,13 +5,13 @@ namespace std { using size_t = decltype(sizeof(int)); } -void operator "" _km(long double); // ok -string operator "" _i18n(const char*, std::size_t); // ok -template int operator "" \u03C0(); // ok, UCN for lowercase pi // expected-warning {{reserved}} +void operator ""_km(long double); // ok +string operator ""_i18n(const char*, std::size_t); // ok +template int operator ""\u03C0(); // ok, UCN for lowercase pi // expected-warning {{reserved}} float operator ""E(const char *); // expected-error {{invalid suffix on literal}} expected-warning {{reserved}} float operator " " B(const char *); // expected-error {{must be '""'}} expected-warning {{reserved}} -string operator "" 5X(const char *, std::size_t); // expected-error {{expected identifier}} -double operator "" _miles(double); // expected-error {{parameter}} +string operator ""5X(const char *, std::size_t); // expected-error {{expected identifier}} +double operator ""_miles(double); // expected-error {{parameter}} template int operator "" j(const char*); // expected-error {{template}} float operator ""_E(const char *); diff --git a/clang/test/CXX/special/class.temporary/p6.cpp b/clang/test/CXX/special/class.temporary/p6.cpp index a6d2adfd1fd2c5..2b1b531b7172ca 100644 --- a/clang/test/CXX/special/class.temporary/p6.cpp +++ b/clang/test/CXX/special/class.temporary/p6.cpp @@ -463,6 +463,80 @@ template void default_arg_dependent_context2(); template void default_arg_dependent_context3(); } // namespace default_arg +namespace default_init { +template +struct DepA { + T arr[1]; + ~DepA() {} +}; + +template +struct DepB { + int x; + const DepA &a = DepA{{0}}; + ~DepB() {} + const int *begin() { return a.arr; } + const int *end() { return &a.arr[1]; } +}; + +template +void default_init1_dependent() { + // CHECK-CXX23: void @_ZN7P2718R012default_init23default_init1_dependentINS0_4DepBIiEEEEvv() + // CHECK-CXX23-LABEL: for.cond.cleanup: + // CHECK-CXX23-NEXT: call void @_ZN7P2718R012default_init4DepBIiED1Ev( + // CHECK-CXX23-NEXT: call void @_ZN7P2718R012default_init4DepAIiED1Ev( + for (auto &&x : T{0}) {} +} + +template +void default_init2_dependent() { + // CHECK-CXX23: void @_ZN7P2718R012default_init23default_init2_dependentINS0_4DepBIiEEEEvv() + // CHECK-CXX23-LABEL: for.cond.cleanup: + // CHECK-CXX23-NEXT: call void @_ZN7P2718R012default_init4DepBIiED1Ev( + // CHECK-CXX23-NEXT: call void @_ZN7P2718R012default_init4DepAIiED1Ev( + for (auto &&x : T{0}.a.arr) {} +} + +template void default_init1_dependent>(); +template void default_init2_dependent>(); +} // namespace default_init + +// -- Examples from https://wg21.link/p2718r0 +extern void block_scope_begin_function(); +extern void block_scope_end_function(); +namespace std_examples { +using T = std::list; +const T& f1(const T& t) { return t; } +const T& f2(T t) { return t; } +T g(); +void foo() { + // CHECK-CXX23: define {{.*}} void @_ZN7P2718R012std_examples3fooEv() + // CHECK-CXX23: call void @_ZN7P2718R026block_scope_begin_functionEv + block_scope_begin_function(); + { + // CHECK-CXX23-NEXT: call void @_ZN7P2718R012std_examples1gEv + // CHECK-CXX23-NEXT: call {{.*}} @_ZN7P2718R012std_examples2f1ERKSt4listIiE + // CHECK-CXX23: for.cond.cleanup: + // CHECK-CXX23-NEXT: call void @_ZNSt4listIiED1Ev + for (auto e : f1(g())) {} // OK, lifetime of return value of g() extended + } + // CHECK-CXX23: call void @_ZN7P2718R024block_scope_end_functionEv + block_scope_end_function(); + + // The lifetime of temporary returned by g() in this case will not be extended. + // CHECK-CXX23: call void @_ZN7P2718R026block_scope_begin_functionEv + block_scope_begin_function(); + { + // CHECK-CXX23-NEXT: call void @_ZN7P2718R012std_examples1gEv + // CHECK-CXX23-NEXT: call {{.*}} @_ZN7P2718R012std_examples2f2ESt4listIiE + // CHECK-CXX23-NEXT: call void @_ZNSt4listIiED1Ev + for (auto e : f2(g())) {} // undefined behavior + } + // CHECK-CXX23: call void @_ZN7P2718R024block_scope_end_functionEv + block_scope_end_function(); +} +} // namespace std_examples + namespace basic { using T = std::list; const T& f1(const T& t) { return t; } @@ -579,5 +653,51 @@ void default_arg3() { for (auto e : C(0, C(0, C(0, C())))) {} } } // namespace default_arg -} // namespace P2718R0 +namespace default_init { +struct X { + int x; + ~X() {} +}; + +struct Y { + int y; + const X &x = X{1}; + ~Y() {} +}; + +struct A { + int arr[1]; + const Y &y = Y{1}; + ~A() {} +}; + +struct B { + int x; + const A &a = A{{0}}; + ~B() {} + const int *begin() { return a.arr; } + const int *end() { return &a.arr[1]; } +}; + +void default_init1() { + // CHECK-CXX23: void @_ZN7P2718R012default_init13default_init1Ev() + // CHECK-CXX23-LABEL: for.cond.cleanup: + // CHECK-CXX23-NEXT: call void @_ZN7P2718R012default_init1BD1Ev( + // CHECK-CXX23-NEXT: call void @_ZN7P2718R012default_init1AD1Ev( + // CHECK-CXX23-NEXT: call void @_ZN7P2718R012default_init1YD1Ev( + // CHECK-CXX23-NEXT: call void @_ZN7P2718R012default_init1XD1Ev( + for (auto &&x : B{0}) {} +} + +void default_init2() { + // CHECK-CXX23: void @_ZN7P2718R012default_init13default_init2Ev() + // CHECK-CXX23-LABEL: for.cond.cleanup: + // CHECK-CXX23-NEXT: call void @_ZN7P2718R012default_init1BD1Ev( + // CHECK-CXX23-NEXT: call void @_ZN7P2718R012default_init1AD1Ev( + // CHECK-CXX23-NEXT: call void @_ZN7P2718R012default_init1YD1Ev( + // CHECK-CXX23-NEXT: call void @_ZN7P2718R012default_init1XD1Ev( + for (auto &&x : B{0}.a.arr) {} +} +} // namespace default_init +} // namespace P2718R0 diff --git a/clang/test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp b/clang/test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp index 1bbbd1d3429ddd..19793fe8263726 100644 --- a/clang/test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp +++ b/clang/test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp @@ -2,13 +2,13 @@ template struct eval; // expected-note 3{{template is declared here}} -template