[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Mar 31 11:20:13 PDT 2025
================
@@ -3231,6 +3241,230 @@ static QualType builtinCommonTypeImpl(Sema &S, TemplateName BaseTemplate,
}
}
+static QualType CopyCV(QualType From, QualType To) {
+ if (From.isConstQualified())
+ To.addConst();
+ if (From.isVolatileQualified())
+ To.addVolatile();
+ return To;
+}
+
+// COND-RES(X, Y) be decltype(false ? declval<X(&)()>()() : declval<Y(&)()>()())
+static QualType CondRes(Sema &S, QualType X, QualType Y, SourceLocation Loc) {
+ 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;
+
+ // declval<X(&)()>()()
+ OpaqueValueExpr LHSExpr(Loc, X.getNonLValueExprType(S.Context),
+ Expr::getValueKindForType(X));
+ ExprResult LHS = &LHSExpr;
+
+ // declval<Y(&)()>()()
+ OpaqueValueExpr RHSExpr(Loc, Y.getNonLValueExprType(S.Context),
+ Expr::getValueKindForType(Y));
+ ExprResult RHS = &RHSExpr;
+
+ ExprValueKind VK = VK_PRValue;
+ ExprObjectKind OK = OK_Ordinary;
+
+ // decltype(false ? declval<X(&)()>()() : declval<Y(&)()>()())
+ QualType Result = S.CheckConditionalOperands(Cond, LHS, RHS, VK, OK, Loc);
+
+ if (SFINAE.hasErrorOccurred())
+ return QualType();
+ if (VK == VK_LValue)
+ return S.BuiltinAddLValueReference(Result, Loc);
+ if (VK == VK_XValue)
+ return S.BuiltinAddRValueReference(Result, Loc);
+ return Result;
+}
+
+static QualType CommonRef(Sema &S, QualType A, QualType B, SourceLocation Loc) {
+ // Given types A and B, let X be remove_reference_t<A>, let Y be
+ // remove_reference_t<B>, and let COMMON-REF(A, B) be:
+ assert(A->isReferenceType() && B->isReferenceType() &&
+ "A and B have to be ref qualified for a COMMON-REF");
+ auto X = A.getNonReferenceType();
+ auto Y = B.getNonReferenceType();
+
+ // If A and B are both lvalue reference types, COMMON-REF(A, B) is
+ // COND-RES(COPYCV(X, Y) &, COPYCV(Y, X) &) if that type exists and is a
+ // reference type.
+ if (A->isLValueReferenceType() && B->isLValueReferenceType()) {
+ auto CR = CondRes(S, S.BuiltinAddLValueReference(CopyCV(X, Y), Loc),
+ S.BuiltinAddLValueReference(CopyCV(Y, X), Loc), Loc);
+ if (CR.isNull() || !CR->isReferenceType())
+ return QualType();
+ return CR;
+ }
+
+ // Otherwise, let C be remove_reference_t<COMMON-REF(X&, Y&)>&&. If A and B
+ // are both rvalue reference types, C is well-formed, and
+ // is_convertible_v<A, C> && is_convertible_v<B, C> is true, then
+ // COMMON-REF(A, B) is C.
+ if (A->isRValueReferenceType() && B->isRValueReferenceType()) {
+ auto C = CommonRef(S, S.BuiltinAddLValueReference(X, Loc),
+ S.BuiltinAddLValueReference(Y, Loc), Loc);
+ if (C.isNull())
+ return QualType();
+
+ C = C.getNonReferenceType();
+
+ if (S.BuiltinIsConvertible(A, C, Loc) && S.BuiltinIsConvertible(B, C, Loc))
+ return S.BuiltinAddRValueReference(C, Loc);
+ return QualType();
+ }
+
+ // Otherwise, if A is an lvalue reference and B is an rvalue reference, then
+ // COMMON-REF(A, B) is COMMON-REF(B, A).
+ if (A->isLValueReferenceType() && B->isRValueReferenceType())
+ std::swap(A, B);
+
+ // Otherwise, let D be COMMON-REF(const X&, Y&). If A is an rvalue reference
+ // and B is an lvalue reference and D is well-formed and
+ // is_convertible_v<A, D> is true, then COMMON-REF(A, B) is D.
+ if (A->isRValueReferenceType() && B->isLValueReferenceType()) {
+ auto X2 = X;
+ X2.addConst();
+ auto D = CommonRef(S, S.BuiltinAddLValueReference(X2, Loc),
+ S.BuiltinAddLValueReference(Y, Loc), Loc);
+ if (!D.isNull() && S.BuiltinIsConvertible(A, D, Loc))
+ return D;
+ return QualType();
+ }
+
+ // Otherwise, COMMON-REF(A, B) is ill-formed.
+ // This is implemented by returning from the individual branches above.
+
+ llvm_unreachable("The above cases should be exhaustive");
+}
+
+static QualType builtinCommonReferenceImpl(Sema &S,
+ TemplateName CommonReference,
+ TemplateName CommonType,
+ SourceLocation TemplateLoc,
+ ArrayRef<TemplateArgument> Ts) {
+ switch (Ts.size()) {
+ // If sizeof...(T) is zero, there shall be no member type.
+ case 0:
+ return QualType();
+
+ // Otherwise, if sizeof...(T) is one, let T0 denote the sole type in the
+ // pack T. The member typedef type shall denote the same type as T0.
+ case 1:
+ return Ts[0].getAsType();
+
+ // Otherwise, if sizeof...(T) is two, let T1 and T2 denote the two types in
+ // the pack T. Then
+ case 2: {
+ auto T1 = Ts[0].getAsType();
+ auto T2 = Ts[1].getAsType();
+
+ // Let R be COMMON-REF(T1, T2). If T1 and T2 are reference types, R is
+ // well-formed, and is_convertible_v<add_pointer_t<T1>, add_pointer_t<R>> &&
+ // is_convertible_v<add_pointer_t<T2>, add_pointer_t<R>> is true, then the
+ // member typedef type denotes R.
+ if (T1->isReferenceType() && T2->isReferenceType()) {
+ QualType R = CommonRef(S, T1, T2, TemplateLoc);
+ if (!R.isNull()) {
+ if (S.BuiltinIsConvertible(S.BuiltinAddPointer(T1, TemplateLoc),
----------------
huixie90 wrote:
perhaps update the status of P2655 is partially implemented?
https://github.com/llvm/llvm-project/pull/121199
More information about the cfe-commits
mailing list