-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[clang][Interp] Handle virtual calls with covariant return types #101218
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@llvm/pr-subscribers-clang Author: Timm Baeder (tbaederr) ChangesFull diff: https://github.com/llvm/llvm-project/pull/101218.diff 14 Files Affected:
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index 89a74ff1fb285..dec51e032158e 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -2509,6 +2509,7 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
bool isFunctionNoProtoType() const { return getAs<FunctionNoProtoType>(); }
bool isFunctionProtoType() const { return getAs<FunctionProtoType>(); }
bool isPointerType() const;
+ bool isPointerOrReferenceType() const;
bool isSignableType() const;
bool isAnyPointerType() const; // Any C pointer or ObjC object pointer
bool isCountAttributedType() const;
@@ -7996,6 +7997,10 @@ inline bool Type::isPointerType() const {
return isa<PointerType>(CanonicalType);
}
+inline bool Type::isPointerOrReferenceType() const {
+ return isPointerType() || isReferenceType();
+}
+
inline bool Type::isAnyPointerType() const {
return isPointerType() || isObjCObjectPointerType();
}
diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h
index 26ffe057c74a2..d6a6cee62a752 100644
--- a/clang/include/clang/Sema/Overload.h
+++ b/clang/include/clang/Sema/Overload.h
@@ -984,7 +984,7 @@ class Sema;
unsigned getNumParams() const {
if (IsSurrogate) {
QualType STy = Surrogate->getConversionType();
- while (STy->isPointerType() || STy->isReferenceType())
+ while (STy->isPointerOrReferenceType())
STy = STy->getPointeeType();
return STy->castAs<FunctionProtoType>()->getNumParams();
}
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index e2c9643151126..6212989e21737 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -152,7 +152,7 @@ bool CXXTypeidExpr::isMostDerived(ASTContext &Context) const {
const Expr *E = getExprOperand()->IgnoreParenNoopCasts(Context);
if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) {
QualType Ty = DRE->getDecl()->getType();
- if (!Ty->isPointerType() && !Ty->isReferenceType())
+ if (!Ty->isPointerOrReferenceType())
return true;
}
diff --git a/clang/lib/AST/Interp/Context.cpp b/clang/lib/AST/Interp/Context.cpp
index b5e992c5a9ac1..fd66e6fe8dcbc 100644
--- a/clang/lib/AST/Interp/Context.cpp
+++ b/clang/lib/AST/Interp/Context.cpp
@@ -176,7 +176,7 @@ std::optional<PrimType> Context::classify(QualType T) const {
T->isFunctionType())
return PT_FnPtr;
- if (T->isReferenceType() || T->isPointerType() ||
+ if (T->isPointerOrReferenceType() ||
T->isObjCObjectPointerType())
return PT_Ptr;
diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h
index d128988a480e1..63e9966b831db 100644
--- a/clang/lib/AST/Interp/Interp.h
+++ b/clang/lib/AST/Interp/Interp.h
@@ -2628,7 +2628,29 @@ inline bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
}
}
- return Call(S, OpPC, Func, VarArgSize);
+ if (!Call(S, OpPC, Func, VarArgSize))
+ return false;
+
+ // Covariant return types. The return type of Overrider is a pointer
+ // or reference to a class type.
+ if (Overrider != InitialFunction &&
+ Overrider->getReturnType()->isPointerOrReferenceType() &&
+ InitialFunction->getReturnType()->isPointerOrReferenceType()) {
+ QualType OverriderPointeeType =
+ Overrider->getReturnType()->getPointeeType();
+ QualType InitialPointeeType =
+ InitialFunction->getReturnType()->getPointeeType();
+ // We've called Overrider above, but calling code expects us to return what
+ // InitialFunction returned. According to the rules for covariant return
+ // types, what InitialFunction returns needs to be a base class of what
+ // Overrider returns. So, we need to do an upcast here.
+ unsigned Offset = S.getContext().collectBaseOffset(
+ InitialPointeeType->getAsRecordDecl(),
+ OverriderPointeeType->getAsRecordDecl());
+ return GetPtrBasePop(S, OpPC, Offset);
+ }
+
+ return true;
}
inline bool CallBI(InterpState &S, CodePtr &PC, const Function *Func,
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index d46d621d4c7d4..ead5da4e90f2f 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -6484,7 +6484,7 @@ void CXXNameMangler::mangleValueInTemplateArg(QualType T, const APValue &V,
case APValue::LValue: {
// Proposed in https://github.com/itanium-cxx-abi/cxx-abi/issues/47.
- assert((T->isPointerType() || T->isReferenceType()) &&
+ assert((T->isPointerOrReferenceType()) &&
"unexpected type for LValue template arg");
if (V.isNullPointer()) {
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index fdaab8e434593..0456b5f96b210 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -75,7 +75,7 @@ bool Qualifiers::isStrictSupersetOf(Qualifiers Other) const {
const IdentifierInfo* QualType::getBaseTypeIdentifier() const {
const Type* ty = getTypePtr();
NamedDecl *ND = nullptr;
- if (ty->isPointerType() || ty->isReferenceType())
+ if (ty->isPointerOrReferenceType())
return ty->getPointeeType().getBaseTypeIdentifier();
else if (ty->isRecordType())
ND = ty->castAs<RecordType>()->getDecl();
diff --git a/clang/lib/Analysis/Consumed.cpp b/clang/lib/Analysis/Consumed.cpp
index d01c7f688e8b5..63c5943242944 100644
--- a/clang/lib/Analysis/Consumed.cpp
+++ b/clang/lib/Analysis/Consumed.cpp
@@ -141,7 +141,7 @@ static bool isCallableInState(const CallableWhenAttr *CWAttr,
}
static bool isConsumableType(const QualType &QT) {
- if (QT->isPointerType() || QT->isReferenceType())
+ if (QT->isPointerOrReferenceType())
return false;
if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl())
@@ -151,7 +151,7 @@ static bool isConsumableType(const QualType &QT) {
}
static bool isAutoCastType(const QualType &QT) {
- if (QT->isPointerType() || QT->isReferenceType())
+ if (QT->isPointerOrReferenceType())
return false;
if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl())
@@ -186,10 +186,6 @@ static bool isTestingFunction(const FunctionDecl *FunDecl) {
return FunDecl->hasAttr<TestTypestateAttr>();
}
-static bool isPointerOrRef(QualType ParamType) {
- return ParamType->isPointerType() || ParamType->isReferenceType();
-}
-
static ConsumedState mapConsumableAttrState(const QualType QT) {
assert(isConsumableType(QT));
@@ -648,7 +644,7 @@ bool ConsumedStmtVisitor::handleCall(const CallExpr *Call, const Expr *ObjArg,
setStateForVarOrTmp(StateMap, PInfo, mapReturnTypestateAttrState(RT));
else if (isRValueRef(ParamType) || isConsumableType(ParamType))
setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Consumed);
- else if (isPointerOrRef(ParamType) &&
+ else if (ParamType->isPointerOrReferenceType() &&
(!ParamType->getPointeeType().isConstQualified() ||
isSetOnReadPtrType(ParamType)))
setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Unknown);
diff --git a/clang/lib/Analysis/ThreadSafetyCommon.cpp b/clang/lib/Analysis/ThreadSafetyCommon.cpp
index 3e8c959ccee4f..cbcfefdc52549 100644
--- a/clang/lib/Analysis/ThreadSafetyCommon.cpp
+++ b/clang/lib/Analysis/ThreadSafetyCommon.cpp
@@ -97,7 +97,7 @@ static StringRef ClassifyDiagnostic(QualType VDT) {
if (const auto *TD = TT->getDecl())
if (const auto *CA = TD->getAttr<CapabilityAttr>())
return ClassifyDiagnostic(CA);
- } else if (VDT->isPointerType() || VDT->isReferenceType())
+ } else if (VDT->isPointerOrReferenceType())
return ClassifyDiagnostic(VDT->getPointeeType());
return "mutex";
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 694a754646f27..cac68dc1b22a1 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -5887,7 +5887,7 @@ Sema::GetNameFromUnqualifiedId(const UnqualifiedId &Name) {
static QualType getCoreType(QualType Ty) {
do {
- if (Ty->isPointerType() || Ty->isReferenceType())
+ if (Ty->isPointerOrReferenceType())
Ty = Ty->getPointeeType();
else if (Ty->isArrayType())
Ty = Ty->castAsArrayTypeUnsafe()->getElementType();
@@ -9339,7 +9339,7 @@ static OpenCLParamType getOpenCLKernelParameterType(Sema &S, QualType PT) {
if (PT->isDependentType())
return InvalidKernelParam;
- if (PT->isPointerType() || PT->isReferenceType()) {
+ if (PT->isPointerOrReferenceType())
QualType PointeeType = PT->getPointeeType();
if (PointeeType.getAddressSpace() == LangAS::opencl_generic ||
PointeeType.getAddressSpace() == LangAS::opencl_private ||
@@ -10789,7 +10789,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (getLangOpts().getOpenCLCompatibleVersion() >= 200) {
if(const PipeType *PipeTy = PT->getAs<PipeType>()) {
QualType ElemTy = PipeTy->getElementType();
- if (ElemTy->isReferenceType() || ElemTy->isPointerType()) {
+ if (ElemTy->isPointerOrReferenceType()) {
Diag(Param->getTypeSpecStartLoc(), diag::err_reference_pipe_type );
D.setInvalidType();
}
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 98e3df9083516..9011fa547638e 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -5992,7 +5992,7 @@ static void handleMSAllocatorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
// Warn if the return type is not a pointer or reference type.
if (auto *FD = dyn_cast<FunctionDecl>(D)) {
QualType RetTy = FD->getReturnType();
- if (!RetTy->isPointerType() && !RetTy->isReferenceType()) {
+ if (!RetTy->isPointerOrReferenceType()) {
S.Diag(AL.getLoc(), diag::warn_declspec_allocator_nonpointer)
<< AL.getRange() << RetTy;
return;
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 029969c1722b7..c5003d9ac0254 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -711,7 +711,7 @@ getUuidAttrOfType(Sema &SemaRef, QualType QT,
llvm::SmallSetVector<const UuidAttr *, 1> &UuidAttrs) {
// Optionally remove one level of pointer, reference or array indirection.
const Type *Ty = QT.getTypePtr();
- if (QT->isPointerType() || QT->isReferenceType())
+ if (QT->isPointerOrReferenceType())
Ty = QT->getPointeeType().getTypePtr();
else if (QT->isArrayType())
Ty = Ty->getBaseElementTypeUnsafe();
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 87b1f98bbe5ac..c22e329bef2b9 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -6719,7 +6719,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
auto *VD = const_cast<ValueDecl *>(Base.dyn_cast<const ValueDecl *>());
// For a non-type template-parameter of pointer or reference type,
// the value of the constant expression shall not refer to
- assert(ParamType->isPointerType() || ParamType->isReferenceType() ||
+ assert(ParamType->isPointerOrReferenceType() ||
ParamType->isNullPtrType());
// -- a temporary object
// -- a string literal
diff --git a/clang/test/AST/Interp/cxx2a.cpp b/clang/test/AST/Interp/cxx2a.cpp
index 27d1aa1a27f75..ad021b30cfd3c 100644
--- a/clang/test/AST/Interp/cxx2a.cpp
+++ b/clang/test/AST/Interp/cxx2a.cpp
@@ -13,3 +13,24 @@ consteval int aConstevalFunction() { // both-error {{consteval function never pr
return 0;
}
/// We're NOT calling the above function. The diagnostics should appear anyway.
+
+namespace Covariant {
+ struct A {
+ virtual constexpr char f() const { return 'Z'; }
+ char a = f();
+ };
+
+ struct D : A {};
+ struct Covariant1 {
+ D d;
+ virtual const A *f() const;
+ };
+
+ struct Covariant3 : Covariant1 {
+ constexpr virtual const D *f() const { return &this->d; }
+ };
+
+ constexpr Covariant3 cb;
+ constexpr const Covariant1 *cb1 = &cb;
+ static_assert(cb1->f()->a == 'Z');
+}
|
@llvm/pr-subscribers-clang-analysis Author: Timm Baeder (tbaederr) ChangesFull diff: https://github.com/llvm/llvm-project/pull/101218.diff 14 Files Affected:
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index 89a74ff1fb285..dec51e032158e 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -2509,6 +2509,7 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
bool isFunctionNoProtoType() const { return getAs<FunctionNoProtoType>(); }
bool isFunctionProtoType() const { return getAs<FunctionProtoType>(); }
bool isPointerType() const;
+ bool isPointerOrReferenceType() const;
bool isSignableType() const;
bool isAnyPointerType() const; // Any C pointer or ObjC object pointer
bool isCountAttributedType() const;
@@ -7996,6 +7997,10 @@ inline bool Type::isPointerType() const {
return isa<PointerType>(CanonicalType);
}
+inline bool Type::isPointerOrReferenceType() const {
+ return isPointerType() || isReferenceType();
+}
+
inline bool Type::isAnyPointerType() const {
return isPointerType() || isObjCObjectPointerType();
}
diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h
index 26ffe057c74a2..d6a6cee62a752 100644
--- a/clang/include/clang/Sema/Overload.h
+++ b/clang/include/clang/Sema/Overload.h
@@ -984,7 +984,7 @@ class Sema;
unsigned getNumParams() const {
if (IsSurrogate) {
QualType STy = Surrogate->getConversionType();
- while (STy->isPointerType() || STy->isReferenceType())
+ while (STy->isPointerOrReferenceType())
STy = STy->getPointeeType();
return STy->castAs<FunctionProtoType>()->getNumParams();
}
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index e2c9643151126..6212989e21737 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -152,7 +152,7 @@ bool CXXTypeidExpr::isMostDerived(ASTContext &Context) const {
const Expr *E = getExprOperand()->IgnoreParenNoopCasts(Context);
if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) {
QualType Ty = DRE->getDecl()->getType();
- if (!Ty->isPointerType() && !Ty->isReferenceType())
+ if (!Ty->isPointerOrReferenceType())
return true;
}
diff --git a/clang/lib/AST/Interp/Context.cpp b/clang/lib/AST/Interp/Context.cpp
index b5e992c5a9ac1..fd66e6fe8dcbc 100644
--- a/clang/lib/AST/Interp/Context.cpp
+++ b/clang/lib/AST/Interp/Context.cpp
@@ -176,7 +176,7 @@ std::optional<PrimType> Context::classify(QualType T) const {
T->isFunctionType())
return PT_FnPtr;
- if (T->isReferenceType() || T->isPointerType() ||
+ if (T->isPointerOrReferenceType() ||
T->isObjCObjectPointerType())
return PT_Ptr;
diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h
index d128988a480e1..63e9966b831db 100644
--- a/clang/lib/AST/Interp/Interp.h
+++ b/clang/lib/AST/Interp/Interp.h
@@ -2628,7 +2628,29 @@ inline bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
}
}
- return Call(S, OpPC, Func, VarArgSize);
+ if (!Call(S, OpPC, Func, VarArgSize))
+ return false;
+
+ // Covariant return types. The return type of Overrider is a pointer
+ // or reference to a class type.
+ if (Overrider != InitialFunction &&
+ Overrider->getReturnType()->isPointerOrReferenceType() &&
+ InitialFunction->getReturnType()->isPointerOrReferenceType()) {
+ QualType OverriderPointeeType =
+ Overrider->getReturnType()->getPointeeType();
+ QualType InitialPointeeType =
+ InitialFunction->getReturnType()->getPointeeType();
+ // We've called Overrider above, but calling code expects us to return what
+ // InitialFunction returned. According to the rules for covariant return
+ // types, what InitialFunction returns needs to be a base class of what
+ // Overrider returns. So, we need to do an upcast here.
+ unsigned Offset = S.getContext().collectBaseOffset(
+ InitialPointeeType->getAsRecordDecl(),
+ OverriderPointeeType->getAsRecordDecl());
+ return GetPtrBasePop(S, OpPC, Offset);
+ }
+
+ return true;
}
inline bool CallBI(InterpState &S, CodePtr &PC, const Function *Func,
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index d46d621d4c7d4..ead5da4e90f2f 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -6484,7 +6484,7 @@ void CXXNameMangler::mangleValueInTemplateArg(QualType T, const APValue &V,
case APValue::LValue: {
// Proposed in https://github.com/itanium-cxx-abi/cxx-abi/issues/47.
- assert((T->isPointerType() || T->isReferenceType()) &&
+ assert((T->isPointerOrReferenceType()) &&
"unexpected type for LValue template arg");
if (V.isNullPointer()) {
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index fdaab8e434593..0456b5f96b210 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -75,7 +75,7 @@ bool Qualifiers::isStrictSupersetOf(Qualifiers Other) const {
const IdentifierInfo* QualType::getBaseTypeIdentifier() const {
const Type* ty = getTypePtr();
NamedDecl *ND = nullptr;
- if (ty->isPointerType() || ty->isReferenceType())
+ if (ty->isPointerOrReferenceType())
return ty->getPointeeType().getBaseTypeIdentifier();
else if (ty->isRecordType())
ND = ty->castAs<RecordType>()->getDecl();
diff --git a/clang/lib/Analysis/Consumed.cpp b/clang/lib/Analysis/Consumed.cpp
index d01c7f688e8b5..63c5943242944 100644
--- a/clang/lib/Analysis/Consumed.cpp
+++ b/clang/lib/Analysis/Consumed.cpp
@@ -141,7 +141,7 @@ static bool isCallableInState(const CallableWhenAttr *CWAttr,
}
static bool isConsumableType(const QualType &QT) {
- if (QT->isPointerType() || QT->isReferenceType())
+ if (QT->isPointerOrReferenceType())
return false;
if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl())
@@ -151,7 +151,7 @@ static bool isConsumableType(const QualType &QT) {
}
static bool isAutoCastType(const QualType &QT) {
- if (QT->isPointerType() || QT->isReferenceType())
+ if (QT->isPointerOrReferenceType())
return false;
if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl())
@@ -186,10 +186,6 @@ static bool isTestingFunction(const FunctionDecl *FunDecl) {
return FunDecl->hasAttr<TestTypestateAttr>();
}
-static bool isPointerOrRef(QualType ParamType) {
- return ParamType->isPointerType() || ParamType->isReferenceType();
-}
-
static ConsumedState mapConsumableAttrState(const QualType QT) {
assert(isConsumableType(QT));
@@ -648,7 +644,7 @@ bool ConsumedStmtVisitor::handleCall(const CallExpr *Call, const Expr *ObjArg,
setStateForVarOrTmp(StateMap, PInfo, mapReturnTypestateAttrState(RT));
else if (isRValueRef(ParamType) || isConsumableType(ParamType))
setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Consumed);
- else if (isPointerOrRef(ParamType) &&
+ else if (ParamType->isPointerOrReferenceType() &&
(!ParamType->getPointeeType().isConstQualified() ||
isSetOnReadPtrType(ParamType)))
setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Unknown);
diff --git a/clang/lib/Analysis/ThreadSafetyCommon.cpp b/clang/lib/Analysis/ThreadSafetyCommon.cpp
index 3e8c959ccee4f..cbcfefdc52549 100644
--- a/clang/lib/Analysis/ThreadSafetyCommon.cpp
+++ b/clang/lib/Analysis/ThreadSafetyCommon.cpp
@@ -97,7 +97,7 @@ static StringRef ClassifyDiagnostic(QualType VDT) {
if (const auto *TD = TT->getDecl())
if (const auto *CA = TD->getAttr<CapabilityAttr>())
return ClassifyDiagnostic(CA);
- } else if (VDT->isPointerType() || VDT->isReferenceType())
+ } else if (VDT->isPointerOrReferenceType())
return ClassifyDiagnostic(VDT->getPointeeType());
return "mutex";
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 694a754646f27..cac68dc1b22a1 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -5887,7 +5887,7 @@ Sema::GetNameFromUnqualifiedId(const UnqualifiedId &Name) {
static QualType getCoreType(QualType Ty) {
do {
- if (Ty->isPointerType() || Ty->isReferenceType())
+ if (Ty->isPointerOrReferenceType())
Ty = Ty->getPointeeType();
else if (Ty->isArrayType())
Ty = Ty->castAsArrayTypeUnsafe()->getElementType();
@@ -9339,7 +9339,7 @@ static OpenCLParamType getOpenCLKernelParameterType(Sema &S, QualType PT) {
if (PT->isDependentType())
return InvalidKernelParam;
- if (PT->isPointerType() || PT->isReferenceType()) {
+ if (PT->isPointerOrReferenceType())
QualType PointeeType = PT->getPointeeType();
if (PointeeType.getAddressSpace() == LangAS::opencl_generic ||
PointeeType.getAddressSpace() == LangAS::opencl_private ||
@@ -10789,7 +10789,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (getLangOpts().getOpenCLCompatibleVersion() >= 200) {
if(const PipeType *PipeTy = PT->getAs<PipeType>()) {
QualType ElemTy = PipeTy->getElementType();
- if (ElemTy->isReferenceType() || ElemTy->isPointerType()) {
+ if (ElemTy->isPointerOrReferenceType()) {
Diag(Param->getTypeSpecStartLoc(), diag::err_reference_pipe_type );
D.setInvalidType();
}
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 98e3df9083516..9011fa547638e 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -5992,7 +5992,7 @@ static void handleMSAllocatorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
// Warn if the return type is not a pointer or reference type.
if (auto *FD = dyn_cast<FunctionDecl>(D)) {
QualType RetTy = FD->getReturnType();
- if (!RetTy->isPointerType() && !RetTy->isReferenceType()) {
+ if (!RetTy->isPointerOrReferenceType()) {
S.Diag(AL.getLoc(), diag::warn_declspec_allocator_nonpointer)
<< AL.getRange() << RetTy;
return;
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 029969c1722b7..c5003d9ac0254 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -711,7 +711,7 @@ getUuidAttrOfType(Sema &SemaRef, QualType QT,
llvm::SmallSetVector<const UuidAttr *, 1> &UuidAttrs) {
// Optionally remove one level of pointer, reference or array indirection.
const Type *Ty = QT.getTypePtr();
- if (QT->isPointerType() || QT->isReferenceType())
+ if (QT->isPointerOrReferenceType())
Ty = QT->getPointeeType().getTypePtr();
else if (QT->isArrayType())
Ty = Ty->getBaseElementTypeUnsafe();
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 87b1f98bbe5ac..c22e329bef2b9 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -6719,7 +6719,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
auto *VD = const_cast<ValueDecl *>(Base.dyn_cast<const ValueDecl *>());
// For a non-type template-parameter of pointer or reference type,
// the value of the constant expression shall not refer to
- assert(ParamType->isPointerType() || ParamType->isReferenceType() ||
+ assert(ParamType->isPointerOrReferenceType() ||
ParamType->isNullPtrType());
// -- a temporary object
// -- a string literal
diff --git a/clang/test/AST/Interp/cxx2a.cpp b/clang/test/AST/Interp/cxx2a.cpp
index 27d1aa1a27f75..ad021b30cfd3c 100644
--- a/clang/test/AST/Interp/cxx2a.cpp
+++ b/clang/test/AST/Interp/cxx2a.cpp
@@ -13,3 +13,24 @@ consteval int aConstevalFunction() { // both-error {{consteval function never pr
return 0;
}
/// We're NOT calling the above function. The diagnostics should appear anyway.
+
+namespace Covariant {
+ struct A {
+ virtual constexpr char f() const { return 'Z'; }
+ char a = f();
+ };
+
+ struct D : A {};
+ struct Covariant1 {
+ D d;
+ virtual const A *f() const;
+ };
+
+ struct Covariant3 : Covariant1 {
+ constexpr virtual const D *f() const { return &this->d; }
+ };
+
+ constexpr Covariant3 cb;
+ constexpr const Covariant1 *cb1 = &cb;
+ static_assert(cb1->f()->a == 'Z');
+}
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
0f16b47
to
78961fb
Compare
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Labels
clang:analysis
clang:frontend
Language frontend issues, e.g. anything involving "Sema"
clang
Clang issues not falling into any other category
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
No description provided.