Skip to content

Commit a99b912

Browse files
committed
[clang][Interp] Create dummy pointers for external variables
This way we can use their address, which is necessary in some scenarios. This requires us to create different descriptors for dummy arrays so we can get the diagnostics right.
1 parent 7f21678 commit a99b912

File tree

8 files changed

+62
-25
lines changed

8 files changed

+62
-25
lines changed

clang/lib/AST/Interp/ByteCodeExprGen.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3301,9 +3301,6 @@ bool ByteCodeExprGen<Emitter>::VisitDeclRefExpr(const DeclRefExpr *E) {
33013301
// Retry.
33023302
return this->VisitDeclRefExpr(E);
33033303
}
3304-
3305-
if (VD->hasExternalStorage())
3306-
return this->emitInvalidDeclRef(E, E);
33073304
}
33083305
} else {
33093306
if (const auto *VD = dyn_cast<VarDecl>(D);

clang/lib/AST/Interp/Descriptor.cpp

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -301,10 +301,19 @@ Descriptor::Descriptor(const DeclTy &D, const Record *R, MetadataSize MD,
301301
assert(Source && "Missing source");
302302
}
303303

304-
Descriptor::Descriptor(const DeclTy &D, MetadataSize MD)
305-
: Source(D), ElemSize(1), Size(ElemSize), MDSize(MD.value_or(0)),
306-
AllocSize(Size + MDSize), ElemRecord(nullptr), IsConst(true),
307-
IsMutable(false), IsTemporary(false), IsDummy(true) {
304+
/// Dummy.
305+
Descriptor::Descriptor(const DeclTy &D)
306+
: Source(D), ElemSize(1), Size(1), MDSize(0), AllocSize(MDSize),
307+
ElemRecord(nullptr), IsConst(true), IsMutable(false), IsTemporary(false),
308+
IsDummy(true) {
309+
assert(Source && "Missing source");
310+
}
311+
312+
/// Dummy array.
313+
Descriptor::Descriptor(const DeclTy &D, UnknownSize)
314+
: Source(D), ElemSize(1), Size(UnknownSizeMark), MDSize(0),
315+
AllocSize(MDSize), ElemRecord(nullptr), IsConst(true), IsMutable(false),
316+
IsTemporary(false), IsArray(true), IsDummy(true) {
308317
assert(Source && "Missing source");
309318
}
310319

clang/lib/AST/Interp/Descriptor.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,11 @@ struct Descriptor final {
156156
Descriptor(const DeclTy &D, const Record *R, MetadataSize MD, bool IsConst,
157157
bool IsTemporary, bool IsMutable);
158158

159-
Descriptor(const DeclTy &D, MetadataSize MD);
159+
/// Allocates a dummy descriptor.
160+
Descriptor(const DeclTy &D);
161+
162+
/// Allocates a dummy array descriptor.
163+
Descriptor(const DeclTy &D, UnknownSize);
160164

161165
QualType getType() const;
162166
QualType getElemQualType() const;

clang/lib/AST/Interp/Interp.h

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1946,8 +1946,15 @@ inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) {
19461946
const T &Offset = S.Stk.pop<T>();
19471947
const Pointer &Ptr = S.Stk.peek<Pointer>();
19481948

1949-
if (Ptr.isDummy())
1950-
return true;
1949+
if (!Ptr.isZero()) {
1950+
if (!CheckArray(S, OpPC, Ptr))
1951+
return false;
1952+
1953+
if (Ptr.isDummy()) {
1954+
S.Stk.push<Pointer>(Ptr);
1955+
return true;
1956+
}
1957+
}
19511958

19521959
if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
19531960
return false;
@@ -1960,9 +1967,14 @@ inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {
19601967
const T &Offset = S.Stk.pop<T>();
19611968
const Pointer &Ptr = S.Stk.pop<Pointer>();
19621969

1963-
if (Ptr.isDummy()) {
1964-
S.Stk.push<Pointer>(Ptr);
1965-
return true;
1970+
if (!Ptr.isZero()) {
1971+
if (!CheckArray(S, OpPC, Ptr))
1972+
return false;
1973+
1974+
if (Ptr.isDummy()) {
1975+
S.Stk.push<Pointer>(Ptr);
1976+
return true;
1977+
}
19661978
}
19671979

19681980
if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))

clang/lib/AST/Interp/Pointer.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,11 @@ class Pointer {
285285
bool inPrimitiveArray() const { return getFieldDesc()->isPrimitiveArray(); }
286286
/// Checks if the structure is an array of unknown size.
287287
bool isUnknownSizeArray() const {
288+
// If this points inside a dummy block, return true.
289+
// FIXME: This might change in the future. If it does, we need
290+
// to set the proper Ctor/Dtor functions for dummy Descriptors.
291+
if (Base != 0 && Base != sizeof(InlineDescriptor) && isDummy())
292+
return true;
288293
return getFieldDesc()->isUnknownSizeArray();
289294
}
290295
/// Checks if the pointer points to an array.

clang/lib/AST/Interp/Program.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,16 @@ std::optional<unsigned> Program::getOrCreateDummy(const ValueDecl *VD) {
149149
return It->second;
150150

151151
// Create dummy descriptor.
152-
Descriptor *Desc = allocateDescriptor(VD, std::nullopt);
152+
// We create desriptors of 'array of unknown size' if the type is an array
153+
// type _and_ the size isn't known (it's not a ConstantArrayType). If the size
154+
// is known however, we create a regular dummy pointer.
155+
Descriptor *Desc;
156+
if (const auto *AT = VD->getType()->getAsArrayTypeUnsafe();
157+
AT && !isa<ConstantArrayType>(AT))
158+
Desc = allocateDescriptor(VD, Descriptor::UnknownSize{});
159+
else
160+
Desc = allocateDescriptor(VD);
161+
153162
// Allocate a block for storage.
154163
unsigned I = Globals.size();
155164

clang/test/AST/Interp/arrays.cpp

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -429,18 +429,13 @@ namespace Incomplete {
429429
// both-note {{array-to-pointer decay of array member without known bound}}
430430

431431
/// These are from test/SemaCXX/constant-expression-cxx11.cpp
432-
/// and are the only tests using the 'indexing of array without known bound' diagnostic.
433-
/// We currently diagnose them differently.
434-
extern int arr[]; // expected-note 3{{declared here}}
432+
extern int arr[];
435433
constexpr int *c = &arr[1]; // both-error {{must be initialized by a constant expression}} \
436-
// ref-note {{indexing of array without known bound}} \
437-
// expected-note {{read of non-constexpr variable 'arr'}}
434+
// both-note {{indexing of array without known bound}}
438435
constexpr int *d = &arr[1]; // both-error {{must be initialized by a constant expression}} \
439-
// ref-note {{indexing of array without known bound}} \
440-
// expected-note {{read of non-constexpr variable 'arr'}}
436+
// both-note {{indexing of array without known bound}}
441437
constexpr int *e = arr + 1; // both-error {{must be initialized by a constant expression}} \
442-
// ref-note {{indexing of array without known bound}} \
443-
// expected-note {{read of non-constexpr variable 'arr'}}
438+
// both-note {{indexing of array without known bound}}
444439
}
445440

446441
namespace GH69115 {

clang/test/AST/Interp/literals.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1113,6 +1113,9 @@ namespace InvalidDeclRefs {
11131113
int b03 = 3; // both-note {{declared here}}
11141114
static_assert(b03, ""); // both-error {{not an integral constant expression}} \
11151115
// both-note {{read of non-const variable}}
1116+
1117+
extern int var;
1118+
constexpr int *varp = &var; // Ok.
11161119
}
11171120

11181121
namespace NonConstReads {
@@ -1182,8 +1185,11 @@ namespace incdecbool {
11821185
}
11831186

11841187
#if __cplusplus >= 201402L
1188+
/// NOTE: The diagnostics of the two interpreters are a little
1189+
/// different here, but they both make sense.
11851190
constexpr int externvar1() { // both-error {{never produces a constant expression}}
1186-
extern char arr[]; // both-note {{declared here}}
1187-
return arr[0]; // both-note {{read of non-constexpr variable 'arr'}}
1191+
extern char arr[]; // ref-note {{declared here}}
1192+
return arr[0]; // ref-note {{read of non-constexpr variable 'arr'}} \
1193+
// expected-note {{indexing of array without known bound}}
11881194
}
11891195
#endif

0 commit comments

Comments
 (0)