Skip to content

[clang][bytecode] Fix dummy handling for p2280r4 #124396

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
merged 1 commit into from
Jan 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion clang/lib/AST/ByteCode/Compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6175,7 +6175,7 @@ bool Compiler<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) {
}

if (D->getType()->isReferenceType())
return false; // FIXME: Do we need to emit InvalidDeclRef?
return this->emitDummyPtr(D, E);
}

// In case we need to re-visit a declaration.
Expand Down
6 changes: 4 additions & 2 deletions clang/lib/AST/ByteCode/Descriptor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,8 @@ QualType Descriptor::getElemQualType() const {
assert(isArray());
QualType T = getType();
if (T->isPointerOrReferenceType())
return T->getPointeeType();
T = T->getPointeeType();

if (const auto *AT = T->getAsArrayTypeUnsafe()) {
// For primitive arrays, we don't save a QualType at all,
// just a PrimType. Try to figure out the QualType here.
Expand All @@ -424,7 +425,8 @@ QualType Descriptor::getElemQualType() const {
return CT->getElementType();
if (const auto *CT = T->getAs<VectorType>())
return CT->getElementType();
llvm_unreachable("Array that's not an array/complex/vector type?");

return T;
}

SourceLocation Descriptor::getLocation() const {
Expand Down
20 changes: 9 additions & 11 deletions clang/lib/AST/ByteCode/Interp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ static bool diagnoseUnknownDecl(InterpState &S, CodePtr OpPC,
const SourceInfo &E = S.Current->getSource(OpPC);

if (isa<ParmVarDecl>(D)) {
if (D->getType()->isReferenceType())
return false;

if (S.getLangOpts().CPlusPlus11) {
S.FFDiag(E, diag::note_constexpr_function_param_value_unknown) << D;
S.Note(D->getLocation(), diag::note_declared_at) << D->getSourceRange();
Expand Down Expand Up @@ -1287,6 +1290,12 @@ bool Call(InterpState &S, CodePtr OpPC, const Function *Func,

const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);

// C++23 [expr.const]p5.6
// an invocation of a virtual function ([class.virtual]) for an object whose
// dynamic type is constexpr-unknown;
if (ThisPtr.isDummy() && Func->isVirtual())
return false;

// If the current function is a lambda static invoker and
// the function we're about to call is a lambda call operator,
// skip the CheckInvoke, since the ThisPtr is a null pointer
Expand Down Expand Up @@ -1661,17 +1670,6 @@ bool GetTypeidPtr(InterpState &S, CodePtr OpPC, const Type *TypeInfoType) {
if (!P.isBlockPointer())
return false;

if (P.isDummy()) {
QualType StarThisType =
S.getASTContext().getLValueReferenceType(P.getType());
S.FFDiag(S.Current->getSource(OpPC),
diag::note_constexpr_polymorphic_unknown_dynamic_type)
<< AK_TypeId
<< P.toAPValue(S.getASTContext())
.getAsString(S.getASTContext(), StarThisType);
return false;
}

S.Stk.push<Pointer>(P.getType().getTypePtr(), TypeInfoType);
return true;
}
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/AST/ByteCode/InterpBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1538,9 +1538,12 @@ static bool interp__builtin_constant_p(InterpState &S, CodePtr OpPC,
if (ArgType->isIntegralOrEnumerationType() || ArgType->isFloatingType() ||
ArgType->isAnyComplexType() || ArgType->isPointerType() ||
ArgType->isNullPtrType()) {
auto PrevDiags = S.getEvalStatus().Diag;
S.getEvalStatus().Diag = nullptr;
InterpStack Stk;
Compiler<EvalEmitter> C(S.Ctx, S.P, S, Stk);
auto Res = C.interpretExpr(Arg, /*ConvertResultToRValue=*/Arg->isGLValue());
S.getEvalStatus().Diag = PrevDiags;
if (Res.isInvalid()) {
C.cleanup();
Stk.clear();
Expand Down
33 changes: 22 additions & 11 deletions clang/lib/AST/ByteCode/Pointer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,10 @@ APValue Pointer::toAPValue(const ASTContext &ASTCtx) const {
return ASTCtx.toCharUnitsFromBits(Layout.getFieldOffset(FieldIndex));
};

bool UsePath = true;
if (getType()->isLValueReferenceType())
UsePath = false;

// Build the path into the object.
Pointer Ptr = *this;
while (Ptr.isField() || Ptr.isArrayElement()) {
Expand All @@ -217,38 +221,42 @@ APValue Pointer::toAPValue(const ASTContext &ASTCtx) const {
// An array root may still be an array element itself.
if (Ptr.isArrayElement()) {
Ptr = Ptr.expand();
const Descriptor *Desc = Ptr.getFieldDesc();
unsigned Index = Ptr.getIndex();
Path.push_back(APValue::LValuePathEntry::ArrayIndex(Index));
QualType ElemType = Ptr.getFieldDesc()->getElemQualType();
QualType ElemType = Desc->getElemQualType();
Offset += (Index * ASTCtx.getTypeSizeInChars(ElemType));
if (Ptr.getArray().getType()->isArrayType())
Path.push_back(APValue::LValuePathEntry::ArrayIndex(Index));
Ptr = Ptr.getArray();
} else {
Path.push_back(APValue::LValuePathEntry(
{Ptr.getFieldDesc()->asDecl(), /*IsVirtual=*/false}));
const Descriptor *Desc = Ptr.getFieldDesc();
const auto *Dcl = Desc->asDecl();
Path.push_back(APValue::LValuePathEntry({Dcl, /*IsVirtual=*/false}));

if (const auto *FD =
dyn_cast_if_present<FieldDecl>(Ptr.getFieldDesc()->asDecl()))
if (const auto *FD = dyn_cast_if_present<FieldDecl>(Dcl))
Offset += getFieldOffset(FD);

Ptr = Ptr.getBase();
}
} else if (Ptr.isArrayElement()) {
Ptr = Ptr.expand();
const Descriptor *Desc = Ptr.getFieldDesc();
unsigned Index;
if (Ptr.isOnePastEnd())
Index = Ptr.getArray().getNumElems();
else
Index = Ptr.getIndex();

QualType ElemType = Ptr.getFieldDesc()->getElemQualType();
QualType ElemType = Desc->getElemQualType();
Offset += (Index * ASTCtx.getTypeSizeInChars(ElemType));
Path.push_back(APValue::LValuePathEntry::ArrayIndex(Index));
if (Ptr.getArray().getType()->isArrayType())
Path.push_back(APValue::LValuePathEntry::ArrayIndex(Index));
Ptr = Ptr.getArray();
} else {
const Descriptor *Desc = Ptr.getFieldDesc();
bool IsVirtual = false;

// Create a path entry for the field.
const Descriptor *Desc = Ptr.getFieldDesc();
if (const auto *BaseOrMember = Desc->asDecl()) {
if (const auto *FD = dyn_cast<FieldDecl>(BaseOrMember)) {
Ptr = Ptr.getBase();
Expand Down Expand Up @@ -281,8 +289,11 @@ APValue Pointer::toAPValue(const ASTContext &ASTCtx) const {
// Just invert the order of the elements.
std::reverse(Path.begin(), Path.end());

return APValue(Base, Offset, Path, /*IsOnePastEnd=*/isOnePastEnd(),
/*IsNullPtr=*/false);
if (UsePath)
return APValue(Base, Offset, Path,
/*IsOnePastEnd=*/!isElementPastEnd() && isOnePastEnd());

return APValue(Base, Offset, APValue::NoLValuePath());
}

void Pointer::print(llvm::raw_ostream &OS) const {
Expand Down
3 changes: 1 addition & 2 deletions clang/lib/AST/ByteCode/Pointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -630,8 +630,7 @@ class Pointer {
if (isUnknownSizeArray())
return false;

return isElementPastEnd() || isPastEnd() ||
(getSize() == getOffset() && !isZeroSizeArray());
return isPastEnd() || (getSize() == getOffset() && !isZeroSizeArray());
}

/// Checks if the pointer points past the end of the object.
Expand Down
4 changes: 1 addition & 3 deletions clang/test/AST/ByteCode/cxx2a.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,7 @@ namespace TypeId {
static_assert(&B2().ti1 == &typeid(B));
static_assert(&B2().ti2 == &typeid(B2));
extern B2 extern_b2;
static_assert(&typeid(extern_b2) == &typeid(B2)); // expected-error {{constant expression}} \
// expected-note{{typeid applied to object 'extern_b2' whose dynamic type is not constant}}

static_assert(&typeid(extern_b2) == &typeid(B2));

constexpr B2 b2;
constexpr const B &b1 = b2;
Expand Down
1 change: 1 addition & 0 deletions clang/test/SemaCXX/constant-expression-p2280r4.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++23 -verify %s
// RUN: %clang_cc1 -std=c++23 -verify %s -fexperimental-new-constant-interpreter

using size_t = decltype(sizeof(0));

Expand Down