Author: Nico Weber Date: 2025-12-02T19:37:16-05:00 New Revision: e05fffbbc54d201a60e55e8c051bad81eaebd69a
URL: https://github.com/llvm/llvm-project/commit/e05fffbbc54d201a60e55e8c051bad81eaebd69a DIFF: https://github.com/llvm/llvm-project/commit/e05fffbbc54d201a60e55e8c051bad81eaebd69a.diff LOG: Revert "[Clang] Add __builtin_common_reference (#121199)" This reverts commit 3b9e203364dcd8234b12eb447ddbcf97a877558c. Causes not-yet-understood semantic differences, see commits on #121199. Added: Modified: clang/docs/LanguageExtensions.rst clang/include/clang/Basic/BuiltinTemplates.td clang/include/clang/Sema/Sema.h clang/lib/Sema/SemaTemplate.cpp clang/lib/Sema/SemaType.cpp clang/lib/Sema/SemaTypeTraits.cpp libcxx/include/__type_traits/common_reference.h libcxx/include/module.modulemap.in Removed: clang/test/SemaCXX/type-trait-common-reference.cpp ################################################################################ diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index 40cc18945764a..80cea2166bc83 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -1833,23 +1833,6 @@ Builtin type aliases Clang provides a few builtin aliases to improve the throughput of certain metaprogramming facilities. -__builtin_common_reference --------------------------- - -.. code-block:: c++ - - template <template <class, class, template <class> class, template <class> class> class BasicCommonReferenceT, - template <class... Args> CommonTypeT, - template <class> HasTypeMember, - class HasNoTypeMember, - class... Ts> - using __builtin_common_reference = ...; - -This alias is used for implementing ``std::common_reference``. If ``std::common_reference`` should contain a ``type`` -member, it is an alias to ``HasTypeMember<TheCommonReference>``. Otherwse it is an alias to ``HasNoTypeMember``. The -``CommonTypeT`` is usually ``std::common_type_t``. ``BasicCommonReferenceT`` is usually an alias template to -``basic_common_reference<T, U, TX, UX>::type``. - __builtin_common_type --------------------- diff --git a/clang/include/clang/Basic/BuiltinTemplates.td b/clang/include/clang/Basic/BuiltinTemplates.td index 804871de2bdab..504405acbdc78 100644 --- a/clang/include/clang/Basic/BuiltinTemplates.td +++ b/clang/include/clang/Basic/BuiltinTemplates.td @@ -10,11 +10,11 @@ class TemplateArg<string name> { string Name = name; } -class Template<list<TemplateArg> args, string name = ""> : TemplateArg<name> { +class Template<list<TemplateArg> args, string name> : TemplateArg<name> { list<TemplateArg> Args = args; } -class Class<string name = "", bit is_variadic = 0> : TemplateArg<name> { +class Class<string name, bit is_variadic = 0> : TemplateArg<name> { bit IsVariadic = is_variadic; } @@ -56,32 +56,6 @@ def __builtin_common_type : CPlusPlusBuiltinTemplate< Class<"HasNoTypeMember">, Class<"Ts", /*is_variadic=*/1>]>; -// template <template <class," -// class," -// template <class> class," -// template <class> class> class BasicCommonReferenceT," -// template <class... Args> class CommonTypeT," -// template <class> class HasTypeMember," -// class HasNoTypeMember," -// class... Ts>" -def __builtin_common_reference : CPlusPlusBuiltinTemplate< - [Template<[Class<>, - Class<>, - Template<[Class<>]>, - Template<[Class<>]>], "BasicCommonReferenceT">, - Template<[Class<"Args", /*is_variadic=*/1>], "CommonTypeT">, - Template<[Class<>], "HasTypeMember">, - Class<"HasNoTypeMember">, - Class<"Ts", /*is_variadic=*/1>]>; - -foreach Ref = ["", "lvalue", "rvalue"] in { - foreach Const = ["", "const"] in { - foreach Volatile = ["", "volatile"] in { - def __clang_internal_xref_#Ref#Const#Volatile : CPlusPlusBuiltinTemplate<[Class<>]>; - } - } -} - // template <uint32_t Opcode, // uint32_t Size, // uint32_t Alignment, diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 19cca691e9859..78ecbccbe4efc 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -15322,17 +15322,6 @@ class Sema final : public SemaBase { QualType BuiltinDecay(QualType BaseType, SourceLocation Loc); QualType BuiltinAddReference(QualType BaseType, UTTKind UKind, SourceLocation Loc); - - QualType BuiltinAddRValueReference(QualType BaseType, SourceLocation Loc) { - return BuiltinAddReference(BaseType, UnaryTransformType::AddRvalueReference, - Loc); - } - - QualType BuiltinAddLValueReference(QualType BaseType, SourceLocation Loc) { - return BuiltinAddReference(BaseType, UnaryTransformType::AddLvalueReference, - Loc); - } - QualType BuiltinRemoveExtent(QualType BaseType, UTTKind UKind, SourceLocation Loc); QualType BuiltinRemoveReference(QualType BaseType, UTTKind UKind, @@ -15347,9 +15336,6 @@ class Sema final : public SemaBase { QualType BuiltinChangeSignedness(QualType BaseType, UTTKind UKind, SourceLocation Loc); - bool BuiltinIsConvertible(QualType From, QualType To, SourceLocation Loc, - bool CheckNothrow = false); - bool BuiltinIsBaseOf(SourceLocation RhsTLoc, QualType LhsT, QualType RhsT); /// Ensure that the type T is a literal type. diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index ba91629783759..4a9e1bc93b918 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -3212,36 +3212,6 @@ void Sema::NoteAllFoundTemplates(TemplateName Name) { } } -static QualType InstantiateTemplate(Sema &S, ElaboratedTypeKeyword Keyword, - TemplateName Template, - ArrayRef<TemplateArgument> Args, - SourceLocation Loc) { - TemplateArgumentListInfo ArgList; - for (auto Arg : Args) { - if (Arg.getKind() == TemplateArgument::Type) { - ArgList.addArgument(TemplateArgumentLoc( - Arg, S.Context.getTrivialTypeSourceInfo(Arg.getAsType()))); - } else { - ArgList.addArgument( - S.getTrivialTemplateArgumentLoc(Arg, QualType(), Loc)); - } - } - - EnterExpressionEvaluationContext UnevaluatedContext( - S, Sema::ExpressionEvaluationContext::Unevaluated); - Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/true); - Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl()); - - QualType Instantiation = - S.CheckTemplateIdType(Keyword, Template, Loc, ArgList, /*Scope=*/nullptr, - /*ForNestedNameSpecifier=*/false); - - if (SFINAE.hasErrorOccurred()) - return QualType(); - - return Instantiation; -} - static QualType builtinCommonTypeImpl(Sema &S, ElaboratedTypeKeyword Keyword, TemplateName BaseTemplate, SourceLocation TemplateLoc, @@ -3254,7 +3224,25 @@ static QualType builtinCommonTypeImpl(Sema &S, ElaboratedTypeKeyword Keyword, return builtinCommonTypeImpl(S, Keyword, BaseTemplate, TemplateLoc, {T1, T2}); - return InstantiateTemplate(S, Keyword, BaseTemplate, {T1, T2}, TemplateLoc); + TemplateArgumentListInfo Args; + Args.addArgument(TemplateArgumentLoc( + T1, S.Context.getTrivialTypeSourceInfo(T1.getAsType()))); + Args.addArgument(TemplateArgumentLoc( + T2, S.Context.getTrivialTypeSourceInfo(T2.getAsType()))); + + EnterExpressionEvaluationContext UnevaluatedContext( + S, Sema::ExpressionEvaluationContext::Unevaluated); + Sema::SFINAETrap SFINAE(S, /*ForValidityCheck=*/true); + Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl()); + + QualType BaseTemplateInst = S.CheckTemplateIdType( + Keyword, BaseTemplate, TemplateLoc, Args, + /*Scope=*/nullptr, /*ForNestedNameSpecifier=*/false); + + if (SFINAE.hasErrorOccurred()) + return QualType(); + + return BaseTemplateInst; }; // Note A: For the common_type trait applied to a template parameter pack T of @@ -3361,233 +3349,6 @@ static QualType builtinCommonTypeImpl(Sema &S, ElaboratedTypeKeyword Keyword, } } -static QualType CopyCV(QualType From, QualType To) { - if (From.isConstQualified()) - To.addConst(); - if (From.isVolatileQualified()) - To.addVolatile(); - return To; -} - -// Let 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, - ElaboratedTypeKeyword Keyword, - 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), - S.BuiltinAddPointer(R, TemplateLoc), - TemplateLoc) && - S.BuiltinIsConvertible(S.BuiltinAddPointer(T2, TemplateLoc), - S.BuiltinAddPointer(R, TemplateLoc), - TemplateLoc)) { - return R; - } - } - } - - // Otherwise, if basic_common_reference<remove_cvref_t<T1>, - // remove_cvref_t<T2>, XREF(T1), XREF(T2)>::type is well-formed, - // then the member typedef type denotes that type. - { - auto getXRef = [&](QualType T) { - BuiltinTemplateDecl *Quals[12] = { - S.Context.get__clang_internal_xref_Decl(), - S.Context.get__clang_internal_xref_constDecl(), - S.Context.get__clang_internal_xref_volatileDecl(), - S.Context.get__clang_internal_xref_constvolatileDecl(), - S.Context.get__clang_internal_xref_lvalueDecl(), - S.Context.get__clang_internal_xref_lvalueconstDecl(), - S.Context.get__clang_internal_xref_lvaluevolatileDecl(), - S.Context.get__clang_internal_xref_lvalueconstvolatileDecl(), - S.Context.get__clang_internal_xref_rvalueDecl(), - S.Context.get__clang_internal_xref_rvalueconstDecl(), - S.Context.get__clang_internal_xref_rvaluevolatileDecl(), - S.Context.get__clang_internal_xref_rvalueconstvolatileDecl(), - }; - size_t Index = 0; - if (T->isLValueReferenceType()) { - T = T.getNonReferenceType(); - Index += 4; - } else if (T->isRValueReferenceType()) { - T = T.getNonReferenceType(); - Index += 8; - } - if (T.isConstQualified()) - Index += 1; - - if (T.isVolatileQualified()) - Index += 2; - - return Quals[Index]; - }; - - auto BCR = InstantiateTemplate(S, Keyword, CommonReference, - {S.BuiltinRemoveCVRef(T1, TemplateLoc), - S.BuiltinRemoveCVRef(T2, TemplateLoc), - TemplateName{getXRef(T1)}, - TemplateName{getXRef(T2)}}, - TemplateLoc); - if (!BCR.isNull()) - return BCR; - } - - // Otherwise, if COND-RES(T1, T2) is well-formed, then the member typedef - // type denotes that type. - if (auto CR = CondRes(S, T1, T2, TemplateLoc); !CR.isNull()) - return CR; - - // Otherwise, if common_type_t<T1, T2> is well-formed, then the member - // typedef type denotes that type. - if (auto CT = - InstantiateTemplate(S, Keyword, CommonType, {T1, T2}, TemplateLoc); - !CT.isNull()) - return CT; - - // Otherwise, there shall be no member type. - return QualType(); - } - - // Otherwise, if sizeof...(T) is greater than two, let T1, T2, and Rest, - // respectively, denote the first, second, and (pack of) remaining types - // comprising T. Let C be the type common_reference_t<T1, T2>. Then: - default: { - auto T1 = Ts[0]; - auto T2 = Ts[1]; - auto Rest = Ts.drop_front(2); - auto C = builtinCommonReferenceImpl(S, Keyword, CommonReference, CommonType, - TemplateLoc, {T1, T2}); - if (C.isNull()) - return QualType(); - llvm::SmallVector<TemplateArgument, 4> Args; - Args.emplace_back(C); - Args.append(Rest.begin(), Rest.end()); - return builtinCommonReferenceImpl(S, Keyword, CommonReference, CommonType, - TemplateLoc, Args); - } - } -} - static bool isInVkNamespace(const RecordType *RT) { DeclContext *DC = RT->getDecl()->getDeclContext(); if (!DC) @@ -3746,89 +3507,6 @@ static QualType checkBuiltinTemplateIdType( return HasNoTypeMember; } - case BTK__builtin_common_reference: { - assert(Converted.size() == 5); - if (llvm::any_of(Converted, [](auto &C) { return C.isDependent(); })) - return QualType(); - - TemplateName BasicCommonReference = Converted[0].getAsTemplate(); - TemplateName CommonType = Converted[1].getAsTemplate(); - TemplateName HasTypeMember = Converted[2].getAsTemplate(); - QualType HasNoTypeMember = Converted[3].getAsType(); - ArrayRef<TemplateArgument> Ts = Converted[4].getPackAsArray(); - if (auto CR = - builtinCommonReferenceImpl(SemaRef, Keyword, BasicCommonReference, - CommonType, TemplateLoc, Ts); - !CR.isNull()) { - TemplateArgumentListInfo TAs; - TAs.addArgument(TemplateArgumentLoc( - TemplateArgument(CR), SemaRef.Context.getTrivialTypeSourceInfo( - CR, TemplateArgs[1].getLocation()))); - return SemaRef.CheckTemplateIdType(Keyword, HasTypeMember, TemplateLoc, - TAs, /*Scope=*/nullptr, - /*ForNestedNameSpecifier=*/false); - } - return HasNoTypeMember; - } - - case BTK__clang_internal_xref_: - case BTK__clang_internal_xref_const: - case BTK__clang_internal_xref_volatile: - case BTK__clang_internal_xref_constvolatile: - case BTK__clang_internal_xref_lvalue: - case BTK__clang_internal_xref_lvalueconst: - case BTK__clang_internal_xref_lvaluevolatile: - case BTK__clang_internal_xref_lvalueconstvolatile: - case BTK__clang_internal_xref_rvalue: - case BTK__clang_internal_xref_rvalueconst: - case BTK__clang_internal_xref_rvaluevolatile: - case BTK__clang_internal_xref_rvalueconstvolatile: { - if (llvm::any_of(Converted, [](auto &C) { return C.isDependent(); })) - return QualType(); - - auto BTK = BTD->getBuiltinTemplateKind(); - auto anyOf = [&](auto... Vals) { return ((BTK == Vals) || ...); }; - - bool AddCV = anyOf(BTK__clang_internal_xref_constvolatile, - BTK__clang_internal_xref_lvalueconstvolatile, - BTK__clang_internal_xref_rvalueconstvolatile); - - bool AddConst = AddCV || anyOf(BTK__clang_internal_xref_const, - BTK__clang_internal_xref_lvalueconst, - BTK__clang_internal_xref_rvalueconst); - - bool AddVolatile = AddCV || anyOf(BTK__clang_internal_xref_volatile, - BTK__clang_internal_xref_lvaluevolatile, - BTK__clang_internal_xref_rvaluevolatile); - - bool AddLValue = anyOf(BTK__clang_internal_xref_lvalue, - BTK__clang_internal_xref_lvalueconst, - BTK__clang_internal_xref_lvaluevolatile, - BTK__clang_internal_xref_lvalueconstvolatile); - - bool AddRValue = anyOf(BTK__clang_internal_xref_rvalue, - BTK__clang_internal_xref_rvalueconst, - BTK__clang_internal_xref_rvaluevolatile, - BTK__clang_internal_xref_rvalueconstvolatile); - - assert(Converted.size() == 1); - - QualType T = Converted[0].getAsType(); - - if (AddConst) - T.addConst(); - - if (AddVolatile) - T.addVolatile(); - - if (AddLValue) - T = SemaRef.BuiltinAddLValueReference(T, TemplateLoc); - else if (AddRValue) - T = SemaRef.BuiltinAddRValueReference(T, TemplateLoc); - - return T; - } - case BTK__hlsl_spirv_type: { assert(Converted.size() == 4); diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 9488a853ffab1..9f5aa153d1cbe 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -32,8 +32,6 @@ #include "clang/Lex/Preprocessor.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/DelayedDiagnostic.h" -#include "clang/Sema/EnterExpressionEvaluationContext.h" -#include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/ParsedAttr.h" #include "clang/Sema/ParsedTemplate.h" @@ -10074,81 +10072,6 @@ QualType Sema::BuiltinChangeSignedness(QualType BaseType, UTTKind UKind, return Context.getQualifiedType(Underlying, BaseType.getQualifiers()); } -bool Sema::BuiltinIsConvertible(QualType From, QualType To, SourceLocation Loc, - bool CheckNothrow) { - if (To->isVoidType()) - return From->isVoidType(); - - // [meta.rel] - // From and To shall be complete types, cv void, or arrays of unknown bound. - if ((!From->isIncompleteArrayType() && !From->isVoidType() && - RequireCompleteType( - Loc, From, diag::err_incomplete_type_used_in_type_trait_expr)) || - (!To->isIncompleteArrayType() && !To->isVoidType() && - RequireCompleteType(Loc, To, - diag::err_incomplete_type_used_in_type_trait_expr))) - return false; - - // C++11 [meta.rel]p4: - // Given the following function prototype: - // - // template <class T> - // typename add_rvalue_reference<T>::type create(); - // - // the predicate condition for a template specialization - // is_convertible<From, To> shall be satisfied if and only if - // the return expression in the following code would be - // well-formed, including any implicit conversions to the return - // type of the function: - // - // To test() { - // return create<From>(); - // } - // - // Access checking is performed as if in a context unrelated to To and - // From. Only the validity of the immediate context of the expression - // of the return-statement (including conversions to the return type) - // is considered. - // - // We model the initialization as a copy-initialization of a temporary - // of the appropriate type, which for this expression is identical to the - // return statement (since NRVO doesn't apply). - - // Functions aren't allowed to return function or array types. - if (To->isFunctionType() || To->isArrayType()) - return false; - - // A function definition requires a non-abstract return type. - if (isAbstractType(Loc, To)) - return false; - - From = BuiltinAddRValueReference(From, Loc); - - // Build a fake source and destination for initialization. - InitializedEntity ToEntity(InitializedEntity::InitializeTemporary(To)); - OpaqueValueExpr FromExpr(Loc, From.getNonLValueExprType(Context), - Expr::getValueKindForType(From)); - InitializationKind Kind = - InitializationKind::CreateCopy(Loc, SourceLocation()); - - // Perform the initialization in an unevaluated context within a SFINAE - // trap at translation unit scope. - EnterExpressionEvaluationContext Unevaluated( - *this, Sema::ExpressionEvaluationContext::Unevaluated); - Sema::SFINAETrap SFINAE(*this, /*AccessCheckingSFINAE=*/true); - Sema::ContextRAII TUContext(*this, Context.getTranslationUnitDecl()); - Expr *FromExprPtr = &FromExpr; - InitializationSequence Init(*this, ToEntity, Kind, FromExprPtr); - if (Init.Failed()) - return false; - - ExprResult Result = Init.Perform(*this, ToEntity, Kind, FromExprPtr); - if (Result.isInvalid() || SFINAE.hasErrorOccurred()) - return false; - - return !CheckNothrow || canThrow(Result.get()) == CT_Cannot; -} - QualType Sema::BuildUnaryTransformType(QualType BaseType, UTTKind UKind, SourceLocation Loc) { if (BaseType->isDependentType()) diff --git a/clang/lib/Sema/SemaTypeTraits.cpp b/clang/lib/Sema/SemaTypeTraits.cpp index 3802da8bc2d45..38877967af05e 100644 --- a/clang/lib/Sema/SemaTypeTraits.cpp +++ b/clang/lib/Sema/SemaTypeTraits.cpp @@ -1212,6 +1212,76 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceInfo *Rhs, SourceLocation KeyLoc); +static ExprResult CheckConvertibilityForTypeTraits( + Sema &Self, const TypeSourceInfo *Lhs, const TypeSourceInfo *Rhs, + SourceLocation KeyLoc, llvm::BumpPtrAllocator &OpaqueExprAllocator) { + + QualType LhsT = Lhs->getType(); + QualType RhsT = Rhs->getType(); + + // C++0x [meta.rel]p4: + // Given the following function prototype: + // + // template <class T> + // typename add_rvalue_reference<T>::type create(); + // + // the predicate condition for a template specialization + // is_convertible<From, To> shall be satisfied if and only if + // the return expression in the following code would be + // well-formed, including any implicit conversions to the return + // type of the function: + // + // To test() { + // return create<From>(); + // } + // + // Access checking is performed as if in a context unrelated to To and + // From. Only the validity of the immediate context of the expression + // of the return-statement (including conversions to the return type) + // is considered. + // + // We model the initialization as a copy-initialization of a temporary + // of the appropriate type, which for this expression is identical to the + // return statement (since NRVO doesn't apply). + + // Functions aren't allowed to return function or array types. + if (RhsT->isFunctionType() || RhsT->isArrayType()) + return ExprError(); + + // A function definition requires a complete, non-abstract return type. + if (!Self.isCompleteType(Rhs->getTypeLoc().getBeginLoc(), RhsT) || + Self.isAbstractType(Rhs->getTypeLoc().getBeginLoc(), RhsT)) + return ExprError(); + + // Compute the result of add_rvalue_reference. + if (LhsT->isObjectType() || LhsT->isFunctionType()) + LhsT = Self.Context.getRValueReferenceType(LhsT); + + // Build a fake source and destination for initialization. + InitializedEntity To(InitializedEntity::InitializeTemporary(RhsT)); + Expr *From = new (OpaqueExprAllocator.Allocate<OpaqueValueExpr>()) + OpaqueValueExpr(KeyLoc, LhsT.getNonLValueExprType(Self.Context), + Expr::getValueKindForType(LhsT)); + InitializationKind Kind = + InitializationKind::CreateCopy(KeyLoc, SourceLocation()); + + // Perform the initialization in an unevaluated context within a SFINAE + // trap at translation unit scope. + EnterExpressionEvaluationContext Unevaluated( + Self, Sema::ExpressionEvaluationContext::Unevaluated); + Sema::SFINAETrap SFINAE(Self, /*ForValidityCheck=*/true); + Sema::ContextRAII TUContext(Self, Self.Context.getTranslationUnitDecl()); + InitializationSequence Init(Self, To, Kind, From); + if (Init.Failed()) + return ExprError(); + + ExprResult Result = Init.Perform(Self, To, Kind, From); + if (Result.isInvalid() || SFINAE.hasErrorOccurred()) + return ExprError(); + + return Result; +} + static APValue EvaluateSizeTTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc, ArrayRef<TypeSourceInfo *> Args, @@ -1372,8 +1442,9 @@ static bool EvaluateBooleanTypeTrait(Sema &S, TypeTrait Kind, S.Context.getPointerType(T.getNonReferenceType())); TypeSourceInfo *UPtr = S.Context.CreateTypeSourceInfo( S.Context.getPointerType(U.getNonReferenceType())); - return S.BuiltinIsConvertible(UPtr->getType(), TPtr->getType(), - RParenLoc); + return !CheckConvertibilityForTypeTraits(S, UPtr, TPtr, RParenLoc, + OpaqueExprAllocator) + .isInvalid(); } if (Kind == clang::TT_IsNothrowConstructible) @@ -1624,9 +1695,20 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, } case BTT_IsConvertible: case BTT_IsConvertibleTo: - case BTT_IsNothrowConvertible: - return Self.BuiltinIsConvertible(LhsT, RhsT, KeyLoc, - BTT == BTT_IsNothrowConvertible); + case BTT_IsNothrowConvertible: { + if (RhsT->isVoidType()) + return LhsT->isVoidType(); + llvm::BumpPtrAllocator OpaqueExprAllocator; + ExprResult Result = CheckConvertibilityForTypeTraits(Self, Lhs, Rhs, KeyLoc, + OpaqueExprAllocator); + if (Result.isInvalid()) + return false; + + if (BTT != BTT_IsNothrowConvertible) + return true; + + return Self.canThrow(Result.get()) == CT_Cannot; + } case BTT_IsAssignable: case BTT_IsNothrowAssignable: diff --git a/clang/test/SemaCXX/type-trait-common-reference.cpp b/clang/test/SemaCXX/type-trait-common-reference.cpp deleted file mode 100644 index cc4fefc49886d..0000000000000 --- a/clang/test/SemaCXX/type-trait-common-reference.cpp +++ /dev/null @@ -1,136 +0,0 @@ -// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=c++17 -Wno-vla-cxx-extension %s -// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=c++20 -Wno-vla-cxx-extension %s - -#if !__has_builtin(__builtin_common_reference) -# error -#endif - -// expected-note@*:* {{template <template <class, class, template <class> class, template <class> class> class, template <class ...> class, template <class> class, class, class ...>}} - -void test() { - __builtin_common_reference<> a; // expected-error {{too few template arguments for template '__builtin_common_reference'}} - __builtin_common_reference<1> b; // expected-error {{template argument for template template parameter must be a class template or type alias template}} - __builtin_common_reference<int, 1> c; // expected-error {{template argument for template template parameter must be a class template or type alias template}} -} - -struct empty_type {}; - -template <class T> -struct type_identity { - using type = T; -}; - -template <class...> -struct common_type; - -template <class... Args> -using common_type_t = typename common_type<Args...>::type; - -template <class, class, template <class> class, template <class> class> -struct basic_common_reference {}; - -template <class T, class U, template <class> class TX, template <class> class UX> -using basic_common_reference_t = typename basic_common_reference<T, U, TX, UX>::type; - -void test_vla() { - int i = 4; - int VLA[i]; - __builtin_common_reference<basic_common_reference_t, common_type_t, type_identity, empty_type, decltype(VLA)> d; // expected-error {{variably modified type 'decltype(VLA)' (aka 'int[i]') cannot be used as a template argument}} -} - -template <class... Args> -using common_reference_base = __builtin_common_reference<basic_common_reference_t, common_type_t, type_identity, empty_type, Args...>; - -template <class... Args> -struct common_reference : common_reference_base<Args...> {}; - -template <class... Args> -using common_reference_t = typename __builtin_common_reference<basic_common_reference_t, common_type_t, type_identity, empty_type, Args...>::type; - -struct Incomplete; - -template<> -struct common_type<Incomplete, Incomplete>; - -static_assert(__is_same(common_reference_base<>, empty_type)); - -static_assert(__is_same(common_reference_base<Incomplete>, type_identity<Incomplete>)); -static_assert(__is_same(common_reference_base<char>, type_identity<char>)); -static_assert(__is_same(common_reference_base<int>, type_identity<int>)); -static_assert(__is_same(common_reference_base<const int>, type_identity<const int>)); -static_assert(__is_same(common_reference_base<volatile int>, type_identity<volatile int>)); -static_assert(__is_same(common_reference_base<const volatile int>, type_identity<const volatile int>)); -static_assert(__is_same(common_reference_base<int[]>, type_identity<int[]>)); -static_assert(__is_same(common_reference_base<const int[]>, type_identity<const int[]>)); -static_assert(__is_same(common_reference_base<void(&)()>, type_identity<void(&)()>)); - -static_assert(__is_same(common_reference_base<int[], int[]>, type_identity<int*>)); -static_assert(__is_same(common_reference_base<int, int>, type_identity<int>)); -static_assert(__is_same(common_reference_base<int, long>, type_identity<long>)); -static_assert(__is_same(common_reference_base<long, int>, type_identity<long>)); -static_assert(__is_same(common_reference_base<long, long>, type_identity<long>)); - -static_assert(__is_same(common_reference_base<const int, long>, type_identity<long>)); -static_assert(__is_same(common_reference_base<const volatile int, long>, type_identity<long>)); -static_assert(__is_same(common_reference_base<int, const long>, type_identity<long>)); -static_assert(__is_same(common_reference_base<int, const volatile long>, type_identity<long>)); - -static_assert(__is_same(common_reference_base<int*, long*>, empty_type)); -static_assert(__is_same(common_reference_base<const unsigned int *const &, const unsigned int *const &>, type_identity<const unsigned int *const &>)); - -static_assert(__is_same(common_reference_base<int, long, float>, type_identity<float>)); -static_assert(__is_same(common_reference_base<unsigned, char, long>, type_identity<long>)); -static_assert(__is_same(common_reference_base<long long, long long, long>, type_identity<long long>)); - -static_assert(__is_same(common_reference_base<int [[clang::address_space(1)]]>, type_identity<int [[clang::address_space(1)]]>)); -static_assert(__is_same(common_reference_base<int [[clang::address_space(1)]], int>, type_identity<int>)); -static_assert(__is_same(common_reference_base<long [[clang::address_space(1)]], int>, type_identity<long>)); -static_assert(__is_same(common_reference_base<long [[clang::address_space(1)]], int [[clang::address_space(1)]]>, type_identity<long>)); -static_assert(__is_same(common_reference_base<long [[clang::address_space(1)]], long [[clang::address_space(1)]]>, type_identity<long>)); -static_assert(__is_same(common_reference_base<long [[clang::address_space(1)]], long [[clang::address_space(2)]]>, type_identity<long>)); - -struct S {}; -struct T : S {}; -struct U {}; - -static_assert(__is_same(common_reference_base<S&&, T&&>, type_identity<S&&>)); - -static_assert(__is_same(common_reference_base<int S::*, int S::*>, type_identity<int S::*>)); -static_assert(__is_same(common_reference_base<int S::*, int T::*>, type_identity<int T::*>)); -static_assert(__is_same(common_reference_base<int S::*, long S::*>, empty_type)); - -static_assert(__is_same(common_reference_base<int (S::*)(), int (S::*)()>, type_identity<int (S::*)()>)); -static_assert(__is_same(common_reference_base<int (S::*)(), int (T::*)()>, type_identity<int (T::*)()>)); -static_assert(__is_same(common_reference_base<int (S::*)(), long (S::*)()>, empty_type)); - -static_assert(__is_same(common_reference_base<int&, int&>, type_identity<int&>)); -static_assert(__is_same(common_reference_base<int&, const int&>, type_identity<const int&>)); -static_assert(__is_same(common_reference_base<volatile int&, const int&>, type_identity<const volatile int&>)); - -template <class T, class U> -struct my_pair; - -template <class T1, class U1, class T2, class U2, template <class> class TX, template <class> class UX> -struct basic_common_reference<my_pair<T1, U1>, my_pair<T2, U2>, TX, UX> { - using type = my_pair<common_reference_t<TX<T1>, UX<T2>>, common_reference_t<TX<U1>, UX<U2>>>; -}; - -static_assert(__is_same(common_reference_base<my_pair<const int&, int&>, my_pair<int&, volatile int&>>, type_identity<my_pair<const int&, volatile int&>>)); -static_assert(__is_same(common_reference_base<const my_pair<int, int>&, my_pair<int&, volatile int&>>, type_identity<my_pair<const int&, const volatile int&>>)); -static_assert(__is_same(common_reference_base<const int&, const volatile int&>, type_identity<const volatile int&>)); -static_assert(__is_same(common_reference_base<int&&, const volatile int&>, type_identity<int>)); -static_assert(__is_same(common_reference_base<my_pair<int, int>&&, my_pair<int&, volatile int&>>, type_identity<my_pair<const int&, int>>)); -static_assert(__is_same(common_reference_base<my_pair<int, int>&&, my_pair<int&, int>&&>, type_identity<my_pair<const int&, int&&>>)); - -struct conversion_operator { - operator volatile int&&() volatile; -}; - -static_assert(__is_same(common_reference_base<volatile conversion_operator&&, volatile int&&>, type_identity<volatile int&&>)); - -struct reference_wrapper { - reference_wrapper(int&); - operator int&() const; -}; - -static_assert(__is_same(common_reference_base<const reference_wrapper&, int&>, empty_type)); diff --git a/libcxx/include/__type_traits/common_reference.h b/libcxx/include/__type_traits/common_reference.h index 297b6adbe1ca0..59badb64267de 100644 --- a/libcxx/include/__type_traits/common_reference.h +++ b/libcxx/include/__type_traits/common_reference.h @@ -18,37 +18,16 @@ #include <__type_traits/is_reference.h> #include <__type_traits/remove_cvref.h> #include <__type_traits/remove_reference.h> -#include <__type_traits/type_identity.h> #include <__utility/declval.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header #endif -#if _LIBCPP_STD_VER >= 20 - _LIBCPP_BEGIN_NAMESPACE_STD -template <class...> -struct _LIBCPP_NO_SPECIALIZATIONS common_reference; - -template <class... _Types> -using common_reference_t = typename common_reference<_Types...>::type; - -template <class, class, template <class> class, template <class> class> -struct basic_common_reference {}; - -# if __has_builtin(__builtin_common_reference) - -template <class _Tp, class _Up, template <class> class _Tx, template <class> class _Ux> -using __basic_common_reference_t = basic_common_reference<_Tp, _Up, _Tx, _Ux>::type; - -template <class... _Args> -struct _LIBCPP_NO_SPECIALIZATIONS common_reference - : __builtin_common_reference<__basic_common_reference_t, common_type_t, type_identity, __empty, _Args...> {}; - -# else - +// common_reference +#if _LIBCPP_STD_VER >= 20 // Let COND_RES(X, Y) be: template <class _Xp, class _Yp> using __cond_res _LIBCPP_NODEBUG = decltype(false ? std::declval<_Xp (&)()>()() : std::declval<_Yp (&)()>()()); @@ -130,10 +109,19 @@ struct __common_ref {}; // Note C: For the common_reference trait applied to a parameter pack [...] +template <class...> +struct _LIBCPP_NO_SPECIALIZATIONS common_reference; + +template <class... _Types> +using common_reference_t = typename common_reference<_Types...>::type; + +template <class, class, template <class> class, template <class> class> +struct basic_common_reference {}; + _LIBCPP_DIAGNOSTIC_PUSH -# if __has_warning("-Winvalid-specialization") +# if __has_warning("-Winvalid-specialization") _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Winvalid-specialization") -# endif +# endif // bullet 1 - sizeof...(T) == 0 template <> struct common_reference<> {}; @@ -207,10 +195,8 @@ _LIBCPP_DIAGNOSTIC_POP template <class...> struct _LIBCPP_NO_SPECIALIZATIONS common_reference {}; -# endif // __has_builtin(__builtin_common_reference) +#endif // _LIBCPP_STD_VER >= 20 _LIBCPP_END_NAMESPACE_STD -#endif // _LIBCPP_STD_VER >= 20 - #endif // _LIBCPP___TYPE_TRAITS_COMMON_REFERENCE_H diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in index 5d2a92bf7905c..0ac5a1ade817f 100644 --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -1517,7 +1517,6 @@ module std [system] { header "__iterator/iterator_traits.h" export std_core.type_traits.integral_constant export std_core.type_traits.is_convertible - export std_core.type_traits.nat } module iterator_with_data { header "__iterator/iterator_with_data.h" } module iterator { header "__iterator/iterator.h" } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
