Skip to content

Commit 002480b

Browse files
committed
WIP: [clang] Template Specialization Resugaring - Expressions
This adds some additional users of the resugaring transform, around expressions. This makes function calls work for example. While probably not the largest patch in the series, this could use some further splitting up. Differential Revision: https://reviews.llvm.org/D137200
1 parent 3297e1b commit 002480b

29 files changed

+669
-205
lines changed

clang-tools-extra/clangd/unittests/InlayHintTests.cpp

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1290,8 +1290,8 @@ TEST(TypeHints, Lambda) {
12901290
assertTypeHints(R"cpp(
12911291
void f() {
12921292
int cap = 42;
1293-
auto $L[[L]] = [cap, $init[[init]] = 1 + 1](int a$ret[[)]] {
1294-
return a + cap + init;
1293+
auto $L[[L]] = [cap, $init[[init]] = 1 + 1](int a$ret[[)]] {
1294+
return a + cap + init;
12951295
};
12961296
}
12971297
)cpp",
@@ -1367,7 +1367,7 @@ TEST(TypeHints, StructuredBindings_TupleLike) {
13671367
TEST(TypeHints, StructuredBindings_NoInitializer) {
13681368
assertTypeHints(R"cpp(
13691369
// No initializer (ill-formed).
1370-
// Do not show useless "NULL TYPE" hint.
1370+
// Do not show useless "NULL TYPE" hint.
13711371
auto [x, y]; /*error-ok*/
13721372
)cpp");
13731373
}
@@ -1670,15 +1670,16 @@ TEST(TypeHints, SubstTemplateParameterAliases) {
16701670
auto $end[[end]] = array.end();
16711671
)cpp";
16721672

1673-
assertHintsWithHeader(
1674-
InlayHintKind::Type, VectorIntPtr, Header,
1675-
ExpectedHint{": int *", "no_modifier"},
1676-
ExpectedHint{": int **", "ptr_modifier"},
1677-
ExpectedHint{": int *&", "ref_modifier"},
1678-
ExpectedHint{": int *const &", "at"}, ExpectedHint{": int **", "data"},
1679-
ExpectedHint{": allocator<int *>", "allocator"},
1680-
ExpectedHint{": size_type", "size"}, ExpectedHint{": iterator", "begin"},
1681-
ExpectedHint{": non_template_iterator", "end"});
1673+
assertHintsWithHeader(InlayHintKind::Type, VectorIntPtr, Header,
1674+
ExpectedHint{": int *", "no_modifier"},
1675+
ExpectedHint{": int **", "ptr_modifier"},
1676+
ExpectedHint{": int *&", "ref_modifier"},
1677+
ExpectedHint{": const value_type &", "at"},
1678+
ExpectedHint{": pointer", "data"},
1679+
ExpectedHint{": allocator_type", "allocator"},
1680+
ExpectedHint{": size_type", "size"},
1681+
ExpectedHint{": iterator", "begin"},
1682+
ExpectedHint{": non_template_iterator", "end"});
16821683

16831684
llvm::StringRef VectorInt = R"cpp(
16841685
vector<int> array;
@@ -1694,15 +1695,16 @@ TEST(TypeHints, SubstTemplateParameterAliases) {
16941695
auto $end[[end]] = array.end();
16951696
)cpp";
16961697

1697-
assertHintsWithHeader(
1698-
InlayHintKind::Type, VectorInt, Header,
1699-
ExpectedHint{": int", "no_modifier"},
1700-
ExpectedHint{": int *", "ptr_modifier"},
1701-
ExpectedHint{": int &", "ref_modifier"},
1702-
ExpectedHint{": const int &", "at"}, ExpectedHint{": int *", "data"},
1703-
ExpectedHint{": allocator<int>", "allocator"},
1704-
ExpectedHint{": size_type", "size"}, ExpectedHint{": iterator", "begin"},
1705-
ExpectedHint{": non_template_iterator", "end"});
1698+
assertHintsWithHeader(InlayHintKind::Type, VectorInt, Header,
1699+
ExpectedHint{": int", "no_modifier"},
1700+
ExpectedHint{": int *", "ptr_modifier"},
1701+
ExpectedHint{": int &", "ref_modifier"},
1702+
ExpectedHint{": const value_type &", "at"},
1703+
ExpectedHint{": pointer", "data"},
1704+
ExpectedHint{": allocator_type", "allocator"},
1705+
ExpectedHint{": size_type", "size"},
1706+
ExpectedHint{": iterator", "begin"},
1707+
ExpectedHint{": non_template_iterator", "end"});
17061708

17071709
llvm::StringRef TypeAlias = R"cpp(
17081710
// If the type alias is not of substituted template parameter type,
@@ -1899,13 +1901,13 @@ TEST(BlockEndHints, Functions) {
18991901
return 41;
19001902
$foo[[}]]
19011903
1902-
template<int X>
1903-
int bar() {
1904+
template<int X>
1905+
int bar() {
19041906
// No hint for lambda for now
1905-
auto f = []() {
1906-
return X;
1907+
auto f = []() {
1908+
return X;
19071909
};
1908-
return f();
1910+
return f();
19091911
$bar[[}]]
19101912
19111913
// No hint because this isn't a definition
@@ -1926,7 +1928,7 @@ TEST(BlockEndHints, Methods) {
19261928
struct Test {
19271929
// No hint because there's no function body
19281930
Test() = default;
1929-
1931+
19301932
~Test() {
19311933
$dtor[[}]]
19321934
@@ -2229,7 +2231,7 @@ TEST(BlockEndHints, TrailingSemicolon) {
22292231
assertBlockEndHints(R"cpp(
22302232
// The hint is placed after the trailing ';'
22312233
struct S1 {
2232-
$S1[[} ;]]
2234+
$S1[[} ;]]
22332235
22342236
// The hint is always placed in the same line with the closing '}'.
22352237
// So in this case where ';' is missing, it is attached to '}'.
@@ -2250,7 +2252,7 @@ TEST(BlockEndHints, TrailingSemicolon) {
22502252
struct {
22512253
int x;
22522254
$anon[[}]]
2253-
2255+
22542256
s2;
22552257
)cpp",
22562258
ExpectedHint{" // struct S1", "S1"},

clang/include/clang/Sema/Sema.h

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8754,7 +8754,8 @@ class Sema final : public SemaBase {
87548754

87558755
ExprResult BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow,
87568756
SourceLocation OpLoc,
8757-
const CXXScopeSpec &SS, FieldDecl *Field,
8757+
const NestedNameSpecifierLoc &NNS,
8758+
FieldDecl *Field, QualType FieldType,
87588759
DeclAccessPair FoundDecl,
87598760
const DeclarationNameInfo &MemberNameInfo);
87608761

@@ -8765,7 +8766,8 @@ class Sema final : public SemaBase {
87658766
const CXXScopeSpec &SS, SourceLocation nameLoc,
87668767
IndirectFieldDecl *indirectField,
87678768
DeclAccessPair FoundDecl = DeclAccessPair::make(nullptr, AS_none),
8768-
Expr *baseObjectExpr = nullptr, SourceLocation opLoc = SourceLocation());
8769+
Expr *baseObjectExpr = nullptr, const Type *BaseType = nullptr,
8770+
SourceLocation opLoc = SourceLocation());
87698771

87708772
private:
87718773
void CheckMemberAccessOfNoDeref(const MemberExpr *E);
@@ -13994,6 +13996,16 @@ class Sema final : public SemaBase {
1399413996
FunctionDecl *Spaceship);
1399513997

1399613998
QualType resugar(const NestedNameSpecifier *NNS, QualType T);
13999+
QualType resugar(const NestedNameSpecifier *NNS, NamedDecl *ND,
14000+
ArrayRef<TemplateArgument> Args, QualType T);
14001+
QualType resugar(NamedDecl *ND, ArrayRef<TemplateArgument> Args, QualType T);
14002+
QualType resugar(const Type *Base, const NestedNameSpecifier *FieldNNS,
14003+
QualType T);
14004+
QualType resugar(const Type *Base, const NestedNameSpecifier *FieldNNS,
14005+
NamedDecl *ND, ArrayRef<TemplateArgument> Args, QualType T);
14006+
QualType resugar(const Type *Base, QualType T);
14007+
QualType resugar(const Type *Base, NamedDecl *ND,
14008+
ArrayRef<TemplateArgument> Args, QualType T);
1399714009

1399814010
/// Performs template instantiation for all implicit template
1399914011
/// instantiations we have seen until this point.

clang/lib/Sema/SemaChecking.cpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -649,9 +649,11 @@ struct BuiltinDumpStructGenerator {
649649
if (!FD || FD->isUnnamedBitField() || FD->isAnonymousStructOrUnion())
650650
continue;
651651

652+
QualType FieldType = FD->getType();
653+
652654
llvm::SmallString<20> Format = llvm::StringRef("%s%s %s ");
653655
llvm::SmallVector<Expr *, 5> Args = {FieldIndentArg,
654-
getTypeString(FD->getType()),
656+
getTypeString(FieldType),
655657
getStringLiteral(FD->getName())};
656658

657659
if (FD->isBitField()) {
@@ -667,15 +669,16 @@ struct BuiltinDumpStructGenerator {
667669
ExprResult Field =
668670
IFD ? S.BuildAnonymousStructUnionMemberReference(
669671
CXXScopeSpec(), Loc, IFD,
670-
DeclAccessPair::make(IFD, AS_public), RecordArg, Loc)
672+
DeclAccessPair::make(IFD, AS_public), RecordArg, nullptr,
673+
Loc)
671674
: S.BuildFieldReferenceExpr(
672-
RecordArg, RecordArgIsPtr, Loc, CXXScopeSpec(), FD,
673-
DeclAccessPair::make(FD, AS_public),
675+
RecordArg, RecordArgIsPtr, Loc, NestedNameSpecifierLoc(),
676+
FD, FieldType, DeclAccessPair::make(FD, AS_public),
674677
DeclarationNameInfo(FD->getDeclName(), Loc));
675678
if (Field.isInvalid())
676679
return true;
677680

678-
auto *InnerRD = FD->getType()->getAsRecordDecl();
681+
auto *InnerRD = FieldType->getAsRecordDecl();
679682
auto *InnerCXXRD = dyn_cast_or_null<CXXRecordDecl>(InnerRD);
680683
if (InnerRD && (!InnerCXXRD || InnerCXXRD->isAggregate())) {
681684
// Recursively print the values of members of aggregate record type.
@@ -684,7 +687,7 @@ struct BuiltinDumpStructGenerator {
684687
return true;
685688
} else {
686689
Format += " ";
687-
if (appendFormatSpecifier(FD->getType(), Format)) {
690+
if (appendFormatSpecifier(FieldType, Format)) {
688691
// We know how to print this field.
689692
Args.push_back(Field.get());
690693
} else {

clang/lib/Sema/SemaCoroutine.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ static ExprResult buildCoroutineHandle(Sema &S, QualType PromiseType,
287287
S.BuildDeclarationNameExpr(SS, Found, /*NeedsADL=*/false);
288288
if (FromAddr.isInvalid())
289289
return ExprError();
290-
290+
// FIXME: resugar
291291
return S.BuildCallExpr(nullptr, FromAddr.get(), Loc, FramePtr, Loc);
292292
}
293293

clang/lib/Sema/SemaDecl.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13129,6 +13129,7 @@ bool Sema::DeduceVariableDeclarationType(VarDecl *VDecl, bool DirectInit,
1312913129
return true;
1313013130
}
1313113131

13132+
// FIXME: Set TypeSourceInfo?
1313213133
VDecl->setType(DeducedType);
1313313134
assert(VDecl->isLinkageValid());
1313413135

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3637,6 +3637,7 @@ static void handleCleanupAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
36373637

36383638
// We're currently more strict than GCC about what function types we accept.
36393639
// If this ever proves to be a problem it should be easy to fix.
3640+
// FIXME: resugar
36403641
QualType Ty = S.Context.getPointerType(cast<VarDecl>(D)->getType());
36413642
QualType ParamTy = FD->getParamDecl(0)->getType();
36423643
if (S.CheckAssignmentConstraints(FD->getParamDecl(0)->getLocation(),

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1556,6 +1556,9 @@ static bool checkMemberDecomposition(Sema &S, ArrayRef<BindingDecl*> Bindings,
15561556
if (FD->isUnnamedBitField())
15571557
continue;
15581558

1559+
// FIXME: Avoid having to recreate the naming context for every field.
1560+
QualType FieldType = S.resugar(DecompType.getTypePtr(), FD->getType());
1561+
15591562
// We have a real field to bind.
15601563
assert(FlatBindingsItr != FlatBindings.end());
15611564
BindingDecl *B = *(FlatBindingsItr++);
@@ -1570,7 +1573,7 @@ static bool checkMemberDecomposition(Sema &S, ArrayRef<BindingDecl*> Bindings,
15701573
if (E.isInvalid())
15711574
return true;
15721575
E = S.BuildFieldReferenceExpr(E.get(), /*IsArrow*/ false, Loc,
1573-
CXXScopeSpec(), FD,
1576+
NestedNameSpecifierLoc(), FD, FieldType,
15741577
DeclAccessPair::make(FD, FD->getAccess()),
15751578
DeclarationNameInfo(FD->getDeclName(), Loc));
15761579
if (E.isInvalid())
@@ -1584,7 +1587,7 @@ static bool checkMemberDecomposition(Sema &S, ArrayRef<BindingDecl*> Bindings,
15841587
Qualifiers Q = DecompType.getQualifiers();
15851588
if (FD->isMutable())
15861589
Q.removeConst();
1587-
B->setBinding(S.BuildQualifiedType(FD->getType(), Loc, Q), E.get());
1590+
B->setBinding(S.BuildQualifiedType(FieldType, Loc, Q), E.get());
15881591
}
15891592

15901593
return false;
@@ -8637,10 +8640,13 @@ class DefaultedComparisonSynthesizer
86378640

86388641
DeclAccessPair Found = DeclAccessPair::make(Field, Field->getAccess());
86398642
DeclarationNameInfo NameInfo(Field->getDeclName(), Loc);
8643+
QualType FieldType = Field->getType();
86408644
return {S.BuildFieldReferenceExpr(Obj.first.get(), /*IsArrow=*/false, Loc,
8641-
CXXScopeSpec(), Field, Found, NameInfo),
8645+
NestedNameSpecifierLoc(), Field,
8646+
FieldType, Found, NameInfo),
86428647
S.BuildFieldReferenceExpr(Obj.second.get(), /*IsArrow=*/false, Loc,
8643-
CXXScopeSpec(), Field, Found, NameInfo)};
8648+
NestedNameSpecifierLoc(), Field,
8649+
FieldType, Found, NameInfo)};
86448650
}
86458651

86468652
// FIXME: When expanding a subobject, register a note in the code synthesis

clang/lib/Sema/SemaExpr.cpp

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3224,6 +3224,7 @@ ExprResult Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
32243224
if (!NeedsADL && R.isSingleResult() &&
32253225
!R.getAsSingle<FunctionTemplateDecl>() &&
32263226
!ShouldLookupResultBeMultiVersionOverload(R))
3227+
// FIXME: get ConvertedArgs
32273228
return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(), R.getFoundDecl(),
32283229
R.getRepresentativeDecl(), nullptr, nullptr,
32293230
AcceptInvalidDecl);
@@ -3308,6 +3309,10 @@ ExprResult Sema::BuildDeclarationNameExpr(
33083309
QualType type = VD->getType();
33093310
if (type.isNull())
33103311
return ExprError();
3312+
assert(!TemplateArgs || ConvertedArgs);
3313+
type = ConvertedArgs
3314+
? resugar(SS.getScopeRep(), VD, ConvertedArgs->asArray(), type)
3315+
: resugar(SS.getScopeRep(), type);
33113316
ExprValueKind valueKind = VK_PRValue;
33123317

33133318
// In 'T ...V;', the type of the declaration 'V' is 'T...', but the type of
@@ -19865,10 +19870,30 @@ static void DoMarkVarDeclReferenced(
1986519870

1986619871
// Re-set the member to trigger a recomputation of the dependence bits
1986719872
// for the expression.
19868-
if (auto *DRE = dyn_cast_or_null<DeclRefExpr>(E))
19873+
CXXScopeSpec SS;
19874+
if (auto *DRE = dyn_cast_or_null<DeclRefExpr>(E)) {
1986919875
DRE->setDecl(DRE->getDecl());
19870-
else if (auto *ME = dyn_cast_or_null<MemberExpr>(E))
19876+
SS.Adopt(DRE->getQualifierLoc());
19877+
assert(DRE->template_arguments().size() == 0 ||
19878+
DRE->getConvertedArgs() != nullptr);
19879+
QualType T = DRE->getConvertedArgs()
19880+
? SemaRef.resugar(SS.getScopeRep(), DRE->getDecl(),
19881+
DRE->getConvertedArgs()->asArray(),
19882+
DRE->getType())
19883+
: SemaRef.resugar(SS.getScopeRep(), DRE->getType());
19884+
DRE->setType(T);
19885+
} else if (auto *ME = dyn_cast_or_null<MemberExpr>(E)) {
1987119886
ME->setMemberDecl(ME->getMemberDecl());
19887+
SS.Adopt(ME->getQualifierLoc());
19888+
assert(ME->template_arguments().size() == 0 ||
19889+
ME->getDeduced() != nullptr);
19890+
QualType T =
19891+
ME->getDeduced()
19892+
? SemaRef.resugar(SS.getScopeRep(), ME->getMemberDecl(),
19893+
ME->getDeduced()->asArray(), ME->getType())
19894+
: SemaRef.resugar(SS.getScopeRep(), ME->getType());
19895+
ME->setType(T);
19896+
}
1987219897
} else if (FirstInstantiation) {
1987319898
SemaRef.PendingInstantiations
1987419899
.push_back(std::make_pair(Var, PointOfInstantiation));
@@ -21170,6 +21195,7 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
2117021195
SS.Adopt(DRE->getQualifierLoc());
2117121196
TemplateArgumentListInfo TemplateArgs;
2117221197
DRE->copyTemplateArgumentsInto(TemplateArgs);
21198+
// FIXME: resugar
2117321199
return BuildDeclRefExpr(
2117421200
FD, FD->getType(), VK_LValue, DRE->getNameInfo(),
2117521201
DRE->hasQualifier() ? &SS : nullptr, DRE->getFoundDecl(),

0 commit comments

Comments
 (0)