Skip to content

Commit d11417d

Browse files
committed
[Clang] Add __common_type builtin
1 parent b634e05 commit d11417d

File tree

15 files changed

+401
-6
lines changed

15 files changed

+401
-6
lines changed

clang/include/clang/AST/ASTContext.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
399399
/// The identifier '__type_pack_element'.
400400
mutable IdentifierInfo *TypePackElementName = nullptr;
401401

402+
/// The identifier '__common_type'.
403+
mutable IdentifierInfo *CommonTypeName = nullptr;
404+
402405
QualType ObjCConstantStringType;
403406
mutable RecordDecl *CFConstantStringTagDecl = nullptr;
404407
mutable TypedefDecl *CFConstantStringTypeDecl = nullptr;
@@ -606,6 +609,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
606609
mutable ExternCContextDecl *ExternCContext = nullptr;
607610
mutable BuiltinTemplateDecl *MakeIntegerSeqDecl = nullptr;
608611
mutable BuiltinTemplateDecl *TypePackElementDecl = nullptr;
612+
mutable BuiltinTemplateDecl *CommonTypeDecl = nullptr;
609613

610614
/// The associated SourceManager object.
611615
SourceManager &SourceMgr;
@@ -1107,6 +1111,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
11071111
ExternCContextDecl *getExternCContextDecl() const;
11081112
BuiltinTemplateDecl *getMakeIntegerSeqDecl() const;
11091113
BuiltinTemplateDecl *getTypePackElementDecl() const;
1114+
BuiltinTemplateDecl *getCommonTypeDecl() const;
11101115

11111116
// Builtin Types.
11121117
CanQualType VoidTy;
@@ -1984,6 +1989,12 @@ class ASTContext : public RefCountedBase<ASTContext> {
19841989
return TypePackElementName;
19851990
}
19861991

1992+
IdentifierInfo *getCommonTypeName() const {
1993+
if (!CommonTypeName)
1994+
CommonTypeName = &Idents.get("__common_type");
1995+
return CommonTypeName;
1996+
}
1997+
19871998
/// Retrieve the Objective-C "instancetype" type, if already known;
19881999
/// otherwise, returns a NULL type;
19892000
QualType getObjCInstanceType() {

clang/include/clang/AST/DeclID.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,13 +84,16 @@ enum PredefinedDeclIDs {
8484

8585
/// The internal '__type_pack_element' template.
8686
PREDEF_DECL_TYPE_PACK_ELEMENT_ID = 17,
87+
88+
/// The internal '__common_type' template.
89+
PREDEF_DECL_COMMON_TYPE_ID = 18,
8790
};
8891

8992
/// The number of declaration IDs that are predefined.
9093
///
9194
/// For more information about predefined declarations, see the
9295
/// \c PredefinedDeclIDs type and the PREDEF_DECL_*_ID constants.
93-
const unsigned int NUM_PREDEF_DECL_IDS = 18;
96+
const unsigned int NUM_PREDEF_DECL_IDS = 19;
9497

9598
/// GlobalDeclID means DeclID in the current ASTContext and LocalDeclID means
9699
/// DeclID specific to a certain ModuleFile. Specially, in ASTWriter, the

clang/include/clang/Basic/Builtins.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,10 @@ enum BuiltinTemplateKind : int {
309309
BTK__make_integer_seq,
310310

311311
/// This names the __type_pack_element BuiltinTemplateDecl.
312-
BTK__type_pack_element
312+
BTK__type_pack_element,
313+
314+
/// This names the __common_type BuiltinTemplateDecl.
315+
BTK__common_type,
313316
};
314317

315318
} // end namespace clang

clang/include/clang/Sema/Sema.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2282,6 +2282,10 @@ class Sema final : public SemaBase {
22822282
/// Check to see if a given expression could have '.c_str()' called on it.
22832283
bool hasCStrMethod(const Expr *E);
22842284

2285+
// Check whether a type member 'Type::Name' exists, and if yes, return the
2286+
// type. If there is no type, the QualType is null
2287+
QualType getTypeMember(StringRef Name, QualType Type);
2288+
22852289
/// Diagnose pointers that are always non-null.
22862290
/// \param E the expression containing the pointer
22872291
/// \param NullKind NPCK_NotNull if E is a cast to bool, otherwise, E is

clang/lib/AST/ASTContext.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1170,6 +1170,13 @@ ASTContext::getTypePackElementDecl() const {
11701170
return TypePackElementDecl;
11711171
}
11721172

1173+
BuiltinTemplateDecl *ASTContext::getCommonTypeDecl() const {
1174+
if (!CommonTypeDecl)
1175+
CommonTypeDecl =
1176+
buildBuiltinTemplateDecl(BTK__common_type, getCommonTypeName());
1177+
return CommonTypeDecl;
1178+
}
1179+
11731180
RecordDecl *ASTContext::buildImplicitRecord(StringRef Name,
11741181
RecordDecl::TagKind TK) const {
11751182
SourceLocation Loc;

clang/lib/AST/ASTImporter.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5408,6 +5408,9 @@ ExpectedDecl ASTNodeImporter::VisitBuiltinTemplateDecl(BuiltinTemplateDecl *D) {
54085408
case BuiltinTemplateKind::BTK__type_pack_element:
54095409
ToD = Importer.getToContext().getTypePackElementDecl();
54105410
break;
5411+
case BuiltinTemplateKind::BTK__common_type:
5412+
ToD = Importer.getToContext().getCommonTypeDecl();
5413+
break;
54115414
}
54125415
assert(ToD && "BuiltinTemplateDecl of unsupported kind!");
54135416
Importer.MapImported(D, ToD);

clang/lib/AST/DeclTemplate.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1599,13 +1599,66 @@ createTypePackElementParameterList(const ASTContext &C, DeclContext *DC) {
15991599
nullptr);
16001600
}
16011601

1602+
static TemplateParameterList *createCommonTypeList(const ASTContext &C,
1603+
DeclContext *DC) {
1604+
// class... Args
1605+
auto *Args = TemplateTypeParmDecl::Create(
1606+
C, DC, {}, {}, /*Depth=*/1, /*Position=*/0, /*Id=*/nullptr,
1607+
/*Typename=*/false, /*ParameterPack=*/true);
1608+
Args->setImplicit();
1609+
1610+
// <class... Args>
1611+
auto *BaseTemplateList =
1612+
TemplateParameterList::Create(C, {}, {}, Args, {}, nullptr);
1613+
1614+
// template <class... Args> class BaseTemplate
1615+
auto *BaseTemplate = TemplateTemplateParmDecl::Create(
1616+
C, DC, {}, /*Depth=*/0, /*Position=*/0, /*ParameterPack=*/false, {},
1617+
/*Typename=*/false, BaseTemplateList);
1618+
1619+
// class TypeMember
1620+
auto *TypeMember = TemplateTypeParmDecl::Create(
1621+
C, DC, {}, {}, /*Depth=*/1, /*Position=*/0, /*Id=*/nullptr,
1622+
/*Typename=*/false, /*ParameterPack=*/false);
1623+
1624+
// <class TypeMember>
1625+
auto *HasTypeMemberList =
1626+
TemplateParameterList::Create(C, {}, {}, TypeMember, {}, nullptr);
1627+
1628+
// template <class TypeMember> class HasTypeMember
1629+
auto *HasTypeMember =
1630+
TemplateTemplateParmDecl::Create(C, DC, {}, /*Depth=*/0, /*Position=*/1,
1631+
/*ParameterPack=*/false, {},
1632+
/*Typename=*/false, HasTypeMemberList);
1633+
1634+
// class HasNoTypeMember
1635+
auto *HasNoTypeMember = TemplateTypeParmDecl::Create(
1636+
C, DC, {}, {}, /*Depth=*/0, /*Position=*/2, /*Id=*/nullptr,
1637+
/*Typename=*/false, /*ParameterPack=*/false);
1638+
1639+
// class... Ts
1640+
auto *Ts = TemplateTypeParmDecl::Create(
1641+
C, DC, {}, {}, /*Depth=*/0, /*Position=*/3,
1642+
/*Id=*/nullptr, /*Typename=*/false, /*ParameterPack=*/true);
1643+
Ts->setImplicit();
1644+
1645+
// template <template <class... Args> class BaseTemplate,
1646+
// template <class TypeMember> class HasTypeMember, class HasNoTypeMember,
1647+
// class... Ts>
1648+
return TemplateParameterList::Create(
1649+
C, {}, {}, {BaseTemplate, HasTypeMember, HasNoTypeMember, Ts}, {},
1650+
nullptr);
1651+
}
1652+
16021653
static TemplateParameterList *createBuiltinTemplateParameterList(
16031654
const ASTContext &C, DeclContext *DC, BuiltinTemplateKind BTK) {
16041655
switch (BTK) {
16051656
case BTK__make_integer_seq:
16061657
return createMakeIntegerSeqParameterList(C, DC);
16071658
case BTK__type_pack_element:
16081659
return createTypePackElementParameterList(C, DC);
1660+
case BTK__common_type:
1661+
return createCommonTypeList(C, DC);
16091662
}
16101663

16111664
llvm_unreachable("unhandled BuiltinTemplateKind!");

clang/lib/Lex/PPMacroExpansion.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1822,6 +1822,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
18221822
// Report builtin templates as being builtins.
18231823
.Case("__make_integer_seq", getLangOpts().CPlusPlus)
18241824
.Case("__type_pack_element", getLangOpts().CPlusPlus)
1825+
.Case("__common_type", getLangOpts().CPlusPlus)
18251826
// Likewise for some builtin preprocessor macros.
18261827
// FIXME: This is inconsistent; we usually suggest detecting
18271828
// builtin macros via #ifdef. Don't add more cases here.

clang/lib/Sema/SemaChecking.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6844,6 +6844,14 @@ CXXRecordMembersNamed(StringRef Name, Sema &S, QualType Ty) {
68446844
return Results;
68456845
}
68466846

6847+
QualType Sema::getTypeMember(StringRef Name, QualType Type) {
6848+
auto Results = CXXRecordMembersNamed<TypeDecl>(Name, *this, Type);
6849+
assert(Results.size() <= 1);
6850+
if (Results.empty())
6851+
return {};
6852+
return Context.getTypeDeclType(*Results.begin());
6853+
}
6854+
68476855
/// Check if we could call '.c_str()' on an object.
68486856
///
68496857
/// FIXME: This returns the wrong results in some cases (if cv-qualifiers don't

clang/lib/Sema/SemaLookup.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -932,6 +932,10 @@ bool Sema::LookupBuiltin(LookupResult &R) {
932932
R.addDecl(getASTContext().getTypePackElementDecl());
933933
return true;
934934
}
935+
if (II == getASTContext().getCommonTypeName()) {
936+
R.addDecl(getASTContext().getCommonTypeDecl());
937+
return true;
938+
}
935939
}
936940

937941
// Check if this is an OpenCL Builtin, and if so, insert its overloads.

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 159 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3058,6 +3058,141 @@ void Sema::NoteAllFoundTemplates(TemplateName Name) {
30583058
}
30593059
}
30603060

3061+
static std::optional<QualType> commonTypeImpl(Sema &S,
3062+
TemplateName BaseTemplate,
3063+
SourceLocation TemplateLoc,
3064+
ArrayRef<TemplateArgument> Ts) {
3065+
auto lookUpCommonType = [&](TemplateArgument T1,
3066+
TemplateArgument T2) -> std::optional<QualType> {
3067+
// Don't bother looking for other specializations if both types are
3068+
// builtins - users aren't allowed to specialize for them
3069+
if (T1.getAsType()->isBuiltinType() && T2.getAsType()->isBuiltinType())
3070+
return commonTypeImpl(S, BaseTemplate, TemplateLoc, {T1, T2});
3071+
3072+
TemplateArgumentListInfo Args;
3073+
Args.addArgument(TemplateArgumentLoc(
3074+
T1, S.Context.getTrivialTypeSourceInfo(T1.getAsType())));
3075+
Args.addArgument(TemplateArgumentLoc(
3076+
T2, S.Context.getTrivialTypeSourceInfo(T2.getAsType())));
3077+
QualType BaseTemplateInst =
3078+
S.CheckTemplateIdType(BaseTemplate, TemplateLoc, Args);
3079+
if (S.RequireCompleteType(TemplateLoc, BaseTemplateInst,
3080+
diag::err_incomplete_type))
3081+
return std::nullopt;
3082+
if (QualType Type = S.getTypeMember("type", BaseTemplateInst);
3083+
!Type.isNull()) {
3084+
return Type;
3085+
}
3086+
return std::nullopt;
3087+
};
3088+
3089+
// Note A: For the common_type trait applied to a template parameter pack T of
3090+
// types, the member type shall be either defined or not present as follows:
3091+
switch (Ts.size()) {
3092+
3093+
// If sizeof...(T) is zero, there shall be no member type.
3094+
case 0:
3095+
return std::nullopt;
3096+
3097+
// If sizeof...(T) is one, let T0 denote the sole type constituting the
3098+
// pack T. The member typedef-name type shall denote the same type, if any, as
3099+
// common_type_t<T0, T0>; otherwise there shall be no member type.
3100+
case 1:
3101+
return lookUpCommonType(Ts[0], Ts[0]);
3102+
3103+
// If sizeof...(T) is two, let the first and second types constituting T be
3104+
// denoted by T1 and T2, respectively, and let D1 and D2 denote the same types
3105+
// as decay_t<T1> and decay_t<T2>, respectively.
3106+
case 2: {
3107+
QualType T1 = Ts[0].getAsType();
3108+
QualType T2 = Ts[1].getAsType();
3109+
QualType D1 = S.BuiltinDecay(T1, {});
3110+
QualType D2 = S.BuiltinDecay(T2, {});
3111+
3112+
// If is_same_v<T1, D1> is false or is_same_v<T2, D2> is false, let C denote
3113+
// the same type, if any, as common_type_t<D1, D2>.
3114+
if (!S.Context.hasSameType(T1, D1) || !S.Context.hasSameType(T2, D2)) {
3115+
return lookUpCommonType(D1, D2);
3116+
}
3117+
3118+
// Otherwise, if decay_t<decltype(false ? declval<D1>() : declval<D2>())>
3119+
// denotes a valid type, let C denote that type.
3120+
{
3121+
auto CheckConditionalOperands =
3122+
[&](bool ConstRefQual) -> std::optional<QualType> {
3123+
EnterExpressionEvaluationContext UnevaluatedContext(
3124+
S, Sema::ExpressionEvaluationContext::Unevaluated);
3125+
Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/true);
3126+
Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl());
3127+
3128+
// false
3129+
OpaqueValueExpr CondExpr({}, S.Context.BoolTy,
3130+
ExprValueKind::VK_PRValue);
3131+
ExprResult Cond = &CondExpr;
3132+
3133+
auto EVK =
3134+
ConstRefQual ? ExprValueKind::VK_LValue : ExprValueKind::VK_PRValue;
3135+
if (ConstRefQual) {
3136+
D1.addConst();
3137+
D2.addConst();
3138+
}
3139+
3140+
// declval<D1>()
3141+
OpaqueValueExpr LHSExpr(TemplateLoc, D1, EVK);
3142+
ExprResult LHS = &LHSExpr;
3143+
3144+
// declval<D2>()
3145+
OpaqueValueExpr RHSExpr(TemplateLoc, D2, EVK);
3146+
ExprResult RHS = &RHSExpr;
3147+
3148+
ExprValueKind VK = VK_PRValue;
3149+
ExprObjectKind OK = OK_Ordinary;
3150+
3151+
// decltype(false ? declval<D1>() : declval<D2>())
3152+
QualType Result =
3153+
S.CheckConditionalOperands(Cond, LHS, RHS, VK, OK, TemplateLoc);
3154+
3155+
if (Result.isNull() || SFINAE.hasErrorOccurred())
3156+
return std::nullopt;
3157+
3158+
// decay_t<decltype(false ? declval<D1>() : declval<D2>())>
3159+
return S.BuiltinDecay(Result, TemplateLoc);
3160+
};
3161+
3162+
if (auto Res = CheckConditionalOperands(false))
3163+
return Res;
3164+
3165+
// Let:
3166+
// CREF(A) be add_lvalue_reference_t<const remove_reference_t<A>>,
3167+
// COND-RES(X, Y) be
3168+
// decltype(false ? declval<X(&)()>()() : declval<Y(&)()>()()).
3169+
3170+
// C++20 only
3171+
// Otherwise, if COND-RES(CREF(D1), CREF(D2)) denotes a type, let C denote
3172+
// the type decay_t<COND-RES(CREF(D1), CREF(D2))>.
3173+
if (!S.Context.getLangOpts().CPlusPlus20)
3174+
return std::nullopt;
3175+
return CheckConditionalOperands(true);
3176+
}
3177+
}
3178+
3179+
// If sizeof...(T) is greater than two, let T1, T2, and R, respectively,
3180+
// denote the first, second, and (pack of) remaining types constituting T. Let
3181+
// C denote the same type, if any, as common_type_t<T1, T2>. If there is such
3182+
// a type C, the member typedef-name type shall denote the same type, if any,
3183+
// as common_type_t<C, R...>. Otherwise, there shall be no member type.
3184+
default: {
3185+
std::optional<QualType> Result = Ts[Ts.size() - 1].getAsType();
3186+
for (size_t i = Ts.size() - 1; i != 0; --i) {
3187+
Result = lookUpCommonType(Ts[i - 1].getAsType(), *Result);
3188+
if (!Result)
3189+
return std::nullopt;
3190+
}
3191+
return Result;
3192+
}
3193+
}
3194+
}
3195+
30613196
static QualType
30623197
checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
30633198
ArrayRef<TemplateArgument> Converted,
@@ -3114,7 +3249,7 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
31143249
TemplateLoc, SyntheticTemplateArgs);
31153250
}
31163251

3117-
case BTK__type_pack_element:
3252+
case BTK__type_pack_element: {
31183253
// Specializations of
31193254
// __type_pack_element<Index, T_1, ..., T_N>
31203255
// are treated like T_Index.
@@ -3140,6 +3275,29 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
31403275
int64_t N = Index.getExtValue();
31413276
return Ts.getPackAsArray()[N].getAsType();
31423277
}
3278+
3279+
case BTK__common_type: {
3280+
assert(Converted.size() == 4);
3281+
if (Converted[0].isDependent() || Converted[1].isDependent() ||
3282+
Converted[2].isDependent() || Converted[3].isDependent())
3283+
return Context.getCanonicalTemplateSpecializationType(TemplateName(BTD),
3284+
Converted);
3285+
3286+
TemplateName BaseTemplate = Converted[0].getAsTemplate();
3287+
TemplateName HasTypeMember = Converted[1].getAsTemplate();
3288+
QualType HasNoTypeMember = Converted[2].getAsType();
3289+
ArrayRef<TemplateArgument> Ts = Converted[3].getPackAsArray();
3290+
if (auto CT = commonTypeImpl(SemaRef, BaseTemplate, TemplateLoc, Ts)) {
3291+
TemplateArgumentListInfo TAs;
3292+
TAs.addArgument(TemplateArgumentLoc(
3293+
TemplateArgument(*CT), SemaRef.Context.getTrivialTypeSourceInfo(
3294+
*CT, TemplateArgs[1].getLocation())));
3295+
3296+
return SemaRef.CheckTemplateIdType(HasTypeMember, TemplateLoc, TAs);
3297+
}
3298+
return HasNoTypeMember;
3299+
}
3300+
}
31433301
llvm_unreachable("unexpected BuiltinTemplateDecl!");
31443302
}
31453303

clang/lib/Serialization/ASTReader.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7789,6 +7789,9 @@ static Decl *getPredefinedDecl(ASTContext &Context, PredefinedDeclIDs ID) {
77897789

77907790
case PREDEF_DECL_TYPE_PACK_ELEMENT_ID:
77917791
return Context.getTypePackElementDecl();
7792+
7793+
case PREDEF_DECL_COMMON_TYPE_ID:
7794+
return Context.getCommonTypeDecl();
77927795
}
77937796
llvm_unreachable("PredefinedDeclIDs unknown enum value");
77947797
}

0 commit comments

Comments
 (0)