================ @@ -3058,6 +3058,133 @@ void Sema::NoteAllFoundTemplates(TemplateName Name) { } } +static QualType commonTypeImpl(Sema &S, TemplateName BaseTemplate, + SourceLocation TemplateLoc, + ArrayRef<TemplateArgument> Ts) { + auto lookUpCommonType = [&](TemplateArgument T1, + TemplateArgument T2) -> QualType { + // Don't bother looking for other specializations if both types are + // builtins - users aren't allowed to specialize for them + if (T1.getAsType()->isBuiltinType() && T2.getAsType()->isBuiltinType()) + return commonTypeImpl(S, BaseTemplate, TemplateLoc, {T1, T2}); + + TemplateArgumentListInfo Args; + Args.addArgument(TemplateArgumentLoc( + T1, S.Context.getTrivialTypeSourceInfo(T1.getAsType()))); + Args.addArgument(TemplateArgumentLoc( + T2, S.Context.getTrivialTypeSourceInfo(T2.getAsType()))); + QualType BaseTemplateInst = + S.CheckTemplateIdType(BaseTemplate, TemplateLoc, Args); + if (S.RequireCompleteType(TemplateLoc, BaseTemplateInst, + diag::err_incomplete_type)) + return QualType(); + return S.getTypeMember(BaseTemplateInst, "type"); + }; + + // Note A: For the common_type trait applied to a template parameter pack T of + // types, the member type shall be either defined or not present as follows: + switch (Ts.size()) { + + // If sizeof...(T) is zero, there shall be no member type. + case 0: + return QualType(); + + // If sizeof...(T) is one, let T0 denote the sole type constituting the + // pack T. The member typedef-name type shall denote the same type, if any, as + // common_type_t<T0, T0>; otherwise there shall be no member type. + case 1: + return lookUpCommonType(Ts[0], Ts[0]); + + // If sizeof...(T) is two, let the first and second types constituting T be + // denoted by T1 and T2, respectively, and let D1 and D2 denote the same types + // as decay_t<T1> and decay_t<T2>, respectively. + case 2: { + QualType T1 = Ts[0].getAsType(); + QualType T2 = Ts[1].getAsType(); + QualType D1 = S.BuiltinDecay(T1, {}); + QualType D2 = S.BuiltinDecay(T2, {}); + + // If is_same_v<T1, D1> is false or is_same_v<T2, D2> is false, let C denote + // the same type, if any, as common_type_t<D1, D2>. + if (!S.Context.hasSameType(T1, D1) || !S.Context.hasSameType(T2, D2)) + return lookUpCommonType(D1, D2); + + // Otherwise, if decay_t<decltype(false ? declval<D1>() : declval<D2>())> + // denotes a valid type, let C denote that type. + { + auto CheckConditionalOperands = [&](bool ConstRefQual) -> QualType { + EnterExpressionEvaluationContext UnevaluatedContext( + S, Sema::ExpressionEvaluationContext::Unevaluated); + Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/true); + Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl()); + + // false + OpaqueValueExpr CondExpr(SourceLocation(), S.Context.BoolTy, + VK_PRValue); + ExprResult Cond = &CondExpr; + + auto EVK = ConstRefQual ? VK_LValue : VK_PRValue; + if (ConstRefQual) { + D1.addConst(); + D2.addConst(); + } + + // declval<D1>() + OpaqueValueExpr LHSExpr(TemplateLoc, D1, EVK); + ExprResult LHS = &LHSExpr; + + // declval<D2>() + OpaqueValueExpr RHSExpr(TemplateLoc, D2, EVK); + ExprResult RHS = &RHSExpr; + + ExprValueKind VK = VK_PRValue; + ExprObjectKind OK = OK_Ordinary; + + // decltype(false ? declval<D1>() : declval<D2>()) + QualType Result = + S.CheckConditionalOperands(Cond, LHS, RHS, VK, OK, TemplateLoc); ---------------- cor3ntin wrote:
So, I think we can call `CXXCheckConditionalOperands` here. But the question I have is, should we factor out the part of `CXXCheckConditionalOperands` that deals with types directly and use that? One one hand, doing surgery to `CXXCheckConditionalOperands` requires care and might be a tad difficult, on the other hand the whole danse we are doing here is a bit convoluted https://github.com/llvm/llvm-project/pull/99473 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits