https://github.com/MaxEW707 updated https://github.com/llvm/llvm-project/pull/99833
>From 0a705b1a8e9673cd5e803ffe392dacfa0f06c40f Mon Sep 17 00:00:00 2001 From: MaxEW707 <max.enrico.wink...@gmail.com> Date: Fri, 21 Jun 2024 20:37:40 -0700 Subject: [PATCH 01/15] Support MSVC lvalue to temporary reference binding --- clang/docs/ReleaseNotes.rst | 4 + clang/include/clang/Basic/LangOptions.def | 1 + clang/include/clang/Driver/Options.td | 12 +++ clang/include/clang/Sema/Sema.h | 2 + clang/lib/Driver/ToolChains/Clang.cpp | 5 + clang/lib/Driver/ToolChains/MSVC.cpp | 1 + clang/lib/Sema/SemaInit.cpp | 22 +++-- clang/lib/Sema/SemaOverload.cpp | 16 ++- clang/test/Driver/cl-permissive.c | 7 ++ clang/test/Driver/cl-zc.cpp | 2 + clang/test/SemaCXX/ms-reference-binding.cpp | 102 ++++++++++++++++++++ 11 files changed, 165 insertions(+), 9 deletions(-) create mode 100644 clang/test/SemaCXX/ms-reference-binding.cpp diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 02284225fb4fa1..3e8f7a8f7d889e 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -419,6 +419,10 @@ New Compiler Flags existing ``-fno-c++-static-destructors`` flag) skips all static destructors registration. +- ``-fms-reference-binding`` and its clang-cl counterpart ``/Zc:referenceBinding``. + Implements the MSVC extension where expressions that bind a user-defined type temporary + to a non-const lvalue reference are allowed. + Deprecated Compiler Flags ------------------------- diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 39e4851dd3814c..c0451eaae344de 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -311,6 +311,7 @@ LANGOPT(HIPStdParInterposeAlloc, 1, 0, "Replace allocations / deallocations with LANGOPT(OpenACC , 1, 0, "OpenACC Enabled") LANGOPT(MSVCEnableStdcMacro , 1, 0, "Define __STDC__ with '-fms-compatibility'") +LANGOPT(MSVCReferenceBinding , 1, 0, "Accept expressions that bind a non-const lvalue reference to a temporary") LANGOPT(SizedDeallocation , 1, 0, "sized deallocation") LANGOPT(AlignedAllocation , 1, 0, "aligned allocation") LANGOPT(AlignedAllocationUnavailable, 1, 0, "aligned allocation functions are unavailable") diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 4bc0b97ea68f2f..4f963a18297ee7 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -3096,6 +3096,12 @@ def fms_extensions : Flag<["-"], "fms-extensions">, Group<f_Group>, Visibility<[ClangOption, CC1Option, CLOption]>, HelpText<"Accept some non-standard constructs supported by the Microsoft compiler">, MarshallingInfoFlag<LangOpts<"MicrosoftExt">>, ImpliedByAnyOf<[fms_compatibility.KeyPath]>; +def fms_reference_binding : Flag<["-"], "fms-reference-binding">, Group<f_Group>, + Visibility<[ClangOption, CC1Option, CLOption]>, + HelpText<"Accept expressions that bind a non-const lvalue reference to a user-defined type temporary as supported by the Microsoft Compiler">, + MarshallingInfoFlag<LangOpts<"MSVCReferenceBinding">>; +def fno_ms_reference_binding : Flag<["-"], "fno-ms-reference-binding">, Group<f_Group>, + Visibility<[ClangOption, CLOption]>; defm asm_blocks : BoolFOption<"asm-blocks", LangOpts<"AsmBlocks">, Default<fms_extensions.KeyPath>, PosFlag<SetTrue, [], [ClangOption, CC1Option]>, @@ -8683,6 +8689,12 @@ def _SLASH_Zc_wchar_t : CLFlag<"Zc:wchar_t">, HelpText<"Enable C++ builtin type wchar_t (default)">; def _SLASH_Zc_wchar_t_ : CLFlag<"Zc:wchar_t-">, HelpText<"Disable C++ builtin type wchar_t">; +def _SLASH_Zc_referenceBinding : CLFlag<"Zc:referenceBinding">, + HelpText<"Do not accept expressions that bind a non-const lvalue reference to a user-defined type temporary">, + Alias<fno_ms_reference_binding>; +def _SLASH_Zc_referenceBinding_ : CLFlag<"Zc:referenceBinding-">, + HelpText<"Accept expressions that bind a non-const lvalue reference to a user-defined type temporary">, + Alias<fms_reference_binding>; def _SLASH_Z7 : CLFlag<"Z7">, Alias<g_Flag>, HelpText<"Enable CodeView debug information in object files">; def _SLASH_ZH_MD5 : CLFlag<"ZH:MD5">, diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index b8684d11460eda..ada5184eb71b05 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -10144,6 +10144,8 @@ class Sema final : public SemaBase { CompareReferenceRelationship(SourceLocation Loc, QualType T1, QualType T2, ReferenceConversions *Conv = nullptr); + bool AllowMSLValueReferenceBinding(Qualifiers Quals, QualType QT); + /// AddOverloadCandidate - Adds the given function to the set of /// candidate functions, using the given function call arguments. If /// @p SuppressUserConversions, then don't allow user-defined diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 99a092d83d531a..3d6d170aee4f34 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -7215,6 +7215,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, IsWindowsMSVC)) CmdArgs.push_back("-fms-extensions"); + // -fno-ms-reference-binding is the default. + if (Args.hasFlag(options::OPT_fms_reference_binding, + options::OPT_fno_ms_reference_binding, false)) + CmdArgs.push_back("-fms-reference-binding"); + // -fms-compatibility=0 is default. bool IsMSVCCompat = Args.hasFlag( options::OPT_fms_compatibility, options::OPT_fno_ms_compatibility, diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp index 80799d1e715f07..28731fdae50285 100644 --- a/clang/lib/Driver/ToolChains/MSVC.cpp +++ b/clang/lib/Driver/ToolChains/MSVC.cpp @@ -947,6 +947,7 @@ static void TranslatePermissive(Arg *A, llvm::opt::DerivedArgList &DAL, const OptTable &Opts) { DAL.AddFlagArg(A, Opts.getOption(options::OPT__SLASH_Zc_twoPhase_)); DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_operator_names)); + DAL.AddFlagArg(A, Opts.getOption(options::OPT_fms_reference_binding)); } static void TranslatePermissiveMinus(Arg *A, llvm::opt::DerivedArgList &DAL, diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 7c03a12e812809..c369a53742772c 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -5329,13 +5329,17 @@ static void TryReferenceInitializationCore(Sema &S, Sequence.SetOverloadFailure( InitializationSequence::FK_ReferenceInitOverloadFailed, ConvOvlResult); - else if (!InitCategory.isLValue()) - Sequence.SetFailed( - T1Quals.isAddressSpaceSupersetOf(T2Quals, S.getASTContext()) - ? InitializationSequence:: - FK_NonConstLValueReferenceBindingToTemporary - : InitializationSequence::FK_ReferenceInitDropsQualifiers); - else { + else if (!InitCategory.isLValue()) { + if (T1Quals.isAddressSpaceSupersetOf(T2Quals, S.getASTContext())) { + if (!S.getLangOpts().MSVCReferenceBinding || + !S.AllowMSLValueReferenceBinding(T1Quals, T1)) + Sequence.SetFailed(InitializationSequence:: + FK_NonConstLValueReferenceBindingToTemporary); + } else { + Sequence.SetFailed( + InitializationSequence::FK_ReferenceInitDropsQualifiers); + } + } else { InitializationSequence::FailureKind FK; switch (RefRelationship) { case Sema::Ref_Compatible: @@ -5361,7 +5365,9 @@ static void TryReferenceInitializationCore(Sema &S, } Sequence.SetFailed(FK); } - return; + + if (Sequence.Failed()) + return; } // - If the initializer expression diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index c174922a926fc6..957d667a4b5545 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -5013,6 +5013,16 @@ Sema::CompareReferenceRelationship(SourceLocation Loc, : Ref_Incompatible; } +bool Sema::AllowMSLValueReferenceBinding(Qualifiers Quals, QualType QT) { + if (Quals.hasVolatile()) + return false; + if (Quals.hasConst()) + return true; + if (QT->isBuiltinType() || QT->isArrayType()) + return false; + return true; +} + /// Look for a user-defined conversion to a value reference-compatible /// with DeclType. Return true if something definite is found. static bool @@ -5245,7 +5255,11 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType, // -- Otherwise, the reference shall be an lvalue reference to a // non-volatile const type (i.e., cv1 shall be const), or the reference // shall be an rvalue reference. - if (!isRValRef && (!T1.isConstQualified() || T1.isVolatileQualified())) { + const bool CanBindLValueRef = + !S.getLangOpts().MSVCReferenceBinding + ? (T1.isConstQualified() && !T1.isVolatileQualified()) + : S.AllowMSLValueReferenceBinding(T1.getQualifiers(), T1); + if (!isRValRef && !CanBindLValueRef) { if (InitCategory.isRValue() && RefRelationship != Sema::Ref_Incompatible) ICS.setBad(BadConversionSequence::lvalue_ref_to_rvalue, Init, DeclType); return ICS; diff --git a/clang/test/Driver/cl-permissive.c b/clang/test/Driver/cl-permissive.c index d88746d3a5517f..712bef71a43af1 100644 --- a/clang/test/Driver/cl-permissive.c +++ b/clang/test/Driver/cl-permissive.c @@ -3,9 +3,11 @@ // RUN: %clang_cl /permissive -### -- %s 2>&1 | FileCheck -check-prefix=PERMISSIVE %s // PERMISSIVE: "-fno-operator-names" +// PERMISSIVE: "-fms-reference-binding" // PERMISSIVE: "-fdelayed-template-parsing" // RUN: %clang_cl /permissive- -### -- %s 2>&1 | FileCheck -check-prefix=PERMISSIVE-MINUS %s // PERMISSIVE-MINUS-NOT: "-fno-operator-names" +// PERMISSIVE-MINUS-NOT: "-fms-reference-binding" // PERMISSIVE-MINUS-NOT: "-fdelayed-template-parsing" // The switches set by permissive may then still be manually enabled or disabled @@ -15,3 +17,8 @@ // RUN: %clang_cl /permissive- /Zc:twoPhase- -### -- %s 2>&1 | FileCheck -check-prefix=PERMISSIVE-MINUS-OVERWRITE %s // PERMISSIVE-MINUS-OVERWRITE-NOT: "-fno-operator-names" // PERMISSIVE-MINUS-OVERWRITE: "-fdelayed-template-parsing" + +// RUN: %clang_cl /permissive -fno-ms-reference-binding -### -- %s 2>&1 | FileCheck -check-prefix=PERMISSIVE-OVERWRITE-REF-BINDING %s +// PERMISSIVE-OVERWRITE-REF-BINDING-NOT: "-fms-reference-binding" +// RUN: %clang_cl /permissive- -fms-reference-binding -### -- %s 2>&1 | FileCheck -check-prefix=PERMISSIVE-MINUS-OVERWRITE-REF-BINDING %s +// PERMISSIVE-MINUS-OVERWRITE-REF-BINDING: "-fms-reference-binding" diff --git a/clang/test/Driver/cl-zc.cpp b/clang/test/Driver/cl-zc.cpp index 5f0cd5e00819dd..d2c27975dd6591 100644 --- a/clang/test/Driver/cl-zc.cpp +++ b/clang/test/Driver/cl-zc.cpp @@ -125,6 +125,8 @@ // RUN: %clang_cl -c -### /Zc:char8_t- -- %s 2>&1 | FileCheck -check-prefix CHECK-CHAR8_T_ %s // CHECK-CHAR8_T_: "-fno-char8_t" +// RUN: %clang_cl -c -### /Zc:referenceBinding- -- %s 2>&1 | FileCheck -check-prefix CHECK-REFERENCE_BINDING_ %s +// CHECK-REFERENCE_BINDING_: "-fms-reference-binding" // These never warn, but don't have an effect yet. diff --git a/clang/test/SemaCXX/ms-reference-binding.cpp b/clang/test/SemaCXX/ms-reference-binding.cpp new file mode 100644 index 00000000000000..44e4723fd4fa3a --- /dev/null +++ b/clang/test/SemaCXX/ms-reference-binding.cpp @@ -0,0 +1,102 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -fms-reference-binding %s + +struct A {}; +struct B : A {}; + +B fB(); +A fA(); + +A&& fARvalueRef(); +A(&&fARvalueRefArray())[1]; +void fARef(A&) {} + +void fIntRef(int&) {} // expected-note{{candidate function not viable: expects an lvalue for 1st argument}} +void fDoubleRef(double&) {} // expected-note{{candidate function not viable: expects an lvalue for 1st argument}} + +void fIntConstRef(const int&) {} +void fDoubleConstRef(const double&) {} + +void fIntArray(int (&)[1]); // expected-note{{candidate function not viable: expects an lvalue for 1st argument}} +void fIntConstArray(const int (&)[1]); + +namespace NS { + void fARef(A&) {} + + void fIntRef(int&) {} // expected-note{{passing argument to parameter here}} + void fDoubleRef(double&) {} // expected-note{{passing argument to parameter here}} + + void fIntConstRef(const int&) {} + void fDoubleConstRef(const double&) {} + + A(&&fARvalueRefArray())[1]; + + void fIntArray(int (&)[1]); // expected-note{{passing argument to parameter here}} + + void fIntConstArray(const int (&)[1]); +} + +void test1() { + double& rd2 = 2.0; // expected-error{{non-const lvalue reference to type 'double' cannot bind to a temporary of type 'double'}} + int& i1 = 0; // expected-error{{non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'}} + + fIntRef(0); // expected-error{{no matching function for call to 'fIntRef'}} + fDoubleRef(0.0); // expected-error{{no matching function for call to 'fDoubleRef'}} + + NS::fIntRef(0); // expected-error{{non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'}} + NS::fDoubleRef(0.0); // expected-error{{non-const lvalue reference to type 'double' cannot bind to a temporary of type 'double'}} + + int i2 = 2; + double& rd3 = i2; // expected-error{{non-const lvalue reference to type 'double' cannot bind to a value of unrelated type 'int'}} +} + +void test2() { + fIntConstRef(0); + fDoubleConstRef(0.0); + + NS::fIntConstRef(0); + NS::fDoubleConstRef(0.0); + + int i = 0; + const int ci = 0; + volatile int vi = 0; + const volatile int cvi = 0; + bool b = true; + + const volatile int &cvir1 = b ? ci : vi; // expected-error{{volatile lvalue reference to type 'const volatile int' cannot bind to a temporary of type 'int'}} + + volatile int& vir1 = 0; // expected-error{{volatile lvalue reference to type 'volatile int' cannot bind to a temporary of type 'int'}} + const volatile int& cvir2 = 0; // expected-error{{volatile lvalue reference to type 'const volatile int' cannot bind to a temporary of type 'int'}} +} + +void test3() { + A& a1 = A(); + + fARef(A()); + fARef(static_cast<A&&>(a1)); + fARef(B()); + + NS::fARef(A()); + NS::fARef(static_cast<A&&>(a1)); + NS::fARef(B()); + + A& a2 = fA(); + + A& a3 = fARvalueRef(); + + const A& rca = fB(); + A& ra = fB(); +} + +void test4() { + A (&array1)[1] = fARvalueRefArray(); // expected-error{{non-const lvalue reference to type 'A[1]' cannot bind to a temporary of type 'A[1]'}} + const A (&array2)[1] = fARvalueRefArray(); + + A (&array3)[1] = NS::fARvalueRefArray(); // expected-error{{non-const lvalue reference to type 'A[1]' cannot bind to a temporary of type 'A[1]'}} + const A (&array4)[1] = NS::fARvalueRefArray(); + + fIntArray({ 1 }); // expected-error{{no matching function for call to 'fIntArray'}} + NS::fIntArray({ 1 }); // expected-error{{non-const lvalue reference to type 'int[1]' cannot bind to an initializer list temporary}} + + fIntConstArray({ 1 }); + NS::fIntConstArray({ 1 }); +} >From 7d5d0b15fce06e2631b4f526f2a31e9aa4ffc971 Mon Sep 17 00:00:00 2001 From: MaxEW707 <max.enrico.wink...@gmail.com> Date: Sat, 20 Jul 2024 23:47:51 -0700 Subject: [PATCH 02/15] update description of lang opt --- clang/include/clang/Basic/LangOptions.def | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index c0451eaae344de..b3a706cfd7b318 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -311,7 +311,7 @@ LANGOPT(HIPStdParInterposeAlloc, 1, 0, "Replace allocations / deallocations with LANGOPT(OpenACC , 1, 0, "OpenACC Enabled") LANGOPT(MSVCEnableStdcMacro , 1, 0, "Define __STDC__ with '-fms-compatibility'") -LANGOPT(MSVCReferenceBinding , 1, 0, "Accept expressions that bind a non-const lvalue reference to a temporary") +LANGOPT(MSVCReferenceBinding , 1, 0, "Accept expressions that bind a non-const lvalue reference to a user-defined type temporary") LANGOPT(SizedDeallocation , 1, 0, "sized deallocation") LANGOPT(AlignedAllocation , 1, 0, "aligned allocation") LANGOPT(AlignedAllocationUnavailable, 1, 0, "aligned allocation functions are unavailable") >From 6ba101e8f7ab42193b074b3e587955be4128e0ed Mon Sep 17 00:00:00 2001 From: MaxEW707 <max.enrico.wink...@gmail.com> Date: Mon, 22 Jul 2024 21:44:33 -0700 Subject: [PATCH 03/15] PR Feedback on SemaOverload.cpp if check variable scoping --- clang/lib/Sema/SemaOverload.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 957d667a4b5545..7e4f1795bd3db7 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -5255,13 +5255,19 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType, // -- Otherwise, the reference shall be an lvalue reference to a // non-volatile const type (i.e., cv1 shall be const), or the reference // shall be an rvalue reference. - const bool CanBindLValueRef = - !S.getLangOpts().MSVCReferenceBinding - ? (T1.isConstQualified() && !T1.isVolatileQualified()) - : S.AllowMSLValueReferenceBinding(T1.getQualifiers(), T1); + if (!isRValRef) { + const bool CanBindLValueRef = + !S.getLangOpts().MSVCReferenceBinding + ? (T1.isConstQualified() && !T1.isVolatileQualified()) + : S.AllowMSLValueReferenceBinding(T1.getQualifiers(), T1); + if (!CanBindLValueRef) { + if (InitCategory.isRValue() && RefRelationship != Sema::Ref_Incompatible) + ICS.setBad(BadConversionSequence::lvalue_ref_to_rvalue, Init, DeclType); + return ICS; + } + } + if (!isRValRef && !CanBindLValueRef) { - if (InitCategory.isRValue() && RefRelationship != Sema::Ref_Incompatible) - ICS.setBad(BadConversionSequence::lvalue_ref_to_rvalue, Init, DeclType); return ICS; } >From 2b417ccb9dba0e3f62a4fe46f85882247b03f701 Mon Sep 17 00:00:00 2001 From: MaxEW707 <max.enrico.wink...@gmail.com> Date: Tue, 23 Jul 2024 20:40:06 -0700 Subject: [PATCH 04/15] Reorder logic around `AllowMSLValueReferenceBinding` --- clang/lib/Sema/SemaOverload.cpp | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 7e4f1795bd3db7..f2c7906ae45088 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -5014,13 +5014,8 @@ Sema::CompareReferenceRelationship(SourceLocation Loc, } bool Sema::AllowMSLValueReferenceBinding(Qualifiers Quals, QualType QT) { - if (Quals.hasVolatile()) - return false; - if (Quals.hasConst()) - return true; - if (QT->isBuiltinType() || QT->isArrayType()) - return false; - return true; + return getLangOpts().MSVCReferenceBinding && + !(Quals.hasVolatile() || QT->isBuiltinType() || QT->isArrayType()); } /// Look for a user-defined conversion to a value reference-compatible @@ -5255,19 +5250,10 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType, // -- Otherwise, the reference shall be an lvalue reference to a // non-volatile const type (i.e., cv1 shall be const), or the reference // shall be an rvalue reference. - if (!isRValRef) { - const bool CanBindLValueRef = - !S.getLangOpts().MSVCReferenceBinding - ? (T1.isConstQualified() && !T1.isVolatileQualified()) - : S.AllowMSLValueReferenceBinding(T1.getQualifiers(), T1); - if (!CanBindLValueRef) { - if (InitCategory.isRValue() && RefRelationship != Sema::Ref_Incompatible) - ICS.setBad(BadConversionSequence::lvalue_ref_to_rvalue, Init, DeclType); - return ICS; - } - } - - if (!isRValRef && !CanBindLValueRef) { + if (!isRValRef && (!T1.isConstQualified() || T1.isVolatileQualified()) && + !S.AllowMSLValueReferenceBinding(T1.getQualifiers(), T1)) { + if (InitCategory.isRValue() && RefRelationship != Sema::Ref_Incompatible) + ICS.setBad(BadConversionSequence::lvalue_ref_to_rvalue, Init, DeclType); return ICS; } >From ec7a263fd9c36ebcb77dd806ee8b926f8f5650d1 Mon Sep 17 00:00:00 2001 From: MaxEW707 <max.enrico.wink...@gmail.com> Date: Mon, 29 Jul 2024 08:23:24 -0700 Subject: [PATCH 05/15] PR Feedback on ext warning --- clang/docs/LanguageExtensions.rst | 30 +++++++++++++++++++ clang/include/clang/Basic/DiagnosticGroups.td | 1 + .../clang/Basic/DiagnosticSemaKinds.td | 4 +++ clang/lib/Sema/SemaInit.cpp | 7 +++-- clang/test/SemaCXX/ms-reference-binding.cpp | 18 ++++++++++- 5 files changed, 57 insertions(+), 3 deletions(-) diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index 6b950d05fb9bf9..e7ba4319a7d8b0 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -6015,3 +6015,33 @@ qualifications. Note, Clang does not allow an ``_Atomic`` function type because of explicit constraints against atomically qualified (arrays and) function types. + + +MSVC Extensions +=============== + +Clang supports a number of extensions inorder to imitate MSVC. +Some of these extensions are behind ``-fms-compatibility`` and ``-fms-extensions`` which +are further described in :doc:`MSVCCompatibility`. + +MSVC Reference Binding +---------------------- + +.. code-block:: c++ + + struct A {}; + + A& a = A(); + +Please see the `MSDN doc<https://learn.microsoft.com/en-us/cpp/build/reference/zc-referencebinding-enforce-reference-binding-rules>`_ for more information on this non-conforming C++ extension. + +MSVC allows user-defined type temporaries to be bound to non-const lvalue references when `/permissive` +or `/Zc:referenceBinding-` are given on the command line. + +The current default behavior as of MSVC 1940 is `/permissive`. +As of Visual Studio 2017, `/permissive-` is the default for projects meaning C++ conformance is enforced when +building with MSVC in Visual Studio. + +This MSVC extension can be enabled with ``-fms-reference-binding`` with the clang or cl driver. +This MSVC extension can be enabled with ``/Zc:referenceBinding-`` with the cl driver. +>>>>>>> 43d9c2ac844e (PR Feedback on ext warning) diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 3ac490d30371b1..c87c9d6780b50b 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -1302,6 +1302,7 @@ def MicrosoftStaticAssert : DiagGroup<"microsoft-static-assert">; def MicrosoftInitFromPredefined : DiagGroup<"microsoft-init-from-predefined">; def MicrosoftStringLiteralFromPredefined : DiagGroup< "microsoft-string-literal-from-predefined">; +def MicrosoftReferenceBinding : DiagGroup<"microsoft-reference-binding">; // Aliases. def : DiagGroup<"msvc-include", [MicrosoftInclude]>; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 8020be6c57bcfb..1c2c2583896bb0 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2452,6 +2452,10 @@ def note_explicit_ctor_deduction_guide_here : Note< "explicit %select{constructor|deduction guide}0 declared here">; def note_implicit_deduction_guide : Note<"implicit deduction guide declared as '%0'">; +def ext_ms_lvalue_reference_binding : ExtWarn< + "binding a user-defined type temporary to a non-const lvalue is a " + "Microsoft extension">, InGroup<MicrosoftReferenceBinding>; + // C++11 auto def warn_cxx98_compat_auto_type_specifier : Warning< "'auto' type specifier is incompatible with C++98">, diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index c369a53742772c..e9f86ff552cfd5 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -5331,10 +5331,13 @@ static void TryReferenceInitializationCore(Sema &S, ConvOvlResult); else if (!InitCategory.isLValue()) { if (T1Quals.isAddressSpaceSupersetOf(T2Quals, S.getASTContext())) { - if (!S.getLangOpts().MSVCReferenceBinding || - !S.AllowMSLValueReferenceBinding(T1Quals, T1)) + if (S.AllowMSLValueReferenceBinding(T1Quals, T1)) { + S.Diag(DeclLoc, diag::ext_ms_lvalue_reference_binding) + << Initializer->getSourceRange(); + } else { Sequence.SetFailed(InitializationSequence:: FK_NonConstLValueReferenceBindingToTemporary); + } } else { Sequence.SetFailed( InitializationSequence::FK_ReferenceInitDropsQualifiers); diff --git a/clang/test/SemaCXX/ms-reference-binding.cpp b/clang/test/SemaCXX/ms-reference-binding.cpp index 44e4723fd4fa3a..91e25959a8754b 100644 --- a/clang/test/SemaCXX/ms-reference-binding.cpp +++ b/clang/test/SemaCXX/ms-reference-binding.cpp @@ -1,4 +1,18 @@ -// RUN: %clang_cc1 -fsyntax-only -verify -fms-reference-binding %s +// RUN: %clang_cc1 -fsyntax-only -Wno-microsoft-reference-binding -verify -fms-reference-binding %s +// RUN: %clang_cc1 -DEXTWARN -fsyntax-only -verify -fms-reference-binding %s + +#ifdef EXTWARN + +struct A {}; +void fARef(A&) {} + +void test() { + A& a1 = A(); // expected-warning{{binding a user-defined type temporary to a non-const lvalue is a Microsoft extension}} + + fARef(A()); // expected-warning{{binding a user-defined type temporary to a non-const lvalue is a Microsoft extension}} +} + +#else struct A {}; struct B : A {}; @@ -100,3 +114,5 @@ void test4() { fIntConstArray({ 1 }); NS::fIntConstArray({ 1 }); } + +#endif >From d811e1f806fabaa967a65c9eae2cba9a69ef5bd0 Mon Sep 17 00:00:00 2001 From: MaxEW707 <max.enrico.wink...@gmail.com> Date: Mon, 29 Jul 2024 08:25:39 -0700 Subject: [PATCH 06/15] quoting --- clang/docs/LanguageExtensions.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index e7ba4319a7d8b0..f98c8d61ee237d 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -6035,11 +6035,11 @@ MSVC Reference Binding Please see the `MSDN doc<https://learn.microsoft.com/en-us/cpp/build/reference/zc-referencebinding-enforce-reference-binding-rules>`_ for more information on this non-conforming C++ extension. -MSVC allows user-defined type temporaries to be bound to non-const lvalue references when `/permissive` -or `/Zc:referenceBinding-` are given on the command line. +MSVC allows user-defined type temporaries to be bound to non-const lvalue references when ``/permissive`` +or ``/Zc:referenceBinding-`` are given on the command line. -The current default behavior as of MSVC 1940 is `/permissive`. -As of Visual Studio 2017, `/permissive-` is the default for projects meaning C++ conformance is enforced when +The current default behavior as of MSVC 1940 is ``/permissive``. +As of Visual Studio 2017, ``/permissive-`` is the default for projects meaning C++ conformance is enforced when building with MSVC in Visual Studio. This MSVC extension can be enabled with ``-fms-reference-binding`` with the clang or cl driver. >From 6d87850db848d14e22db5a1a56adbf28ba94e05e Mon Sep 17 00:00:00 2001 From: MaxEW707 <max.enrico.wink...@gmail.com> Date: Mon, 29 Jul 2024 18:57:33 -0700 Subject: [PATCH 07/15] Fix doc build --- clang/docs/LanguageExtensions.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index f98c8d61ee237d..d54c0d7aecebea 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -6033,7 +6033,9 @@ MSVC Reference Binding A& a = A(); -Please see the `MSDN doc<https://learn.microsoft.com/en-us/cpp/build/reference/zc-referencebinding-enforce-reference-binding-rules>`_ for more information on this non-conforming C++ extension. +Please see the `MSDN doc +<https://learn.microsoft.com/en-us/cpp/build/reference/zc-referencebinding-enforce-reference-binding-rules>`_ +for more information on this non-conforming C++ extension. MSVC allows user-defined type temporaries to be bound to non-const lvalue references when ``/permissive`` or ``/Zc:referenceBinding-`` are given on the command line. >From 6e6f7a55df7e1ab76fab4a7eecbb0630822b9036 Mon Sep 17 00:00:00 2001 From: MaxEW707 <max.enrico.wink...@gmail.com> Date: Mon, 29 Jul 2024 21:41:52 -0700 Subject: [PATCH 08/15] Default ms reference binding to on unless C++20 similar to delayed-template-parsing --- clang/lib/Driver/ToolChains/Clang.cpp | 11 ++++++----- clang/lib/Driver/ToolChains/MSVC.cpp | 1 + clang/test/Driver/cl-permissive.c | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 3d6d170aee4f34..75af8cfe887fac 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -7215,11 +7215,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, IsWindowsMSVC)) CmdArgs.push_back("-fms-extensions"); - // -fno-ms-reference-binding is the default. - if (Args.hasFlag(options::OPT_fms_reference_binding, - options::OPT_fno_ms_reference_binding, false)) - CmdArgs.push_back("-fms-reference-binding"); - // -fms-compatibility=0 is default. bool IsMSVCCompat = Args.hasFlag( options::OPT_fms_compatibility, options::OPT_fno_ms_compatibility, @@ -7386,6 +7381,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fdelayed-template-parsing"); } + // -fno-ms-reference-binding is the default. + if (Args.hasFlag(options::OPT_fms_reference_binding, + options::OPT_fno_ms_reference_binding, + IsWindowsMSVC && !HaveCxx20)) + CmdArgs.push_back("-fms-reference-binding"); + if (Args.hasFlag(options::OPT_fpch_validate_input_files_content, options::OPT_fno_pch_validate_input_files_content, false)) CmdArgs.push_back("-fvalidate-ast-input-files-content"); diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp index 28731fdae50285..8aca222807e2e2 100644 --- a/clang/lib/Driver/ToolChains/MSVC.cpp +++ b/clang/lib/Driver/ToolChains/MSVC.cpp @@ -954,6 +954,7 @@ static void TranslatePermissiveMinus(Arg *A, llvm::opt::DerivedArgList &DAL, const OptTable &Opts) { DAL.AddFlagArg(A, Opts.getOption(options::OPT__SLASH_Zc_twoPhase)); DAL.AddFlagArg(A, Opts.getOption(options::OPT_foperator_names)); + DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_ms_reference_binding)); } llvm::opt::DerivedArgList * diff --git a/clang/test/Driver/cl-permissive.c b/clang/test/Driver/cl-permissive.c index 712bef71a43af1..e325fc02d0d50a 100644 --- a/clang/test/Driver/cl-permissive.c +++ b/clang/test/Driver/cl-permissive.c @@ -3,8 +3,8 @@ // RUN: %clang_cl /permissive -### -- %s 2>&1 | FileCheck -check-prefix=PERMISSIVE %s // PERMISSIVE: "-fno-operator-names" -// PERMISSIVE: "-fms-reference-binding" // PERMISSIVE: "-fdelayed-template-parsing" +// PERMISSIVE: "-fms-reference-binding" // RUN: %clang_cl /permissive- -### -- %s 2>&1 | FileCheck -check-prefix=PERMISSIVE-MINUS %s // PERMISSIVE-MINUS-NOT: "-fno-operator-names" // PERMISSIVE-MINUS-NOT: "-fms-reference-binding" >From c85ecb5a20ac4350fcac3274cd5eeb7eb65032de Mon Sep 17 00:00:00 2001 From: MaxEW707 <max.enrico.wink...@gmail.com> Date: Tue, 30 Jul 2024 20:07:47 -0700 Subject: [PATCH 09/15] remove old comment --- clang/lib/Driver/ToolChains/Clang.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 75af8cfe887fac..f1f530c6c33a64 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -7381,7 +7381,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fdelayed-template-parsing"); } - // -fno-ms-reference-binding is the default. if (Args.hasFlag(options::OPT_fms_reference_binding, options::OPT_fno_ms_reference_binding, IsWindowsMSVC && !HaveCxx20)) >From 18cde6dcbbe67c5afba9642340ffaa9126540ab8 Mon Sep 17 00:00:00 2001 From: MaxEW707 <max.enrico.wink...@gmail.com> Date: Wed, 31 Jul 2024 21:26:29 -0700 Subject: [PATCH 10/15] Fix overload resolution and only consider msvc binding if we are an rvalue --- clang/lib/Sema/SemaOverload.cpp | 32 ++++++++++++++--- .../test/CodeGenCXX/ms-reference-binding.cpp | 30 ++++++++++++++++ clang/test/SemaCXX/ms-reference-binding.cpp | 35 ++++++++++++++++++- 3 files changed, 91 insertions(+), 6 deletions(-) create mode 100644 clang/test/CodeGenCXX/ms-reference-binding.cpp diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index f2c7906ae45088..003fc860c125ff 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -4552,6 +4552,24 @@ CompareStandardConversionSequences(Sema &S, SourceLocation Loc, T1 = S.Context.getQualifiedType(UnqualT1, T1Quals); if (isa<ArrayType>(T2) && T2Quals) T2 = S.Context.getQualifiedType(UnqualT2, T2Quals); + + if (S.getLangOpts().MSVCReferenceBinding && + S.Context.hasSameType(SCS1.getFromType(), SCS2.getFromType()) && + !SCS1.getFromType().hasQualifiers() && SCS1.BindsToRvalue && + SCS2.BindsToRvalue) { + + // When binding a user-defined type temporary to an lvalue MSVC will + // pick `const T&` over `T&` when binding an unqualified `T&&`. + // Therefore we want to pick the more qualified const overload in this + // specific case. + if (!T2.hasQualifiers() && + (T1.isConstQualified() && !T1.isVolatileQualified())) + return ImplicitConversionSequence::Better; + if (!T1.hasQualifiers() && + (T2.isConstQualified() && !T2.isVolatileQualified())) + return ImplicitConversionSequence::Worse; + } + if (T2.isMoreQualifiedThan(T1, S.getASTContext())) return ImplicitConversionSequence::Better; if (T1.isMoreQualifiedThan(T2, S.getASTContext())) @@ -5250,11 +5268,15 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType, // -- Otherwise, the reference shall be an lvalue reference to a // non-volatile const type (i.e., cv1 shall be const), or the reference // shall be an rvalue reference. - if (!isRValRef && (!T1.isConstQualified() || T1.isVolatileQualified()) && - !S.AllowMSLValueReferenceBinding(T1.getQualifiers(), T1)) { - if (InitCategory.isRValue() && RefRelationship != Sema::Ref_Incompatible) - ICS.setBad(BadConversionSequence::lvalue_ref_to_rvalue, Init, DeclType); - return ICS; + if (!isRValRef && (!T1.isConstQualified() || T1.isVolatileQualified())) { + if (InitCategory.isRValue() && RefRelationship != Sema::Ref_Incompatible) { + if (!S.AllowMSLValueReferenceBinding(T1.getQualifiers(), T1)) { + ICS.setBad(BadConversionSequence::lvalue_ref_to_rvalue, Init, DeclType); + return ICS; + } + } else { + return ICS; + } } // -- If the initializer expression diff --git a/clang/test/CodeGenCXX/ms-reference-binding.cpp b/clang/test/CodeGenCXX/ms-reference-binding.cpp new file mode 100644 index 00000000000000..6f8ca371914222 --- /dev/null +++ b/clang/test/CodeGenCXX/ms-reference-binding.cpp @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 -triple x86_64-windows-msvc %s -emit-llvm -fms-extensions -fms-compatibility -fms-reference-binding -o - | FileCheck %s + +struct A {}; +struct B : A {}; + +void fAPickConstRef(A&) {} +void fAPickConstRef(const A&) {} + +void fBPickConstRef(A&) {} +void fBPickConstRef(const A&) {} + +void fAPickRef(A&) {} +void fAPickRef(const volatile A&) {} + +void fAPickRef2(A&) {} +void fAPickRef2(const volatile A&) {} + +void test() { + fAPickConstRef(A()); + // CHECK: call {{.*}} @"?fAPickConstRef@@YAXAEBUA@@@Z" + + fBPickConstRef(B()); + // CHECK: call {{.*}} @"?fBPickConstRef@@YAXAEBUA@@@Z" + + fAPickRef(A()); + // CHECK: call {{.*}} @"?fAPickRef@@YAXAEAUA@@@Z" + + fAPickRef2(A()); + // CHECK: call {{.*}} @"?fAPickRef2@@YAXAEAUA@@@Z" +} diff --git a/clang/test/SemaCXX/ms-reference-binding.cpp b/clang/test/SemaCXX/ms-reference-binding.cpp index 91e25959a8754b..27201ef2bf63b7 100644 --- a/clang/test/SemaCXX/ms-reference-binding.cpp +++ b/clang/test/SemaCXX/ms-reference-binding.cpp @@ -6,12 +6,28 @@ struct A {}; void fARef(A&) {} -void test() { +void test1() { A& a1 = A(); // expected-warning{{binding a user-defined type temporary to a non-const lvalue is a Microsoft extension}} fARef(A()); // expected-warning{{binding a user-defined type temporary to a non-const lvalue is a Microsoft extension}} } +void fARefDoNotWarn(A&) {} +void fARefDoNotWarn(const A&) {} + +// expected-note@+2 {{candidate function not viable: 1st argument ('const A') would lose const qualifier}} +// expected-note@+1 {{candidate function not viable: 1st argument ('const A') would lose const qualifier}} +void fARefLoseConstQualifier(A&) {} + +void test2() { + // This should not warn since `fARef2(const A&)` is a better candidate + fARefDoNotWarn(A()); + + const A a; + fARefLoseConstQualifier(a); // expected-error{{no matching function for call to 'fARefLoseConstQualifier'}} + fARefLoseConstQualifier(static_cast<const A&&>(a)); // expected-error{{no matching function for call to 'fARefLoseConstQualifier'}} +} + #else struct A {}; @@ -22,8 +38,13 @@ A fA(); A&& fARvalueRef(); A(&&fARvalueRefArray())[1]; + void fARef(A&) {} +// expected-note@+2 {{candidate function not viable: expects an lvalue for 1st argument}} +// expected-note@+1 {{candidate function not viable: expects an lvalue for 1st argument}} +void fAVolatileRef(volatile A&) {} + void fIntRef(int&) {} // expected-note{{candidate function not viable: expects an lvalue for 1st argument}} void fDoubleRef(double&) {} // expected-note{{candidate function not viable: expects an lvalue for 1st argument}} @@ -36,6 +57,10 @@ void fIntConstArray(const int (&)[1]); namespace NS { void fARef(A&) {} + // expected-note@+2 {{passing argument to parameter here}} + // expected-note@+1 {{passing argument to parameter here}} + void fAVolatileRef(volatile A&) {} + void fIntRef(int&) {} // expected-note{{passing argument to parameter here}} void fDoubleRef(double&) {} // expected-note{{passing argument to parameter here}} @@ -87,10 +112,18 @@ void test3() { fARef(A()); fARef(static_cast<A&&>(a1)); + + fAVolatileRef(A()); // expected-error{{no matching function for call to 'fAVolatileRef'}} + fAVolatileRef(static_cast<A&&>(a1)); // expected-error{{no matching function for call to 'fAVolatileRef'}} + fARef(B()); NS::fARef(A()); NS::fARef(static_cast<A&&>(a1)); + + NS::fAVolatileRef(A()); // expected-error{{volatile lvalue reference to type 'volatile A' cannot bind to a temporary of type 'A'}} + NS::fAVolatileRef(static_cast<A&&>(a1)); // expected-error{{volatile lvalue reference to type 'volatile A' cannot bind to a temporary of type 'A'}} + NS::fARef(B()); A& a2 = fA(); >From a9db45696c9ed2bdff860993211b7769117c0c4e Mon Sep 17 00:00:00 2001 From: MaxEW707 <max.enrico.wink...@gmail.com> Date: Wed, 31 Jul 2024 21:30:08 -0700 Subject: [PATCH 11/15] fix comment --- clang/test/SemaCXX/ms-reference-binding.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/SemaCXX/ms-reference-binding.cpp b/clang/test/SemaCXX/ms-reference-binding.cpp index 27201ef2bf63b7..9b774c2d4989ee 100644 --- a/clang/test/SemaCXX/ms-reference-binding.cpp +++ b/clang/test/SemaCXX/ms-reference-binding.cpp @@ -20,7 +20,7 @@ void fARefDoNotWarn(const A&) {} void fARefLoseConstQualifier(A&) {} void test2() { - // This should not warn since `fARef2(const A&)` is a better candidate + // This should not warn since `fARefDoNotWarn(const A&)` is a better candidate fARefDoNotWarn(A()); const A a; >From b9c5b8d92db505c00c564cdfbc468fd57b01a235 Mon Sep 17 00:00:00 2001 From: MaxEW707 <max.enrico.wink...@gmail.com> Date: Thu, 1 Aug 2024 00:09:52 -0700 Subject: [PATCH 12/15] Fix CXX method functions --- clang/lib/Sema/SemaOverload.cpp | 4 +- .../test/CodeGenCXX/ms-reference-binding.cpp | 52 ++++++++++++++++++- 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 003fc860c125ff..c7d5f7b77a2b3c 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -4556,7 +4556,9 @@ CompareStandardConversionSequences(Sema &S, SourceLocation Loc, if (S.getLangOpts().MSVCReferenceBinding && S.Context.hasSameType(SCS1.getFromType(), SCS2.getFromType()) && !SCS1.getFromType().hasQualifiers() && SCS1.BindsToRvalue && - SCS2.BindsToRvalue) { + SCS2.BindsToRvalue && + !SCS1.BindsImplicitObjectArgumentWithoutRefQualifier && + !SCS2.BindsImplicitObjectArgumentWithoutRefQualifier) { // When binding a user-defined type temporary to an lvalue MSVC will // pick `const T&` over `T&` when binding an unqualified `T&&`. diff --git a/clang/test/CodeGenCXX/ms-reference-binding.cpp b/clang/test/CodeGenCXX/ms-reference-binding.cpp index 6f8ca371914222..bca13f24dc918c 100644 --- a/clang/test/CodeGenCXX/ms-reference-binding.cpp +++ b/clang/test/CodeGenCXX/ms-reference-binding.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -triple x86_64-windows-msvc %s -emit-llvm -fms-extensions -fms-compatibility -fms-reference-binding -o - | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-windows-msvc %s -emit-llvm -fms-extensions -fms-compatibility -fms-reference-binding -Wno-microsoft-reference-binding -o - | FileCheck %s struct A {}; struct B : A {}; @@ -15,6 +15,31 @@ void fAPickRef(const volatile A&) {} void fAPickRef2(A&) {} void fAPickRef2(const volatile A&) {} +namespace NS { + void fAPickConstRef(A&) {} + void fAPickConstRef(const A&) {} + + void fBPickConstRef(A&) {} + void fBPickConstRef(const A&) {} + + void fAPickRef(A&) {} + void fAPickRef(const volatile A&) {} + + void fAPickRef2(A&) {} + void fAPickRef2(const volatile A&) {} +} + +struct S { + void memberPickNonConst() {} + void memberPickNonConst() const {} + + void memberPickConstRef() const & {} + void memberPickConstRef() & {} + + static void fAPickConstRef(A&) {} + static void fAPickConstRef(const A&) {} +}; + void test() { fAPickConstRef(A()); // CHECK: call {{.*}} @"?fAPickConstRef@@YAXAEBUA@@@Z" @@ -27,4 +52,29 @@ void test() { fAPickRef2(A()); // CHECK: call {{.*}} @"?fAPickRef2@@YAXAEAUA@@@Z" + + NS::fAPickConstRef(A()); + // CHECK: call {{.*}} @"?fAPickConstRef@NS@@YAXAEBUA@@@Z" + + NS::fBPickConstRef(B()); + // CHECK: call {{.*}} @"?fBPickConstRef@NS@@YAXAEBUA@@@Z" + + NS::fAPickRef(A()); + // CHECK: call {{.*}} @"?fAPickRef@NS@@YAXAEAUA@@@Z" + + NS::fAPickRef2(A()); + // CHECK: call {{.*}} @"?fAPickRef2@NS@@YAXAEAUA@@@Z" + + S::fAPickConstRef(A()); + // CHECK: call {{.*}} @"?fAPickConstRef@S@@SAXAEBUA@@@Z" +} + +void test_member_call() { + S s; + + static_cast<S&&>(s).memberPickNonConst(); + // CHECK: call {{.*}} @"?memberPickNonConst@S@@QEAAXXZ" + + static_cast<S&&>(s).memberPickConstRef(); + // CHECK: call {{.*}} @"?memberPickConstRef@S@@QEGBAXXZ" } >From 71babd19c214d01fcd299ae7a63c7629170fdd78 Mon Sep 17 00:00:00 2001 From: MaxEW707 <max.enrico.wink...@gmail.com> Date: Mon, 2 Dec 2024 22:46:08 -0800 Subject: [PATCH 13/15] Disable reference binding by default and fix options comments --- clang/include/clang/Driver/Options.td | 8 +++++--- clang/lib/Driver/ToolChains/Clang.cpp | 2 +- clang/lib/Driver/ToolChains/MSVC.cpp | 1 - clang/test/Driver/cl-permissive.c | 1 - clang/test/Driver/cl-zc.cpp | 2 ++ 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 4f963a18297ee7..64599a7559c8d6 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -3098,7 +3098,8 @@ def fms_extensions : Flag<["-"], "fms-extensions">, Group<f_Group>, MarshallingInfoFlag<LangOpts<"MicrosoftExt">>, ImpliedByAnyOf<[fms_compatibility.KeyPath]>; def fms_reference_binding : Flag<["-"], "fms-reference-binding">, Group<f_Group>, Visibility<[ClangOption, CC1Option, CLOption]>, - HelpText<"Accept expressions that bind a non-const lvalue reference to a user-defined type temporary as supported by the Microsoft Compiler">, + HelpText<"Accept expressions that bind a non-const lvalue reference to a " + "user-defined type temporary as supported by the Microsoft compiler">, MarshallingInfoFlag<LangOpts<"MSVCReferenceBinding">>; def fno_ms_reference_binding : Flag<["-"], "fno-ms-reference-binding">, Group<f_Group>, Visibility<[ClangOption, CLOption]>; @@ -8690,10 +8691,11 @@ def _SLASH_Zc_wchar_t : CLFlag<"Zc:wchar_t">, def _SLASH_Zc_wchar_t_ : CLFlag<"Zc:wchar_t-">, HelpText<"Disable C++ builtin type wchar_t">; def _SLASH_Zc_referenceBinding : CLFlag<"Zc:referenceBinding">, - HelpText<"Do not accept expressions that bind a non-const lvalue reference to a user-defined type temporary">, + HelpText<"Do not accept expressions that bind a non-const lvalue reference to a user-defined type temporary (default)">, Alias<fno_ms_reference_binding>; def _SLASH_Zc_referenceBinding_ : CLFlag<"Zc:referenceBinding-">, - HelpText<"Accept expressions that bind a non-const lvalue reference to a user-defined type temporary">, + HelpText<"Accept expressions that bind a non-const lvalue reference to a " + "user-defined type temporary">, Alias<fms_reference_binding>; def _SLASH_Z7 : CLFlag<"Z7">, Alias<g_Flag>, HelpText<"Enable CodeView debug information in object files">; diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index f1f530c6c33a64..61642071ea3d94 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -7383,7 +7383,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasFlag(options::OPT_fms_reference_binding, options::OPT_fno_ms_reference_binding, - IsWindowsMSVC && !HaveCxx20)) + false)) CmdArgs.push_back("-fms-reference-binding"); if (Args.hasFlag(options::OPT_fpch_validate_input_files_content, diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp index 8aca222807e2e2..e3a0434e648fae 100644 --- a/clang/lib/Driver/ToolChains/MSVC.cpp +++ b/clang/lib/Driver/ToolChains/MSVC.cpp @@ -947,7 +947,6 @@ static void TranslatePermissive(Arg *A, llvm::opt::DerivedArgList &DAL, const OptTable &Opts) { DAL.AddFlagArg(A, Opts.getOption(options::OPT__SLASH_Zc_twoPhase_)); DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_operator_names)); - DAL.AddFlagArg(A, Opts.getOption(options::OPT_fms_reference_binding)); } static void TranslatePermissiveMinus(Arg *A, llvm::opt::DerivedArgList &DAL, diff --git a/clang/test/Driver/cl-permissive.c b/clang/test/Driver/cl-permissive.c index e325fc02d0d50a..b70a98d3564231 100644 --- a/clang/test/Driver/cl-permissive.c +++ b/clang/test/Driver/cl-permissive.c @@ -4,7 +4,6 @@ // RUN: %clang_cl /permissive -### -- %s 2>&1 | FileCheck -check-prefix=PERMISSIVE %s // PERMISSIVE: "-fno-operator-names" // PERMISSIVE: "-fdelayed-template-parsing" -// PERMISSIVE: "-fms-reference-binding" // RUN: %clang_cl /permissive- -### -- %s 2>&1 | FileCheck -check-prefix=PERMISSIVE-MINUS %s // PERMISSIVE-MINUS-NOT: "-fno-operator-names" // PERMISSIVE-MINUS-NOT: "-fms-reference-binding" diff --git a/clang/test/Driver/cl-zc.cpp b/clang/test/Driver/cl-zc.cpp index d2c27975dd6591..e6b885c4bde7ff 100644 --- a/clang/test/Driver/cl-zc.cpp +++ b/clang/test/Driver/cl-zc.cpp @@ -127,6 +127,8 @@ // RUN: %clang_cl -c -### /Zc:referenceBinding- -- %s 2>&1 | FileCheck -check-prefix CHECK-REFERENCE_BINDING_ %s // CHECK-REFERENCE_BINDING_: "-fms-reference-binding" +// RUN: %clang_cl -c -### /Zc:referenceBinding -- %s 2>&1 | FileCheck -check-prefix CHECK-REFERENCE_BINDING %s +// CHECK-REFERENCE_BINDING-NOT: "-fms-reference-binding" // These never warn, but don't have an effect yet. >From 9ceb05b38efe57c1bb3ea3f708839f599efb4c24 Mon Sep 17 00:00:00 2001 From: MaxEW707 <max.enrico.wink...@gmail.com> Date: Sun, 8 Dec 2024 22:23:26 -0800 Subject: [PATCH 14/15] Fix inorder spelling --- clang/docs/LanguageExtensions.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index d54c0d7aecebea..78d52243da3248 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -6020,7 +6020,7 @@ types. MSVC Extensions =============== -Clang supports a number of extensions inorder to imitate MSVC. +Clang supports a number of extensions in order to imitate MSVC. Some of these extensions are behind ``-fms-compatibility`` and ``-fms-extensions`` which are further described in :doc:`MSVCCompatibility`. @@ -6040,9 +6040,9 @@ for more information on this non-conforming C++ extension. MSVC allows user-defined type temporaries to be bound to non-const lvalue references when ``/permissive`` or ``/Zc:referenceBinding-`` are given on the command line. -The current default behavior as of MSVC 1940 is ``/permissive``. -As of Visual Studio 2017, ``/permissive-`` is the default for projects meaning C++ conformance is enforced when -building with MSVC in Visual Studio. +The current default behavior as of MSVC 1942 is ``/permissive``. +As of Visual Studio 2017, ``/permissive-`` is the default for newly generated projects in Visual Studio meaning C++ +conformance is enforced when building with MSVC in Visual Studio. This MSVC extension can be enabled with ``-fms-reference-binding`` with the clang or cl driver. This MSVC extension can be enabled with ``/Zc:referenceBinding-`` with the cl driver. >From 4a0c669a618f75013fc791d69b11edf51e6d9053 Mon Sep 17 00:00:00 2001 From: MaxEW707 <max.enrico.wink...@gmail.com> Date: Mon, 9 Dec 2024 17:01:49 -0800 Subject: [PATCH 15/15] cl -> clang-cl --- clang/docs/LanguageExtensions.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index 78d52243da3248..5f032817510113 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -6044,6 +6044,6 @@ The current default behavior as of MSVC 1942 is ``/permissive``. As of Visual Studio 2017, ``/permissive-`` is the default for newly generated projects in Visual Studio meaning C++ conformance is enforced when building with MSVC in Visual Studio. -This MSVC extension can be enabled with ``-fms-reference-binding`` with the clang or cl driver. -This MSVC extension can be enabled with ``/Zc:referenceBinding-`` with the cl driver. +This MSVC extension can be enabled with ``-fms-reference-binding`` with the clang or clang-cl driver. +This MSVC extension can be enabled with ``/Zc:referenceBinding-`` with the clang-cl driver. >>>>>>> 43d9c2ac844e (PR Feedback on ext warning) _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits