@@ -129,51 +129,120 @@ findFirstParentInfo(
129129 }
130130}
131131
132+ template <bool isInner>
132133bool
133- isDecayedEqual (
134+ isDecayedEqualImpl (
134135 Polymorphic<TypeInfo> const & lhs,
135136 Polymorphic<TypeInfo> const & rhs)
136137{
137- // When comparing two parameters, we need to compare
138- // them as if they are decayed at the top level
139- // the same way function parameters are decayed to
140- // consider if they redefine an overload.
141- if (lhs == rhs)
138+ // Polymorphic
139+ MRDOCS_CHECK_OR (static_cast <bool >(lhs) == static_cast <bool >(rhs), false );
140+ MRDOCS_CHECK_OR (static_cast <bool >(lhs) && static_cast <bool >(rhs), true );
141+ // TypeInfo
142+ bool const decayToPointer = !isInner && (lhs->isArray () || rhs->isArray ());
143+ if (!decayToPointer)
144+ {
145+ MRDOCS_CHECK_OR (lhs->Kind == rhs->Kind , false );
146+ }
147+ else
142148 {
143- return true ;
149+ // in root types, arrays are decayed to pointers
150+ MRDOCS_CHECK_OR (lhs->isArray () || lhs->isPointer (), false );
151+ MRDOCS_CHECK_OR (rhs->isArray () || rhs->isPointer (), false );
144152 }
145-
146- // const and volatile are ignored at the top level
147- auto lhsDecay = lhs;
148- lhsDecay->IsConst = false ;
149- lhsDecay->IsVolatile = false ;
150- auto rhsDecay = rhs;
151- rhsDecay->IsConst = false ;
152- rhsDecay->IsVolatile = false ;
153-
154- // Arrays decay to pointer
155- if (lhsDecay->isArray ())
153+ MRDOCS_CHECK_OR (lhs->IsPackExpansion == rhs->IsPackExpansion , false );
154+ if constexpr (isInner)
155+ {
156+ // const and volative are ignored from root types
157+ // in function parameters
158+ MRDOCS_CHECK_OR (lhs->IsConst == rhs->IsConst , false );
159+ MRDOCS_CHECK_OR (lhs->IsVolatile == rhs->IsVolatile , false );
160+ }
161+ MRDOCS_CHECK_OR (lhs->Constraints == rhs->Constraints , false );
162+ switch (lhs->Kind )
163+ {
164+ // Types that never decay are compared directly
165+ case TypeKind::Named:
166+ {
167+ // Compare only the fields of NameInfo, without
168+ // TypeInfo, to avoid evaluating TypeInfo::IsConst
169+ return dynamic_cast <NamedTypeInfo const &>(*lhs).Name ==
170+ dynamic_cast <NamedTypeInfo const &>(*rhs).Name ;
171+ }
172+ case TypeKind::Decltype:
173+ {
174+ return dynamic_cast <DecltypeTypeInfo const &>(*lhs).Operand ==
175+ dynamic_cast <DecltypeTypeInfo const &>(*rhs).Operand ;
176+ }
177+ case TypeKind::Auto:
178+ {
179+ auto const & lhsAuto = dynamic_cast <AutoTypeInfo const &>(*lhs);
180+ auto const & rhsAuto = dynamic_cast <AutoTypeInfo const &>(*rhs);
181+ return lhsAuto.Keyword == rhsAuto.Keyword &&
182+ lhsAuto.Constraint == rhsAuto.Constraint ;
183+ }
184+ case TypeKind::LValueReference:
156185 {
157- auto & lhsAsArray = dynamic_cast <ArrayTypeInfo&>(*lhsDecay);
158- PointerTypeInfo lhsAsPtr;
159- lhsAsPtr.PointeeType = std::move (lhsAsArray.ElementType );
160- // Copy all fields from base type
161- dynamic_cast <TypeInfo&>(lhsAsPtr) = dynamic_cast <TypeInfo&>(lhsAsArray);
162- lhsAsPtr.Kind = TypeKind::Pointer;
163- lhsDecay = std::move (lhsAsPtr);
186+ return
187+ isDecayedEqualImpl<true >(
188+ dynamic_cast <LValueReferenceTypeInfo const &>(*lhs).PointeeType ,
189+ dynamic_cast <LValueReferenceTypeInfo const &>(*rhs).PointeeType );
164190 }
165- if (rhsDecay-> isArray ())
191+ case TypeKind::RValueReference:
166192 {
167- auto & rhsAsArray = dynamic_cast <ArrayTypeInfo&>(*rhsDecay);
168- PointerTypeInfo rhsAsPtr;
169- rhsAsPtr.PointeeType = std::move (rhsAsArray.ElementType );
170- // Copy all fields from base type
171- dynamic_cast <TypeInfo&>(rhsAsPtr) = dynamic_cast <TypeInfo&>(rhsAsArray);
172- rhsAsPtr.Kind = TypeKind::Pointer;
173- rhsDecay = std::move (rhsAsPtr);
193+ return
194+ isDecayedEqualImpl<true >(
195+ dynamic_cast <RValueReferenceTypeInfo const &>(*lhs).PointeeType ,
196+ dynamic_cast <RValueReferenceTypeInfo const &>(*rhs).PointeeType );
174197 }
198+ case TypeKind::MemberPointer:
199+ {
200+ auto const & lhsMP = dynamic_cast <MemberPointerTypeInfo const &>(*lhs);
201+ auto const & rhsMP = dynamic_cast <MemberPointerTypeInfo const &>(*rhs);
202+ return
203+ isDecayedEqualImpl<true >(lhsMP.PointeeType , rhsMP.PointeeType ) &&
204+ isDecayedEqualImpl<true >(lhsMP.ParentType , rhsMP.ParentType );
205+ }
206+ case TypeKind::Function:
207+ {
208+ auto const & lhsF = dynamic_cast <FunctionTypeInfo const &>(*lhs);
209+ auto const & rhsF = dynamic_cast <FunctionTypeInfo const &>(*rhs);
210+ MRDOCS_CHECK_OR (lhsF.RefQualifier == rhsF.RefQualifier , false );
211+ MRDOCS_CHECK_OR (lhsF.ExceptionSpec == rhsF.ExceptionSpec , false );
212+ MRDOCS_CHECK_OR (lhsF.IsVariadic == rhsF.IsVariadic , false );
213+ MRDOCS_CHECK_OR (isDecayedEqualImpl<true >(lhsF.ReturnType , rhsF.ReturnType ), false );
214+ MRDOCS_CHECK_OR (lhsF.ParamTypes .size () == rhsF.ParamTypes .size (), false );
215+ for (std::size_t i = 0 ; i < lhsF.ParamTypes .size (); ++i)
216+ {
217+ MRDOCS_CHECK_OR (isDecayedEqualImpl<false >(lhsF.ParamTypes [i], rhsF.ParamTypes [i]), false );
218+ }
219+ return true ;
220+ }
221+ // Types that should decay
222+ case TypeKind::Pointer:
223+ case TypeKind::Array:
224+ {
225+ auto const I1 = innerType (*lhs);
226+ auto const I2 = innerType (*rhs);
227+ MRDOCS_CHECK_OR (static_cast <bool >(I1) == static_cast <bool >(I2), false );
228+ MRDOCS_CHECK_OR (static_cast <bool >(I1) && static_cast <bool >(I2), true );
229+ return isDecayedEqualImpl<true >(I1->get (), I2->get ());
230+ }
231+ default :
232+ MRDOCS_UNREACHABLE ();
233+ }
234+ return true ;
235+ }
175236
176- return lhsDecay == rhsDecay;
237+ /* Compare two types for equality for the purposes of
238+ overload resolution.
239+ */
240+ bool
241+ isDecayedEqual (
242+ Polymorphic<TypeInfo> const & lhs,
243+ Polymorphic<TypeInfo> const & rhs)
244+ {
245+ return isDecayedEqualImpl<false >(lhs, rhs);
177246}
178247}
179248
0 commit comments