Skip to content

Commit 61e855a

Browse files
committed
[clang] ASTContext: flesh out implementation of getCommonNNS
This properly implements getCommonNNS, for getting the common NestedNameSpecifier, for which the previous implementation was a bare minimum placeholder.
1 parent b326cb6 commit 61e855a

File tree

3 files changed

+120
-14
lines changed

3 files changed

+120
-14
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,9 @@ Improvements to Clang's diagnostics
264264
as function arguments or return value respectively. Note that
265265
:doc:`ThreadSafetyAnalysis` still does not perform alias analysis. The
266266
feature will be default-enabled with ``-Wthread-safety`` in a future release.
267-
- The ``-Wsign-compare`` warning now treats expressions with bitwise not(~) and minus(-) as signed integers
267+
- Clang will now do a better job producing common nested names, when producing
268+
common types for ternary operator, template argument deduction and multiple return auto deduction.
269+
- The ``-Wsign-compare`` warning now treats expressions with bitwise not(~) and minus(-) as signed integers
268270
except for the case where the operand is an unsigned integer
269271
and throws warning if they are compared with unsigned integers (##18878).
270272
- The ``-Wunnecessary-virtual-specifier`` warning has been added to warn about

clang/lib/AST/ASTContext.cpp

Lines changed: 115 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13462,13 +13462,114 @@ static ElaboratedTypeKeyword getCommonTypeKeyword(const T *X, const T *Y) {
1346213462
: ElaboratedTypeKeyword::None;
1346313463
}
1346413464

13465+
static NestedNameSpecifier *getCommonNNS(ASTContext &Ctx,
13466+
NestedNameSpecifier *X,
13467+
NestedNameSpecifier *Y, bool IsSame) {
13468+
if (X == Y)
13469+
return X;
13470+
13471+
NestedNameSpecifier *Canon = Ctx.getCanonicalNestedNameSpecifier(X);
13472+
if (Canon != Ctx.getCanonicalNestedNameSpecifier(Y)) {
13473+
assert(!IsSame && "Should be the same NestedNameSpecifier");
13474+
return nullptr;
13475+
}
13476+
13477+
NestedNameSpecifier *R = nullptr;
13478+
switch (auto KX = X->getKind(), KY = Y->getKind(); KX) {
13479+
case NestedNameSpecifier::SpecifierKind::Identifier: {
13480+
assert(KY == NestedNameSpecifier::SpecifierKind::Identifier);
13481+
IdentifierInfo *II = X->getAsIdentifier();
13482+
assert(II == Y->getAsIdentifier());
13483+
NestedNameSpecifier *P =
13484+
::getCommonNNS(Ctx, X->getPrefix(), Y->getPrefix(), /*IsSame=*/true);
13485+
R = NestedNameSpecifier::Create(Ctx, P, II);
13486+
break;
13487+
}
13488+
case NestedNameSpecifier::SpecifierKind::Namespace:
13489+
case NestedNameSpecifier::SpecifierKind::NamespaceAlias: {
13490+
assert(KY == NestedNameSpecifier::SpecifierKind::Namespace ||
13491+
KY == NestedNameSpecifier::SpecifierKind::NamespaceAlias);
13492+
NestedNameSpecifier *P = ::getCommonNNS(Ctx, X->getPrefix(), Y->getPrefix(),
13493+
/*IsSame=*/false);
13494+
NamespaceAliasDecl *AX = X->getAsNamespaceAlias(),
13495+
*AY = Y->getAsNamespaceAlias();
13496+
if (declaresSameEntity(AX, AY)) {
13497+
R = NestedNameSpecifier::Create(Ctx, P, ::getCommonDeclChecked(AX, AY));
13498+
break;
13499+
}
13500+
NamespaceDecl *NX = AX ? AX->getNamespace() : X->getAsNamespace(),
13501+
*NY = AY ? AY->getNamespace() : Y->getAsNamespace();
13502+
R = NestedNameSpecifier::Create(Ctx, P, ::getCommonDeclChecked(NX, NY));
13503+
break;
13504+
}
13505+
case NestedNameSpecifier::SpecifierKind::TypeSpec:
13506+
case NestedNameSpecifier::SpecifierKind::TypeSpecWithTemplate: {
13507+
assert(KY == NestedNameSpecifier::SpecifierKind::TypeSpec ||
13508+
KY == NestedNameSpecifier::SpecifierKind::TypeSpecWithTemplate);
13509+
bool Template =
13510+
KX == NestedNameSpecifier::SpecifierKind::TypeSpecWithTemplate &&
13511+
KY == NestedNameSpecifier::SpecifierKind::TypeSpecWithTemplate;
13512+
13513+
const Type *TX = X->getAsType(), *TY = Y->getAsType();
13514+
if (TX == TY) {
13515+
NestedNameSpecifier *P =
13516+
::getCommonNNS(Ctx, X->getPrefix(), Y->getPrefix(),
13517+
/*IsSame=*/false);
13518+
R = NestedNameSpecifier::Create(Ctx, P, Template, TX);
13519+
break;
13520+
}
13521+
// TODO: Try to salvage the original prefix.
13522+
// If getCommonSugaredType removed any top level sugar, the original prefix
13523+
// is not applicable anymore.
13524+
NestedNameSpecifier *P = nullptr;
13525+
const Type *T = Ctx.getCommonSugaredType(QualType(X->getAsType(), 0),
13526+
QualType(Y->getAsType(), 0),
13527+
/*Unqualified=*/true)
13528+
.getTypePtr();
13529+
switch (T->getTypeClass()) {
13530+
case Type::Elaborated: {
13531+
auto *ET = cast<ElaboratedType>(T);
13532+
R = NestedNameSpecifier::Create(Ctx, ET->getQualifier(), Template,
13533+
ET->getNamedType().getTypePtr());
13534+
break;
13535+
}
13536+
case Type::DependentName: {
13537+
auto *DN = cast<DependentNameType>(T);
13538+
R = NestedNameSpecifier::Create(Ctx, DN->getQualifier(),
13539+
DN->getIdentifier());
13540+
break;
13541+
}
13542+
case Type::DependentTemplateSpecialization: {
13543+
auto *DTST = cast<DependentTemplateSpecializationType>(T);
13544+
T = Ctx.getDependentTemplateSpecializationType(
13545+
DTST->getKeyword(), /*NNS=*/nullptr, DTST->getIdentifier(),
13546+
DTST->template_arguments())
13547+
.getTypePtr();
13548+
P = DTST->getQualifier();
13549+
R = NestedNameSpecifier::Create(Ctx, DTST->getQualifier(), Template, T);
13550+
break;
13551+
}
13552+
default:
13553+
R = NestedNameSpecifier::Create(Ctx, P, Template, T);
13554+
break;
13555+
}
13556+
break;
13557+
}
13558+
case NestedNameSpecifier::SpecifierKind::Global:
13559+
assert(KY == NestedNameSpecifier::SpecifierKind::Global);
13560+
return X;
13561+
case NestedNameSpecifier::SpecifierKind::Super:
13562+
assert(KY == NestedNameSpecifier::SpecifierKind::Super);
13563+
return X;
13564+
}
13565+
assert(Ctx.getCanonicalNestedNameSpecifier(R) == Canon);
13566+
return R;
13567+
}
13568+
1346513569
template <class T>
13466-
static NestedNameSpecifier *getCommonNNS(ASTContext &Ctx, const T *X,
13467-
const T *Y) {
13468-
// FIXME: Try to keep the common NNS sugar.
13469-
return X->getQualifier() == Y->getQualifier()
13470-
? X->getQualifier()
13471-
: Ctx.getCanonicalNestedNameSpecifier(X->getQualifier());
13570+
static NestedNameSpecifier *getCommonQualifier(ASTContext &Ctx, const T *X,
13571+
const T *Y, bool IsSame) {
13572+
return ::getCommonNNS(Ctx, X->getQualifier(), Y->getQualifier(), IsSame);
1347213573
}
1347313574

1347413575
template <class T>
@@ -13879,8 +13980,9 @@ static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X,
1387913980
*NY = cast<DependentNameType>(Y);
1388013981
assert(NX->getIdentifier() == NY->getIdentifier());
1388113982
return Ctx.getDependentNameType(
13882-
getCommonTypeKeyword(NX, NY), getCommonNNS(Ctx, NX, NY),
13883-
NX->getIdentifier(), NX->getCanonicalTypeInternal());
13983+
getCommonTypeKeyword(NX, NY),
13984+
getCommonQualifier(Ctx, NX, NY, /*IsSame=*/true), NX->getIdentifier(),
13985+
NX->getCanonicalTypeInternal());
1388413986
}
1388513987
case Type::DependentTemplateSpecialization: {
1388613988
const auto *TX = cast<DependentTemplateSpecializationType>(X),
@@ -13889,8 +13991,9 @@ static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X,
1388913991
auto As = getCommonTemplateArguments(Ctx, TX->template_arguments(),
1389013992
TY->template_arguments());
1389113993
return Ctx.getDependentTemplateSpecializationType(
13892-
getCommonTypeKeyword(TX, TY), getCommonNNS(Ctx, TX, TY),
13893-
TX->getIdentifier(), As);
13994+
getCommonTypeKeyword(TX, TY),
13995+
getCommonQualifier(Ctx, TX, TY, /*IsSame=*/true), TX->getIdentifier(),
13996+
As);
1389413997
}
1389513998
case Type::UnaryTransform: {
1389613999
const auto *TX = cast<UnaryTransformType>(X),
@@ -14047,7 +14150,8 @@ static QualType getCommonSugarTypeNode(ASTContext &Ctx, const Type *X,
1404714150
case Type::Elaborated: {
1404814151
const auto *EX = cast<ElaboratedType>(X), *EY = cast<ElaboratedType>(Y);
1404914152
return Ctx.getElaboratedType(
14050-
::getCommonTypeKeyword(EX, EY), ::getCommonNNS(Ctx, EX, EY),
14153+
::getCommonTypeKeyword(EX, EY),
14154+
::getCommonQualifier(Ctx, EX, EY, /*IsSame=*/false),
1405114155
Ctx.getQualifiedType(Underlying),
1405214156
::getCommonDecl(EX->getOwnedTagDecl(), EY->getOwnedTagDecl()));
1405314157
}

clang/test/SemaCXX/sugar-common-types.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ template <class T> struct S1 {
4444
};
4545

4646
N t10 = 0 ? S1<X1>() : S1<Y1>(); // expected-error {{from 'S1<B1>' (aka 'S1<int>')}}
47-
N t11 = 0 ? S1<X1>::S2<X2>() : S1<Y1>::S2<Y2>(); // expected-error {{from 'S1<int>::S2<B2>' (aka 'S2<void>')}}
47+
N t11 = 0 ? S1<X1>::S2<X2>() : S1<Y1>::S2<Y2>(); // expected-error {{from 'S1<B1>::S2<B2>' (aka 'S2<void>')}}
4848

4949
template <class T> using Al = S1<T>;
5050

@@ -88,7 +88,7 @@ N t19 = 0 ? (__underlying_type(EnumsX::X)){} : (__underlying_type(EnumsY::Y)){};
8888
// expected-error@-1 {{rvalue of type 'B1' (aka 'int')}}
8989

9090
N t20 = 0 ? (__underlying_type(EnumsX::X)){} : (__underlying_type(EnumsY::X)){};
91-
// expected-error@-1 {{rvalue of type '__underlying_type(Enums::X)' (aka 'int')}}
91+
// expected-error@-1 {{rvalue of type '__underlying_type(EnumsB::X)' (aka 'int')}}
9292

9393
using QX = const SB1 *;
9494
using QY = const ::SB1 *;

0 commit comments

Comments
 (0)