Skip to content

Commit a3fd6cc

Browse files
committed
This is really a reference (microsoft#5473)
This fixes a few cases that were missed when I updated `this` objects to be references. Specifically we were still generating some implicit `this` cases as pointers, and we were not always correctly looking through the reference types. Fixes microsoft#4709
1 parent a7efdff commit a3fd6cc

File tree

11 files changed

+159
-20
lines changed

11 files changed

+159
-20
lines changed

tools/clang/include/clang/AST/DeclCXX.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1830,6 +1830,13 @@ class CXXMethodDecl : public FunctionDecl {
18301830
/// Should only be called for instance (i.e., non-static) methods.
18311831
QualType getThisType(ASTContext &C) const;
18321832

1833+
// HLSL Change Begin - This is a reference.
1834+
/// \brief Returns the type of the \c this object looking through the pointer.
1835+
///
1836+
/// Should only be called for instance (i.e., non-static) methods.
1837+
QualType getThisObjectType(ASTContext &C) const;
1838+
// HLSL Change End - This is a reference.
1839+
18331840
unsigned getTypeQualifiers() const {
18341841
return getType()->getAs<FunctionProtoType>()->getTypeQuals();
18351842
}

tools/clang/lib/AST/DeclCXX.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1603,9 +1603,18 @@ QualType CXXMethodDecl::getThisType(ASTContext &C) const {
16031603
QualType ClassTy = C.getTypeDeclType(getParent());
16041604
ClassTy = C.getQualifiedType(ClassTy,
16051605
Qualifiers::fromCVRMask(getTypeQualifiers()));
1606-
return C.getPointerType(ClassTy);
1606+
return C.getLangOpts().HLSL ? C.getLValueReferenceType(ClassTy) : C.getPointerType(ClassTy);
16071607
}
16081608

1609+
// HLSL Change Begin - This is a reference.
1610+
QualType CXXMethodDecl::getThisObjectType(ASTContext &C) const {
1611+
QualType ClassTy = C.getTypeDeclType(getParent());
1612+
ClassTy = C.getQualifiedType(ClassTy,
1613+
Qualifiers::fromCVRMask(getTypeQualifiers()));
1614+
return ClassTy;
1615+
}
1616+
// HLSL Change End - This is a reference.
1617+
16091618
bool CXXMethodDecl::hasInlineBody() const {
16101619
// If this function is a template instantiation, look at the template from
16111620
// which it was instantiated.

tools/clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1557,8 +1557,10 @@ void CodeGenModule::CompleteDIClassType(const CXXMethodDecl* D) {
15571557

15581558
if (CGDebugInfo *DI = getModuleDebugInfo())
15591559
if (getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo) {
1560-
const auto *ThisPtr = cast<PointerType>(D->getThisType(getContext()));
1561-
DI->getOrCreateRecordType(ThisPtr->getPointeeType(), D->getLocation());
1560+
// HLSL Change Begin - This is a reference.
1561+
QualType ThisType = D->getThisObjectType(getContext());
1562+
DI->getOrCreateRecordType(ThisType, D->getLocation());
1563+
// HLSL Change End - This is a reference.
15621564
}
15631565
}
15641566

tools/clang/lib/Sema/SemaExpr.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1910,13 +1910,15 @@ Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
19101910

19111911
CXXScopeSpec SS;
19121912
SS.Adopt(ULE->getQualifierLoc());
1913+
// HLSL Change Begin - This is a reference.
19131914
CXXDependentScopeMemberExpr *DepExpr =
19141915
CXXDependentScopeMemberExpr::Create(
1915-
Context, DepThis, DepThisType, true, SourceLocation(),
1916-
SS.getWithLocInContext(Context),
1917-
ULE->getTemplateKeywordLoc(), nullptr,
1918-
R.getLookupNameInfo(),
1916+
Context, DepThis, DepThisType,
1917+
/*IsArrow*/ !getLangOpts().HLSL, SourceLocation(),
1918+
SS.getWithLocInContext(Context), ULE->getTemplateKeywordLoc(),
1919+
nullptr, R.getLookupNameInfo(),
19191920
ULE->hasExplicitTemplateArgs() ? &TList : nullptr);
1921+
// HLSL Change End - This is a reference.
19201922
CallsUndergoingInstantiation.back()->setCallee(DepExpr);
19211923
} else {
19221924
Diag(R.getNameLoc(), diagnostic) << Name;
@@ -2100,6 +2102,12 @@ recoverFromMSUnqualifiedLookup(Sema &S, ASTContext &Context,
21002102
DB << NameInfo.getName() << RD;
21012103

21022104
if (!ThisType.isNull()) {
2105+
// HLSL Change Begin - This code is broken because `this` is a reference in
2106+
// HLSL, but this code should also be unreachable.
2107+
assert(!S.getLangOpts().HLSL &&
2108+
"This should be unreachable in DXC because we don't enable the "
2109+
"MSCompat language feature.");
2110+
// HLSL Change End
21032111
DB << FixItHint::CreateInsertion(Loc, "this->");
21042112
return CXXDependentScopeMemberExpr::Create(
21052113
Context, /*This=*/nullptr, ThisType, /*IsArrow=*/true,

tools/clang/lib/Sema/SemaExprCXX.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -970,7 +970,7 @@ ExprResult Sema::ActOnCXXThis(SourceLocation Loc) {
970970

971971
CheckCXXThisCapture(Loc);
972972
// HLSL Change Starts - adjust this from T* to T&-like
973-
if (getLangOpts().HLSL && ThisTy.getTypePtr()->isPointerType()) {
973+
if (getLangOpts().HLSL) {
974974
return genereateHLSLThis(Loc, ThisTy, /*isImplicit=*/false);
975975
}
976976
// HLSL Change Ends
@@ -982,10 +982,10 @@ CXXThisExpr *Sema::genereateHLSLThis(SourceLocation Loc, QualType ThisType,
982982
bool isImplicit) {
983983
// Expressions cannot be of reference type - instead, they yield
984984
// an lvalue on the underlying type.
985-
const Type *TypePtr = ThisType.getTypePtr();
986-
CXXThisExpr *ResultExpr = new (Context) CXXThisExpr(
987-
Loc, TypePtr->isPointerType() ? TypePtr->getPointeeType() : ThisType,
988-
isImplicit);
985+
if (ThisType->isPointerType() || ThisType->isReferenceType())
986+
ThisType = ThisType->getPointeeType();
987+
CXXThisExpr *ResultExpr =
988+
new (Context) CXXThisExpr(Loc, ThisType, isImplicit);
989989
ResultExpr->setValueKind(ExprValueKind::VK_LValue);
990990
return ResultExpr;
991991
}

tools/clang/lib/Sema/SemaExprMember.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,7 @@ bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr,
507507
QualType BaseType,
508508
const CXXScopeSpec &SS,
509509
const LookupResult &R) {
510+
BaseType = BaseType.getNonReferenceType(); // HLSL Change
510511
CXXRecordDecl *BaseRecord =
511512
cast_or_null<CXXRecordDecl>(computeDeclContext(BaseType));
512513
if (!BaseRecord) {
@@ -704,6 +705,7 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
704705
TypoExpr *TE = nullptr;
705706
QualType RecordTy = BaseType;
706707
if (IsArrow) RecordTy = RecordTy->getAs<PointerType>()->getPointeeType();
708+
RecordTy = RecordTy.getNonReferenceType(); // HLSL Change - implicit this is a reference.
707709
if (LookupMemberExprInRecord(*this, R, nullptr,
708710
RecordTy->getAs<RecordType>(), OpLoc, IsArrow,
709711
SS, TemplateArgs != nullptr, TE))
@@ -1051,7 +1053,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
10511053
CheckCXXThisCapture(Loc);
10521054

10531055
// HLSL Change Starts - adjust this from T* to T&-like
1054-
if (getLangOpts().HLSL && BaseExprType->isPointerType())
1056+
if (getLangOpts().HLSL)
10551057
BaseExpr = genereateHLSLThis(Loc, BaseExprType, /*isImplicit=*/true);
10561058
else
10571059
BaseExpr = new (Context) CXXThisExpr(Loc, BaseExprType,/*isImplicit=*/true);
@@ -1768,9 +1770,9 @@ Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS,
17681770
if (SS.getRange().isValid())
17691771
Loc = SS.getRange().getBegin();
17701772
CheckCXXThisCapture(Loc);
1771-
if (getLangOpts().HLSL && ThisTy->isPointerType()) {
1773+
if (getLangOpts().HLSL) {
17721774
baseExpr = genereateHLSLThis(Loc, ThisTy, /*isImplicit=*/true);
1773-
ThisTy = ThisTy->getAs<PointerType>()->getPointeeType();
1775+
ThisTy = ThisTy->getPointeeType();
17741776
} else
17751777
baseExpr = new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/true);
17761778
}

tools/clang/lib/Sema/SemaOverload.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4987,8 +4987,8 @@ Sema::PerformObjectArgumentInitialization(Expr *From,
49874987
NamedDecl *FoundDecl,
49884988
CXXMethodDecl *Method) {
49894989
QualType FromRecordType, DestType;
4990-
QualType ImplicitParamRecordType =
4991-
Method->getThisType(Context)->getAs<PointerType>()->getPointeeType();
4990+
// HLSL Change - this is a reference.
4991+
QualType ImplicitParamRecordType = Method->getThisObjectType(Context);
49924992

49934993
Expr::Classification FromClassification;
49944994
if (const PointerType *PT = From->getType()->getAs<PointerType>()) {

tools/clang/lib/Sema/SemaTemplate.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -420,10 +420,12 @@ Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS,
420420
// perform the double-lookup check.
421421
NamedDecl *FirstQualifierInScope = nullptr;
422422

423+
// HLSL Change begin - This is a reference.
423424
return CXXDependentScopeMemberExpr::Create(
424-
Context, /*This*/ nullptr, ThisType, /*IsArrow*/ true,
425+
Context, /*This*/ nullptr, ThisType, /*IsArrow*/ !getLangOpts().HLSL,
425426
/*Op*/ SourceLocation(), SS.getWithLocInContext(Context), TemplateKWLoc,
426427
FirstQualifierInScope, NameInfo, TemplateArgs);
428+
// HLSL Change end - This is a reference.
427429
}
428430

429431
return BuildDependentDeclRefExpr(SS, TemplateKWLoc, NameInfo, TemplateArgs);

tools/clang/lib/Sema/TreeTransform.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2344,7 +2344,7 @@ class TreeTransform {
23442344
bool isImplicit) {
23452345
getSema().CheckCXXThisCapture(ThisLoc);
23462346
// HLSL Change Begin - adjust this from T* to T&-like
2347-
if (getSema().getLangOpts().HLSL && ThisType.getTypePtr()->isPointerType())
2347+
if (getSema().getLangOpts().HLSL)
23482348
return getSema().genereateHLSLThis(ThisLoc, ThisType, isImplicit);
23492349
// HLSL Change End - adjust this from T* to T&-like
23502350
return new (getSema().Context) CXXThisExpr(ThisLoc, ThisType, isImplicit);
@@ -9777,7 +9777,7 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr(
97779777
} else {
97789778
OldBase = nullptr;
97799779
BaseType = getDerived().TransformType(E->getBaseType());
9780-
ObjectType = BaseType->getAs<PointerType>()->getPointeeType();
9780+
ObjectType = BaseType->getPointeeType();
97819781
}
97829782

97839783
// Transform the first part of the nested-name-specifier that qualifies
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// RUN: %dxc -T lib_6_4 -HV 2021 %s -ast-dump | FileCheck %s -check-prefix=AST
2+
// RUN: %dxc -T lib_6_4 -HV 2021 %s -fcgl | FileCheck %s
3+
4+
// This test verifies two things. First it verifies that the AST instantiates a
5+
// correct AST where the `CXXThisExpr` is an lvalue of type array_ext<float, 3>
6+
// rather than a pointer (as C++ would have).
7+
8+
// Secondarily it verifies that the code geneariton for the `this` reference
9+
// correctly resolves to the base pointer and indexes off the base class member.
10+
11+
// AST: ClassTemplateDecl {{.*}} array_ext
12+
// AST-NEXT: TemplateTypeParmDecl {{.*}} referenced typename T
13+
// AST-NEXT: NonTypeTemplateParmDecl {{.*}} referenced 'uint32_t':'unsigned int' N
14+
// AST-NEXT: CXXRecordDecl {{.*}} class array_ext definition
15+
// AST-NEXT: public 'array<T, N>'
16+
17+
// AST: ClassTemplateSpecializationDecl {{.*}} class array_ext definition
18+
// AST: TemplateArgument type 'float'
19+
// AST-NEXT: TemplateArgument integral 3
20+
// AST-NEXT: CXXRecordDecl {{.*}} implicit class array_ext
21+
// AST-NEXT: CXXMethodDecl {{.*}} used test 'float ()'
22+
// AST-NEXT: CompoundStmt
23+
// AST-NEXT: ReturnStmt
24+
// AST-NEXT: ImplicitCastExpr {{.*}} 'float':'float' <LValueToRValue>
25+
// AST-NEXT: ArraySubscriptExpr {{.*}} 'float':'float' lvalue
26+
27+
// Note: the implicit LValueToRvalue casts below are nonsensical as noted by them
28+
// producing lvalues. This test verifies them only to ensure the correct ASTs
29+
// around the casts. The casts themselves might be removed or changed in a
30+
// future change.
31+
32+
// AST-NEXT: ImplicitCastExpr {{.*}} 'float [3]' <LValueToRValue>
33+
// AST-NEXT: MemberExpr {{.*}} 'float [3]' lvalue .mArr
34+
// AST-NEXT: ImplicitCastExpr {{.*}} 'array<float, 3U>':'array<float, 3>' lvalue <UncheckedDerivedToBase (array)>
35+
// AST-NEXT: CXXThisExpr {{.* }}'array_ext<float, 3>' lvalue this
36+
// AST-NEXT: IntegerLiteral {{.*}} 'literal int' 0
37+
38+
template <typename T, uint32_t N> class array { T mArr[N]; };
39+
40+
template <typename T, uint32_t N> class array_ext : array<T, N> {
41+
float test() { return array<T, N>::mArr[0]; }
42+
};
43+
44+
// CHECK: define linkonce_odr float @"\01?test@?$array_ext@{{.*}}"(%"class.array_ext<float, 3>"* [[this:%.+]])
45+
// CHECK: [[basePtr:%[0-9]+]] = bitcast %"class.array_ext<float, 3>"* [[this]] to %"class.array<float, 3>"*
46+
// CHECK: [[mArr:%.+]] = getelementptr inbounds %"class.array<float, 3>", %"class.array<float, 3>"* [[basePtr]], i32 0, i32 0
47+
// CHECK: [[elemPtr:%.+]] = getelementptr inbounds [3 x float], [3 x float]* [[mArr]], i32 0, i32 0
48+
// CHECK: [[Val:%.+]] = load float, float* [[elemPtr]]
49+
// CHECK: ret float [[Val]]
50+
51+
// This function only exists to force instantiation of the template.
52+
float fn() {
53+
array_ext<float, 3> arr1;
54+
return arr1.test();
55+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// RUN: %dxc -T lib_6_6 %s -HV 2018 -ast-dump | FileCheck %s -check-prefix=AST
2+
// RUN: %dxc -T lib_6_6 %s -HV 2018 -fcgl | FileCheck %s
3+
// RUN: %dxc -T lib_6_6 %s -HV 2021 -ast-dump | FileCheck %s -check-prefix=AST
4+
// RUN: %dxc -T lib_6_6 %s -HV 2021 -fcgl | FileCheck %s
5+
6+
// This test verifies two things, and it verifies them each under both HLSL 2018
7+
// and HLSL 2021 language modes. The behavior between the two modes should not
8+
// differ.
9+
10+
// The first thing this verifies is that the AST formulation for
11+
// `array_ext::test` uses the `this` reference as an lvalue of type `array_ext`
12+
// rather than a pointer (as C++ would).
13+
14+
// The second part of this test is to verify the code generation to verify that
15+
// the base class address is resolved and that the member is indexed off the
16+
// base class as expected.
17+
18+
// AST: CXXRecordDecl {{.*}} referenced class array definition
19+
// AST-NEXT: CXXRecordDecl {{.*}} implicit class array
20+
// AST-NEXT: FieldDecl {{.*}} referenced mArr 'float [4]'
21+
// AST-NEXT: CXXRecordDecl {{.*}} class array_ext definition
22+
// AST-NEXT: public 'array'
23+
// AST-NEXT: CXXRecordDecl {{.*}} implicit class array_ext
24+
// AST-NEXT: CXXMethodDecl {{.*}} test 'float ()'
25+
// AST-NEXT: CompoundStmt
26+
// AST-NEXT: ReturnStmt
27+
// AST-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
28+
// AST-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue
29+
// AST-NEXT: ImplicitCastExpr {{.*}} 'float [4]' <LValueToRValue>
30+
// AST-NEXT: MemberExpr {{.*}} 'float [4]' lvalue .mArr
31+
// AST-NEXT: ImplicitCastExpr {{.*}} 'array' lvalue <UncheckedDerivedToBase (array)>
32+
// AST-NEXT: CXXThisExpr {{.*}} 'array_ext' lvalue this
33+
// AST-NEXT: IntegerLiteral {{.*}} 'literal int' 0
34+
35+
class array {
36+
float mArr[4];
37+
};
38+
39+
class array_ext : array {
40+
float test() { return array::mArr[0]; }
41+
};
42+
43+
// CHECK: define linkonce_odr float @"\01?test@array_ext@{{.*}}"(%class.array_ext* [[this:%.+]])
44+
// CHECK: [[basePtr:%[0-9]+]] = bitcast %class.array_ext* [[this]] to %class.array*
45+
// CHECK: [[mArr:%.+]] = getelementptr inbounds %class.array, %class.array* [[basePtr]], i32 0, i32 0
46+
// CHECK: [[elemPtr:%.+]] = getelementptr inbounds [4 x float], [4 x float]* [[mArr]], i32 0, i32 0
47+
// CHECK: [[Val:%.+]] = load float, float* [[elemPtr]]
48+
// CHECK: ret float [[Val]]
49+
50+
// This function only exists to force generation of the internal methods
51+
float fn() {
52+
array_ext arr1;
53+
return arr1.test();
54+
}

0 commit comments

Comments
 (0)