Skip to content

Commit aa3cc42

Browse files
committed
[Clang] Use TargetInfo when deciding is an address space is compatible
Summary: Address spaces are used in several embedded and GPU targets to describe accesses to different types of memory. Currently we use the address space enumerations to control which address spaces are considered supersets of eachother, however this is also a target level property as described by the C standard's passing mentions. This patch allows the address space checks to use the target information to decide if a pointer conversion is legal. For AMDGPU and NVPTX, all supported address spaces can be converted to the default address space. More semantic checks can be added on top of this, for now I'm mainly looking to get more standard semantics working for C/C++. Right now the address space conversions must all be done explicitly in C/C++ unlike the offloading languages which define their own custom address spaces that just map to the same target specific ones anyway. The main question is if this behavior is a function of the target or the language.
1 parent e68c454 commit aa3cc42

19 files changed

+321
-107
lines changed

clang-tools-extra/clang-tidy/bugprone/VirtualNearMissCheck.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ static bool checkOverridingFunctionReturnType(const ASTContext *Context,
112112

113113
// The class type D should have the same cv-qualification as or less
114114
// cv-qualification than the class type B.
115-
if (DTy.isMoreQualifiedThan(BTy))
115+
if (DTy.isMoreQualifiedThan(BTy, Context->getTargetInfo()))
116116
return false;
117117

118118
return true;

clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -299,10 +299,11 @@ static bool applyDiceHeuristic(StringRef Arg, StringRef Param,
299299

300300
/// Checks if ArgType binds to ParamType regarding reference-ness and
301301
/// cv-qualifiers.
302-
static bool areRefAndQualCompatible(QualType ArgType, QualType ParamType) {
302+
static bool areRefAndQualCompatible(QualType ArgType, QualType ParamType,
303+
const ASTContext &Ctx) {
303304
return !ParamType->isReferenceType() ||
304305
ParamType.getNonReferenceType().isAtLeastAsQualifiedAs(
305-
ArgType.getNonReferenceType());
306+
ArgType.getNonReferenceType(), Ctx.getTargetInfo());
306307
}
307308

308309
static bool isPointerOrArray(QualType TypeToCheck) {
@@ -311,12 +312,12 @@ static bool isPointerOrArray(QualType TypeToCheck) {
311312

312313
/// Checks whether ArgType is an array type identical to ParamType's array type.
313314
/// Enforces array elements' qualifier compatibility as well.
314-
static bool isCompatibleWithArrayReference(QualType ArgType,
315-
QualType ParamType) {
315+
static bool isCompatibleWithArrayReference(QualType ArgType, QualType ParamType,
316+
const ASTContext &Ctx) {
316317
if (!ArgType->isArrayType())
317318
return false;
318319
// Here, qualifiers belong to the elements of the arrays.
319-
if (!ParamType.isAtLeastAsQualifiedAs(ArgType))
320+
if (!ParamType.isAtLeastAsQualifiedAs(ArgType, Ctx.getTargetInfo()))
320321
return false;
321322

322323
return ParamType.getUnqualifiedType() == ArgType.getUnqualifiedType();
@@ -342,12 +343,13 @@ static QualType convertToPointeeOrArrayElementQualType(QualType TypeToConvert) {
342343
/// every * in ParamType to the right of that cv-qualifier, except the last
343344
/// one, must also be const-qualified.
344345
static bool arePointersStillQualCompatible(QualType ArgType, QualType ParamType,
345-
bool &IsParamContinuouslyConst) {
346+
bool &IsParamContinuouslyConst,
347+
const ASTContext &Ctx) {
346348
// The types are compatible, if the parameter is at least as qualified as the
347349
// argument, and if it is more qualified, it has to be const on upper pointer
348350
// levels.
349351
bool AreTypesQualCompatible =
350-
ParamType.isAtLeastAsQualifiedAs(ArgType) &&
352+
ParamType.isAtLeastAsQualifiedAs(ArgType, Ctx.getTargetInfo()) &&
351353
(!ParamType.hasQualifiers() || IsParamContinuouslyConst);
352354
// Check whether the parameter's constness continues at the current pointer
353355
// level.
@@ -359,9 +361,10 @@ static bool arePointersStillQualCompatible(QualType ArgType, QualType ParamType,
359361
/// Checks whether multilevel pointers are compatible in terms of levels,
360362
/// qualifiers and pointee type.
361363
static bool arePointerTypesCompatible(QualType ArgType, QualType ParamType,
362-
bool IsParamContinuouslyConst) {
364+
bool IsParamContinuouslyConst,
365+
const ASTContext &Ctx) {
363366
if (!arePointersStillQualCompatible(ArgType, ParamType,
364-
IsParamContinuouslyConst))
367+
IsParamContinuouslyConst, Ctx))
365368
return false;
366369

367370
do {
@@ -372,7 +375,7 @@ static bool arePointerTypesCompatible(QualType ArgType, QualType ParamType,
372375
// Check whether cv-qualifiers permit compatibility on
373376
// current level.
374377
if (!arePointersStillQualCompatible(ArgType, ParamType,
375-
IsParamContinuouslyConst))
378+
IsParamContinuouslyConst, Ctx))
376379
return false;
377380

378381
if (ParamType.getUnqualifiedType() == ArgType.getUnqualifiedType())
@@ -396,7 +399,7 @@ static bool areTypesCompatible(QualType ArgType, QualType ParamType,
396399
return true;
397400

398401
// Check for constness and reference compatibility.
399-
if (!areRefAndQualCompatible(ArgType, ParamType))
402+
if (!areRefAndQualCompatible(ArgType, ParamType, Ctx))
400403
return false;
401404

402405
bool IsParamReference = ParamType->isReferenceType();
@@ -434,7 +437,7 @@ static bool areTypesCompatible(QualType ArgType, QualType ParamType,
434437
// When ParamType is an array reference, ArgType has to be of the same-sized
435438
// array-type with cv-compatible element type.
436439
if (IsParamReference && ParamType->isArrayType())
437-
return isCompatibleWithArrayReference(ArgType, ParamType);
440+
return isCompatibleWithArrayReference(ArgType, ParamType, Ctx);
438441

439442
bool IsParamContinuouslyConst =
440443
!IsParamReference || ParamType.getNonReferenceType().isConstQualified();
@@ -444,7 +447,7 @@ static bool areTypesCompatible(QualType ArgType, QualType ParamType,
444447
ParamType = convertToPointeeOrArrayElementQualType(ParamType);
445448

446449
// Check qualifier compatibility on the next level.
447-
if (!ParamType.isAtLeastAsQualifiedAs(ArgType))
450+
if (!ParamType.isAtLeastAsQualifiedAs(ArgType, Ctx.getTargetInfo()))
448451
return false;
449452

450453
if (ParamType.getUnqualifiedType() == ArgType.getUnqualifiedType())
@@ -472,8 +475,8 @@ static bool areTypesCompatible(QualType ArgType, QualType ParamType,
472475
if (!(ParamType->isAnyPointerType() && ArgType->isAnyPointerType()))
473476
return false;
474477

475-
return arePointerTypesCompatible(ArgType, ParamType,
476-
IsParamContinuouslyConst);
478+
return arePointerTypesCompatible(ArgType, ParamType, IsParamContinuouslyConst,
479+
Ctx);
477480
}
478481

479482
static bool isOverloadedUnaryOrBinarySymbolOperator(const FunctionDecl *FD) {

clang/include/clang/AST/CanonicalType.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -164,14 +164,14 @@ class CanQual {
164164

165165
/// Determines whether this canonical type is more qualified than
166166
/// the @p Other canonical type.
167-
bool isMoreQualifiedThan(CanQual<T> Other) const {
168-
return Stored.isMoreQualifiedThan(Other.Stored);
167+
bool isMoreQualifiedThan(CanQual<T> Other, const TargetInfo &TI) const {
168+
return Stored.isMoreQualifiedThan(Other.Stored, TI);
169169
}
170170

171171
/// Determines whether this canonical type is at least as qualified as
172172
/// the @p Other canonical type.
173-
bool isAtLeastAsQualifiedAs(CanQual<T> Other) const {
174-
return Stored.isAtLeastAsQualifiedAs(Other.Stored);
173+
bool isAtLeastAsQualifiedAs(CanQual<T> Other, const TargetInfo &TI) const {
174+
return Stored.isAtLeastAsQualifiedAs(Other.Stored, TI);
175175
}
176176

177177
/// If the canonical type is a reference type, returns the type that

clang/include/clang/AST/Type.h

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "clang/Basic/PointerAuthOptions.h"
3232
#include "clang/Basic/SourceLocation.h"
3333
#include "clang/Basic/Specifiers.h"
34+
#include "clang/Basic/TargetInfo.h"
3435
#include "clang/Basic/Visibility.h"
3536
#include "llvm/ADT/APInt.h"
3637
#include "llvm/ADT/APSInt.h"
@@ -323,6 +324,7 @@ class PointerAuthQualifier {
323324
/// * Objective C: the GC attributes (none, weak, or strong)
324325
class Qualifiers {
325326
public:
327+
Qualifiers() = default;
326328
enum TQ : uint64_t {
327329
// NOTE: These flags must be kept in sync with DeclSpec::TQ.
328330
Const = 0x1,
@@ -697,7 +699,8 @@ class Qualifiers {
697699
/// every address space is a superset of itself.
698700
/// CL2.0 adds:
699701
/// __generic is a superset of any address space except for __constant.
700-
static bool isAddressSpaceSupersetOf(LangAS A, LangAS B) {
702+
static bool isAddressSpaceSupersetOf(LangAS A, LangAS B,
703+
const TargetInfo &TI) {
701704
// Address spaces must match exactly.
702705
return A == B ||
703706
// Otherwise in OpenCLC v2.0 s6.5.5: every address space except
@@ -722,20 +725,25 @@ class Qualifiers {
722725
// to implicitly cast into the default address space.
723726
(A == LangAS::Default &&
724727
(B == LangAS::cuda_constant || B == LangAS::cuda_device ||
725-
B == LangAS::cuda_shared));
728+
B == LangAS::cuda_shared)) ||
729+
// The AMDPGU and NVPTX targets allow all supported address spaces to
730+
// be casted to the default address space.
731+
(TI.getTriple().isNVPTX() && A == LangAS::Default) ||
732+
(TI.getTriple().isAMDGPU() && A == LangAS::Default);
726733
}
727734

728735
/// Returns true if the address space in these qualifiers is equal to or
729736
/// a superset of the address space in the argument qualifiers.
730-
bool isAddressSpaceSupersetOf(Qualifiers other) const {
731-
return isAddressSpaceSupersetOf(getAddressSpace(), other.getAddressSpace());
737+
bool isAddressSpaceSupersetOf(Qualifiers other, const TargetInfo &TI) const {
738+
return isAddressSpaceSupersetOf(getAddressSpace(), other.getAddressSpace(),
739+
TI);
732740
}
733741

734742
/// Determines if these qualifiers compatibly include another set.
735743
/// Generally this answers the question of whether an object with the other
736744
/// qualifiers can be safely used as an object with these qualifiers.
737-
bool compatiblyIncludes(Qualifiers other) const {
738-
return isAddressSpaceSupersetOf(other) &&
745+
bool compatiblyIncludes(Qualifiers other, const TargetInfo &TI) const {
746+
return isAddressSpaceSupersetOf(other, TI) &&
739747
// ObjC GC qualifiers can match, be added, or be removed, but can't
740748
// be changed.
741749
(getObjCGCAttr() == other.getObjCGCAttr() || !hasObjCGCAttr() ||
@@ -1273,11 +1281,11 @@ class QualType {
12731281

12741282
/// Determine whether this type is more qualified than the other
12751283
/// given type, requiring exact equality for non-CVR qualifiers.
1276-
bool isMoreQualifiedThan(QualType Other) const;
1284+
bool isMoreQualifiedThan(QualType Other, const TargetInfo &TI) const;
12771285

12781286
/// Determine whether this type is at least as qualified as the other
12791287
/// given type, requiring exact equality for non-CVR qualifiers.
1280-
bool isAtLeastAsQualifiedAs(QualType Other) const;
1288+
bool isAtLeastAsQualifiedAs(QualType Other, const TargetInfo &TI) const;
12811289

12821290
QualType getNonReferenceType() const;
12831291

@@ -1425,11 +1433,12 @@ class QualType {
14251433
/// address spaces overlap iff they are they same.
14261434
/// OpenCL C v2.0 s6.5.5 adds:
14271435
/// __generic overlaps with any address space except for __constant.
1428-
bool isAddressSpaceOverlapping(QualType T) const {
1436+
bool isAddressSpaceOverlapping(QualType T, const TargetInfo &TI) const {
14291437
Qualifiers Q = getQualifiers();
14301438
Qualifiers TQ = T.getQualifiers();
14311439
// Address spaces overlap if at least one of them is a superset of another
1432-
return Q.isAddressSpaceSupersetOf(TQ) || TQ.isAddressSpaceSupersetOf(Q);
1440+
return Q.isAddressSpaceSupersetOf(TQ, TI) ||
1441+
TQ.isAddressSpaceSupersetOf(Q, TI);
14331442
}
14341443

14351444
/// Returns gc attribute of this type.
@@ -8112,24 +8121,26 @@ inline FunctionType::ExtInfo getFunctionExtInfo(QualType t) {
81128121
/// is more qualified than "const int", "volatile int", and
81138122
/// "int". However, it is not more qualified than "const volatile
81148123
/// int".
8115-
inline bool QualType::isMoreQualifiedThan(QualType other) const {
8124+
inline bool QualType::isMoreQualifiedThan(QualType other,
8125+
const TargetInfo &TI) const {
81168126
Qualifiers MyQuals = getQualifiers();
81178127
Qualifiers OtherQuals = other.getQualifiers();
8118-
return (MyQuals != OtherQuals && MyQuals.compatiblyIncludes(OtherQuals));
8128+
return (MyQuals != OtherQuals && MyQuals.compatiblyIncludes(OtherQuals, TI));
81198129
}
81208130

81218131
/// Determine whether this type is at last
81228132
/// as qualified as the Other type. For example, "const volatile
81238133
/// int" is at least as qualified as "const int", "volatile int",
81248134
/// "int", and "const volatile int".
8125-
inline bool QualType::isAtLeastAsQualifiedAs(QualType other) const {
8135+
inline bool QualType::isAtLeastAsQualifiedAs(QualType other,
8136+
const TargetInfo &TI) const {
81268137
Qualifiers OtherQuals = other.getQualifiers();
81278138

81288139
// Ignore __unaligned qualifier if this type is a void.
81298140
if (getUnqualifiedType()->isVoidType())
81308141
OtherQuals.removeUnaligned();
81318142

8132-
return getQualifiers().compatiblyIncludes(OtherQuals);
8143+
return getQualifiers().compatiblyIncludes(OtherQuals, TI);
81338144
}
81348145

81358146
/// If Type is a reference type (e.g., const

clang/lib/AST/ASTContext.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11405,7 +11405,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, bool OfBlockPointer,
1140511405
Qualifiers RHSPteeQual = RHSPointee.getQualifiers();
1140611406
// Blocks can't be an expression in a ternary operator (OpenCL v2.0
1140711407
// 6.12.5) thus the following check is asymmetric.
11408-
if (!LHSPteeQual.isAddressSpaceSupersetOf(RHSPteeQual))
11408+
if (!LHSPteeQual.isAddressSpaceSupersetOf(RHSPteeQual, getTargetInfo()))
1140911409
return {};
1141011410
LHSPteeQual.removeAddressSpace();
1141111411
RHSPteeQual.removeAddressSpace();

clang/lib/Sema/SemaARM.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -907,7 +907,8 @@ bool SemaARM::CheckARMBuiltinExclusiveCall(unsigned BuiltinID,
907907

908908
// Issue a warning if the cast is dodgy.
909909
CastKind CastNeeded = CK_NoOp;
910-
if (!AddrType.isAtLeastAsQualifiedAs(ValType)) {
910+
if (!AddrType.isAtLeastAsQualifiedAs(ValType,
911+
getASTContext().getTargetInfo())) {
911912
CastNeeded = CK_BitCast;
912913
Diag(DRE->getBeginLoc(), diag::ext_typecheck_convert_discards_qualifiers)
913914
<< PointerArg->getType() << Context.getPointerType(AddrType)

clang/lib/Sema/SemaCast.cpp

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -731,7 +731,8 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType,
731731
*CastAwayQualifiers = SrcCvrQuals - DestCvrQuals;
732732

733733
// If we removed a cvr-qualifier, this is casting away 'constness'.
734-
if (!DestCvrQuals.compatiblyIncludes(SrcCvrQuals)) {
734+
if (!DestCvrQuals.compatiblyIncludes(
735+
SrcCvrQuals, Self.getASTContext().getTargetInfo())) {
735736
if (TheOffendingSrcType)
736737
*TheOffendingSrcType = PrevUnwrappedSrcType;
737738
if (TheOffendingDestType)
@@ -889,7 +890,8 @@ void CastOperation::CheckDynamicCast() {
889890
assert(SrcRecord && "Bad source pointee slipped through.");
890891

891892
// C++ 5.2.7p1: The dynamic_cast operator shall not cast away constness.
892-
if (!DestPointee.isAtLeastAsQualifiedAs(SrcPointee)) {
893+
if (!DestPointee.isAtLeastAsQualifiedAs(
894+
SrcPointee, Self.getASTContext().getTargetInfo())) {
893895
Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_qualifiers_away)
894896
<< CT_Dynamic << OrigSrcType << this->DestType << OpRange;
895897
SrcExpr = ExprError();
@@ -1463,7 +1465,8 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
14631465
SrcPointeeQuals.removeObjCGCAttr();
14641466
SrcPointeeQuals.removeObjCLifetime();
14651467
if (DestPointeeQuals != SrcPointeeQuals &&
1466-
!DestPointeeQuals.compatiblyIncludes(SrcPointeeQuals)) {
1468+
!DestPointeeQuals.compatiblyIncludes(
1469+
SrcPointeeQuals, Self.getASTContext().getTargetInfo())) {
14671470
msg = diag::err_bad_cxx_cast_qualifiers_away;
14681471
return TC_Failed;
14691472
}
@@ -1695,7 +1698,8 @@ TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType,
16951698
// FIXME: Being 100% compliant here would be nice to have.
16961699

16971700
// Must preserve cv, as always, unless we're in C-style mode.
1698-
if (!CStyle && !DestType.isAtLeastAsQualifiedAs(SrcType)) {
1701+
if (!CStyle && !DestType.isAtLeastAsQualifiedAs(
1702+
SrcType, Self.getASTContext().getTargetInfo())) {
16991703
msg = diag::err_bad_cxx_cast_qualifiers_away;
17001704
return TC_Failed;
17011705
}
@@ -2524,7 +2528,8 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
25242528
assert(SrcType->isPointerType() && DestType->isPointerType());
25252529
if (!CStyle &&
25262530
!DestType->getPointeeType().getQualifiers().isAddressSpaceSupersetOf(
2527-
SrcType->getPointeeType().getQualifiers())) {
2531+
SrcType->getPointeeType().getQualifiers(),
2532+
Self.getASTContext().getTargetInfo())) {
25282533
SuccessResult = TC_Failed;
25292534
}
25302535
} else if (IsLValueCast) {
@@ -2631,7 +2636,8 @@ static TryCastResult TryAddressSpaceCast(Sema &Self, ExprResult &SrcExpr,
26312636
return TC_NotApplicable;
26322637
auto SrcPointeeType = SrcPtrType->getPointeeType();
26332638
auto DestPointeeType = DestPtrType->getPointeeType();
2634-
if (!DestPointeeType.isAddressSpaceOverlapping(SrcPointeeType)) {
2639+
if (!DestPointeeType.isAddressSpaceOverlapping(
2640+
SrcPointeeType, Self.getASTContext().getTargetInfo())) {
26352641
msg = diag::err_bad_cxx_cast_addr_space_mismatch;
26362642
return TC_Failed;
26372643
}
@@ -2676,7 +2682,8 @@ void CastOperation::checkAddressSpaceCast(QualType SrcType, QualType DestType) {
26762682
QualType SrcPPointee = SrcPPtr->getPointeeType();
26772683
if (Nested
26782684
? DestPPointee.getAddressSpace() != SrcPPointee.getAddressSpace()
2679-
: !DestPPointee.isAddressSpaceOverlapping(SrcPPointee)) {
2685+
: !DestPPointee.isAddressSpaceOverlapping(
2686+
SrcPPointee, Self.getASTContext().getTargetInfo())) {
26802687
Self.Diag(OpRange.getBegin(), DiagID)
26812688
<< SrcType << DestType << AssignmentAction::Casting
26822689
<< SrcExpr.get()->getSourceRange();

clang/lib/Sema/SemaCodeComplete.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1246,7 +1246,8 @@ enum class OverloadCompare { BothViable, Dominates, Dominated };
12461246
static OverloadCompare compareOverloads(const CXXMethodDecl &Candidate,
12471247
const CXXMethodDecl &Incumbent,
12481248
const Qualifiers &ObjectQuals,
1249-
ExprValueKind ObjectKind) {
1249+
ExprValueKind ObjectKind,
1250+
const TargetInfo &TI) {
12501251
// Base/derived shadowing is handled elsewhere.
12511252
if (Candidate.getDeclContext() != Incumbent.getDeclContext())
12521253
return OverloadCompare::BothViable;
@@ -1280,8 +1281,8 @@ static OverloadCompare compareOverloads(const CXXMethodDecl &Candidate,
12801281
// So make some decision based on the qualifiers.
12811282
Qualifiers CandidateQual = Candidate.getMethodQualifiers();
12821283
Qualifiers IncumbentQual = Incumbent.getMethodQualifiers();
1283-
bool CandidateSuperset = CandidateQual.compatiblyIncludes(IncumbentQual);
1284-
bool IncumbentSuperset = IncumbentQual.compatiblyIncludes(CandidateQual);
1284+
bool CandidateSuperset = CandidateQual.compatiblyIncludes(IncumbentQual, TI);
1285+
bool IncumbentSuperset = IncumbentQual.compatiblyIncludes(CandidateQual, TI);
12851286
if (CandidateSuperset == IncumbentSuperset)
12861287
return OverloadCompare::BothViable;
12871288
return IncumbentSuperset ? OverloadCompare::Dominates
@@ -1450,9 +1451,10 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext,
14501451
CurContext, Method->getDeclName().getAsOpaqueInteger())];
14511452
for (const DeclIndexPair Entry : OverloadSet) {
14521453
Result &Incumbent = Results[Entry.second];
1453-
switch (compareOverloads(*Method,
1454-
*cast<CXXMethodDecl>(Incumbent.Declaration),
1455-
ObjectTypeQualifiers, ObjectKind)) {
1454+
switch (compareOverloads(
1455+
*Method, *cast<CXXMethodDecl>(Incumbent.Declaration),
1456+
ObjectTypeQualifiers, ObjectKind,
1457+
CurContext->getParentASTContext().getTargetInfo())) {
14561458
case OverloadCompare::Dominates:
14571459
// Replace the dominated overload with this one.
14581460
// FIXME: if the overload dominates multiple incumbents then we

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18332,7 +18332,8 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
1833218332

1833318333

1833418334
// The new class type must have the same or less qualifiers as the old type.
18335-
if (!OldClassTy.isAtLeastAsQualifiedAs(NewClassTy)) {
18335+
if (!OldClassTy.isAtLeastAsQualifiedAs(NewClassTy,
18336+
getASTContext().getTargetInfo())) {
1833618337
Diag(New->getLocation(),
1833718338
diag::err_covariant_return_type_class_type_not_same_or_less_qualified)
1833818339
<< New->getDeclName() << NewTy << OldTy

0 commit comments

Comments
 (0)