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/21] 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/21] 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/21] 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/21] 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/21] 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/21] 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/21] 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/21] 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/21] 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/21] 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/21] 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/21] 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/21] 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/21] 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/21] 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)

>From 08227eab44b24d343eb47084034558e7459ea990 Mon Sep 17 00:00:00 2001
From: MaxEW707 <max.enrico.wink...@gmail.com>
Date: Tue, 10 Dec 2024 17:25:12 -0800
Subject: [PATCH 16/21] Add unit tests for default arguments

---
 clang/test/SemaCXX/ms-reference-binding.cpp | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/clang/test/SemaCXX/ms-reference-binding.cpp 
b/clang/test/SemaCXX/ms-reference-binding.cpp
index 9b774c2d4989ee..c8ba7fb0564d03 100644
--- a/clang/test/SemaCXX/ms-reference-binding.cpp
+++ b/clang/test/SemaCXX/ms-reference-binding.cpp
@@ -33,6 +33,9 @@ void test2() {
 struct A {};
 struct B : A {};
 
+void fADefaultArgRef(A& = A{});
+void fBDefaultArgRef(A& = B{});
+
 B fB();
 A fA();
 
@@ -148,4 +151,13 @@ void test4() {
   NS::fIntConstArray({ 1 });
 }
 
+void test5() {
+  fADefaultArgRef();
+  fADefaultArgRef(A());
+
+  fBDefaultArgRef();
+  fBDefaultArgRef(B());
+  fBDefaultArgRef(A());
+}
+
 #endif

>From 2d72da07daad75139a07cc8d5eeee1e6e12697a6 Mon Sep 17 00:00:00 2001
From: MaxEW707 <max.enrico.wink...@gmail.com>
Date: Tue, 10 Dec 2024 17:29:45 -0800
Subject: [PATCH 17/21] Add another default arg unit test

---
 clang/test/SemaCXX/ms-reference-binding.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/clang/test/SemaCXX/ms-reference-binding.cpp 
b/clang/test/SemaCXX/ms-reference-binding.cpp
index c8ba7fb0564d03..a9231324876e7c 100644
--- a/clang/test/SemaCXX/ms-reference-binding.cpp
+++ b/clang/test/SemaCXX/ms-reference-binding.cpp
@@ -42,6 +42,8 @@ A fA();
 A&& fARvalueRef();
 A(&&fARvalueRefArray())[1];
 
+void fADefaultArgRef2(A& = fARvalueRef());
+
 void fARef(A&) {}
 
 // expected-note@+2 {{candidate function not viable: expects an lvalue for 1st 
argument}}

>From d8da7651b5b426db91c583651d2eec9514c7065f Mon Sep 17 00:00:00 2001
From: MaxEW707 <max.enrico.wink...@gmail.com>
Date: Tue, 10 Dec 2024 17:44:54 -0800
Subject: [PATCH 18/21] Convert to addOptInFlag

---
 clang/lib/Driver/ToolChains/Clang.cpp | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/clang/lib/Driver/ToolChains/Clang.cpp 
b/clang/lib/Driver/ToolChains/Clang.cpp
index 61642071ea3d94..c7e6617e0b97a6 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -7381,10 +7381,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction 
&JA,
     CmdArgs.push_back("-fdelayed-template-parsing");
   }
 
-  if (Args.hasFlag(options::OPT_fms_reference_binding,
-                   options::OPT_fno_ms_reference_binding,
-                   false))
-    CmdArgs.push_back("-fms-reference-binding");
+  Args.addOptInFlag(CmdArgs, options::OPT_fms_reference_binding,
+                    options::OPT_fno_ms_reference_binding);
 
   if (Args.hasFlag(options::OPT_fpch_validate_input_files_content,
                    options::OPT_fno_pch_validate_input_files_content, false))

>From a0c36f83fa64576230e166446180d82ca3377b39 Mon Sep 17 00:00:00 2001
From: MaxEW707 <max.enrico.wink...@gmail.com>
Date: Tue, 10 Dec 2024 19:32:04 -0800
Subject: [PATCH 19/21] Typedef lvalue ref tests

---
 clang/test/SemaCXX/ms-reference-binding.cpp | 26 +++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/clang/test/SemaCXX/ms-reference-binding.cpp 
b/clang/test/SemaCXX/ms-reference-binding.cpp
index a9231324876e7c..6207c716917468 100644
--- a/clang/test/SemaCXX/ms-reference-binding.cpp
+++ b/clang/test/SemaCXX/ms-reference-binding.cpp
@@ -33,9 +33,13 @@ void test2() {
 struct A {};
 struct B : A {};
 
+typedef A AAlias;
+
 void fADefaultArgRef(A& = A{});
 void fBDefaultArgRef(A& = B{});
 
+void fAAliasDefaultArgRef(AAlias& = AAlias{});
+
 B fB();
 A fA();
 
@@ -45,6 +49,7 @@ A(&&fARvalueRefArray())[1];
 void fADefaultArgRef2(A& = fARvalueRef());
 
 void fARef(A&) {}
+void fAAliasRef(AAlias&) {}
 
 // 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}}
@@ -61,6 +66,7 @@ void fIntConstArray(const int (&)[1]);
 
 namespace NS {
   void fARef(A&) {}
+  void fAAliasRef(AAlias&) {}
 
   // expected-note@+2 {{passing argument to parameter here}}
   // expected-note@+1 {{passing argument to parameter here}}
@@ -114,29 +120,45 @@ void test2() {
 
 void test3() {
   A& a1 = A();
+  AAlias& aalias1 = A();
 
   fARef(A());
   fARef(static_cast<A&&>(a1));
 
+  fAAliasRef(A());
+  fAAliasRef(static_cast<A&&>(a1));
+  fAAliasRef(AAlias());
+  fAAliasRef(static_cast<AAlias&&>(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());
+  fAAliasRef(B());
 
   NS::fARef(A());
   NS::fARef(static_cast<A&&>(a1));
 
+  NS::fAAliasRef(A());
+  NS::fAAliasRef(static_cast<A&&>(a1));
+  NS::fAAliasRef(AAlias());
+  NS::fAAliasRef(static_cast<AAlias&&>(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());
+  NS::fAAliasRef(B());
 
   A& a2 = fA();
+  AAlias& aalias2 = fA();
 
   A& a3 = fARvalueRef();
+  AAlias& aalias3 = fARvalueRef();
 
   const A& rca = fB();
   A& ra = fB();
+  AAlias& raalias = fB();
 }
 
 void test4() {
@@ -160,6 +182,10 @@ void test5() {
   fBDefaultArgRef();
   fBDefaultArgRef(B());
   fBDefaultArgRef(A());
+
+  fAAliasDefaultArgRef(A());
+  fAAliasDefaultArgRef(B());
+  fAAliasDefaultArgRef(AAlias());
 }
 
 #endif

>From ffe5bd4de6f6184616064b94f383419591e5c12c Mon Sep 17 00:00:00 2001
From: MaxEW707 <max.enrico.wink...@gmail.com>
Date: Wed, 11 Dec 2024 23:49:32 -0800
Subject: [PATCH 20/21] Add ref related derived to base cv binding test

---
 .../test/CodeGenCXX/ms-reference-binding.cpp  | 23 ++++++++++++-------
 1 file changed, 15 insertions(+), 8 deletions(-)

diff --git a/clang/test/CodeGenCXX/ms-reference-binding.cpp 
b/clang/test/CodeGenCXX/ms-reference-binding.cpp
index bca13f24dc918c..c4a4067b5f34fb 100644
--- a/clang/test/CodeGenCXX/ms-reference-binding.cpp
+++ b/clang/test/CodeGenCXX/ms-reference-binding.cpp
@@ -12,8 +12,14 @@ void fBPickConstRef(const A&) {}
 void fAPickRef(A&) {}
 void fAPickRef(const volatile A&) {}
 
-void fAPickRef2(A&) {}
-void fAPickRef2(const volatile A&) {}
+// NOTE: MSVC incorrectly picks the `const volatile A&` overload with the 
mangled name
+// "?fBPickConstVolatileRef@@YAXAEDUA@@@Z" when converting a derived class `B` 
to base `A`.
+// This occurs even with conforming reference binding enabled so this isn't a 
one off
+// behaviour with non-conforming MSVC specific reference binding but appears 
to be a bug.
+// A bug report has been submitted to MSVC. This bug has been verified upto 
MSVC 19.40.
+// We are not emulating this behaviour and instead will pick the `A&` overload 
as intended.
+void fBPickConstVolatileRef(A&) {}
+void fBPickConstVolatileRef(const volatile A&) {}
 
 namespace NS {
   void fAPickConstRef(A&) {}
@@ -25,8 +31,9 @@ namespace NS {
   void fAPickRef(A&) {}
   void fAPickRef(const volatile A&) {}
 
-  void fAPickRef2(A&) {}
-  void fAPickRef2(const volatile A&) {}
+  // See the above note above the global `fBPickConstVolatileRef`
+  void fBPickConstVolatileRef(A&) {}
+  void fBPickConstVolatileRef(const volatile A&) {}
 }
 
 struct S {
@@ -50,8 +57,8 @@ void test() {
   fAPickRef(A());
   // CHECK: call {{.*}} @"?fAPickRef@@YAXAEAUA@@@Z"
 
-  fAPickRef2(A());
-  // CHECK: call {{.*}} @"?fAPickRef2@@YAXAEAUA@@@Z"
+  fBPickConstVolatileRef(B());
+  // CHECK: call {{.*}} @"?fBPickConstVolatileRef@@YAXAEAUA@@@Z"
 
   NS::fAPickConstRef(A());
   // CHECK: call {{.*}} @"?fAPickConstRef@NS@@YAXAEBUA@@@Z"
@@ -62,8 +69,8 @@ void test() {
   NS::fAPickRef(A());
   // CHECK: call {{.*}} @"?fAPickRef@NS@@YAXAEAUA@@@Z"
 
-  NS::fAPickRef2(A());
-  // CHECK: call {{.*}} @"?fAPickRef2@NS@@YAXAEAUA@@@Z"
+  NS::fBPickConstVolatileRef(B());
+  // CHECK: call {{.*}} @"?fBPickConstVolatileRef@NS@@YAXAEAUA@@@Z"
 
   S::fAPickConstRef(A());
   // CHECK: call {{.*}} @"?fAPickConstRef@S@@SAXAEBUA@@@Z"

>From b7754e9288bbd9c8f1824512d120e48519a6fe0b Mon Sep 17 00:00:00 2001
From: MaxEW707 <max.enrico.wink...@gmail.com>
Date: Thu, 12 Dec 2024 23:53:25 -0800
Subject: [PATCH 21/21] Add conversion and temporary materialization unit
 tests; enforece variable non-const lvalue reference init doesn't consider ref
 incompatible relationships

---
 clang/lib/Sema/SemaInit.cpp                 |  3 +-
 clang/test/SemaCXX/ms-reference-binding.cpp | 34 +++++++++++++++++++++
 2 files changed, 36 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index e9f86ff552cfd5..2729dae4792ccc 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -5331,7 +5331,8 @@ static void TryReferenceInitializationCore(Sema &S,
                                   ConvOvlResult);
     else if (!InitCategory.isLValue()) {
       if (T1Quals.isAddressSpaceSupersetOf(T2Quals, S.getASTContext())) {
-        if (S.AllowMSLValueReferenceBinding(T1Quals, T1)) {
+        if (S.AllowMSLValueReferenceBinding(T1Quals, T1) &&
+            RefRelationship != Sema::Ref_Incompatible) {
           S.Diag(DeclLoc, diag::ext_ms_lvalue_reference_binding)
               << Initializer->getSourceRange();
         } else {
diff --git a/clang/test/SemaCXX/ms-reference-binding.cpp 
b/clang/test/SemaCXX/ms-reference-binding.cpp
index 6207c716917468..0e180bd157c25d 100644
--- a/clang/test/SemaCXX/ms-reference-binding.cpp
+++ b/clang/test/SemaCXX/ms-reference-binding.cpp
@@ -188,4 +188,38 @@ void test5() {
   fAAliasDefaultArgRef(AAlias());
 }
 
+struct C { operator A() { return A(); } };
+struct D { D(int) {} };
+
+// expected-note@+1 {{candidate function not viable: no known conversion from 
'C' to 'A &' for 1st argument}}
+void fARefConvOperator(A&);
+
+// expected-note@+1 {{candidate function not viable: no known conversion from 
'int' to 'D &' for 1st argument}}
+void fDRefTemp(D&);
+
+void fAConstRefConvOperator(const A&);
+void fDConstRefTemp(const D&);
+
+void test6() {
+  fARefConvOperator(C()); // expected-error{{no matching function for call to 
'fARefConvOperator'}}
+  fDRefTemp(1); // expected-error{{no matching function for call to 
'fDRefTemp'}}
+
+  fAConstRefConvOperator(C());
+  fDConstRefTemp(1);
+
+  const A& cARef = C();
+  A& ARef = C(); // expected-error{{non-const lvalue reference to type 'A' 
cannot bind to a temporary of type 'C'}}
+
+  const D& cDRef = 1;
+  D& DRef = 1; // expected-error{{non-const lvalue reference to type 'D' 
cannot bind to a temporary of type 'int'}}
+}
+
+A& retARef();
+struct E { operator A&() { return retARef(); } };
+
+void test7() {
+  const A& cARef = E();
+  A& ARef = E();
+}
+
 #endif

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to