mirror of
https://github.com/intel/llvm.git
synced 2026-01-13 19:08:21 +08:00
Revert "[Clang] Add __builtin_common_reference (#121199)"
This reverts commit 3b9e203364.
Causes not-yet-understood semantic differences, see commits
on #121199.
This commit is contained in:
@@ -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
|
||||
---------------------
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -15322,17 +15322,6 @@ public:
|
||||
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 @@ public:
|
||||
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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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));
|
||||
@@ -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
|
||||
|
||||
@@ -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" }
|
||||
|
||||
Reference in New Issue
Block a user