Skip to content

Commit

Permalink
Properly handle instantiation-dependent array bounds.
Browse files Browse the repository at this point in the history
We previously failed to treat an array with an instantiation-dependent
but not value-dependent bound as being an instantiation-dependent type.
We now track the array bound expression as part of a constant array type
if it's an instantiation-dependent expression.

llvm-svn: 373685
  • Loading branch information
zygoloid committed Oct 4, 2019
1 parent 053391f commit 772e266
Show file tree
Hide file tree
Showing 31 changed files with 237 additions and 156 deletions.
4 changes: 3 additions & 1 deletion clang/include/clang/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
mutable llvm::FoldingSet<LValueReferenceType> LValueReferenceTypes;
mutable llvm::FoldingSet<RValueReferenceType> RValueReferenceTypes;
mutable llvm::FoldingSet<MemberPointerType> MemberPointerTypes;
mutable llvm::FoldingSet<ConstantArrayType> ConstantArrayTypes;
mutable llvm::ContextualFoldingSet<ConstantArrayType, ASTContext &>
ConstantArrayTypes;
mutable llvm::FoldingSet<IncompleteArrayType> IncompleteArrayTypes;
mutable std::vector<VariableArrayType*> VariableArrayTypes;
mutable llvm::FoldingSet<DependentSizedArrayType> DependentSizedArrayTypes;
Expand Down Expand Up @@ -1330,6 +1331,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// Return the unique reference to the type for a constant array of
/// the specified element type.
QualType getConstantArrayType(QualType EltTy, const llvm::APInt &ArySize,
const Expr *SizeExpr,
ArrayType::ArraySizeModifier ASM,
unsigned IndexTypeQuals) const;

Expand Down
7 changes: 5 additions & 2 deletions clang/include/clang/AST/RecursiveASTVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -959,8 +959,11 @@ DEF_TRAVERSE_TYPE(AdjustedType, { TRY_TO(TraverseType(T->getOriginalType())); })

DEF_TRAVERSE_TYPE(DecayedType, { TRY_TO(TraverseType(T->getOriginalType())); })

DEF_TRAVERSE_TYPE(ConstantArrayType,
{ TRY_TO(TraverseType(T->getElementType())); })
DEF_TRAVERSE_TYPE(ConstantArrayType, {
TRY_TO(TraverseType(T->getElementType()));
if (T->getSizeExpr())
TRY_TO(TraverseStmt(const_cast<Expr*>(T->getSizeExpr())));
})

DEF_TRAVERSE_TYPE(IncompleteArrayType,
{ TRY_TO(TraverseType(T->getElementType())); })
Expand Down
84 changes: 42 additions & 42 deletions clang/include/clang/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -1513,6 +1513,15 @@ class alignas(8) Type : public ExtQualsTypeCommonBase {
unsigned SizeModifier : 3;
};

class ConstantArrayTypeBitfields {
friend class ConstantArrayType;

unsigned : NumTypeBits + 3 + 3;

/// Whether we have a stored size expression.
unsigned HasStoredSizeExpr : 1;
};

class BuiltinTypeBitfields {
friend class BuiltinType;

Expand Down Expand Up @@ -1734,6 +1743,7 @@ class alignas(8) Type : public ExtQualsTypeCommonBase {
union {
TypeBitfields TypeBits;
ArrayTypeBitfields ArrayTypeBits;
ConstantArrayTypeBitfields ConstantArrayTypeBits;
AttributedTypeBitfields AttributedTypeBits;
AutoTypeBitfields AutoTypeBits;
BuiltinTypeBitfields BuiltinTypeBits;
Expand Down Expand Up @@ -2864,22 +2874,8 @@ class ArrayType : public Type, public llvm::FoldingSetNode {
protected:
friend class ASTContext; // ASTContext creates these.

// C++ [temp.dep.type]p1:
// A type is dependent if it is...
// - an array type constructed from any dependent type or whose
// size is specified by a constant expression that is
// value-dependent,
ArrayType(TypeClass tc, QualType et, QualType can,
ArraySizeModifier sm, unsigned tq,
bool ContainsUnexpandedParameterPack)
: Type(tc, can, et->isDependentType() || tc == DependentSizedArray,
et->isInstantiationDependentType() || tc == DependentSizedArray,
(tc == VariableArray || et->isVariablyModifiedType()),
ContainsUnexpandedParameterPack),
ElementType(et) {
ArrayTypeBits.IndexTypeQuals = tq;
ArrayTypeBits.SizeModifier = sm;
}
ArrayType(TypeClass tc, QualType et, QualType can, ArraySizeModifier sm,
unsigned tq, const Expr *sz = nullptr);

public:
QualType getElementType() const { return ElementType; }
Expand Down Expand Up @@ -2907,25 +2903,35 @@ class ArrayType : public Type, public llvm::FoldingSetNode {
/// Represents the canonical version of C arrays with a specified constant size.
/// For example, the canonical type for 'int A[4 + 4*100]' is a
/// ConstantArrayType where the element type is 'int' and the size is 404.
class ConstantArrayType : public ArrayType {
class ConstantArrayType final
: public ArrayType,
private llvm::TrailingObjects<ConstantArrayType, const Expr *> {
friend class ASTContext; // ASTContext creates these.
friend TrailingObjects;

llvm::APInt Size; // Allows us to unique the type.

ConstantArrayType(QualType et, QualType can, const llvm::APInt &size,
ArraySizeModifier sm, unsigned tq)
: ArrayType(ConstantArray, et, can, sm, tq,
et->containsUnexpandedParameterPack()),
Size(size) {}

protected:
friend class ASTContext; // ASTContext creates these.
const Expr *sz, ArraySizeModifier sm, unsigned tq)
: ArrayType(ConstantArray, et, can, sm, tq, sz), Size(size) {
ConstantArrayTypeBits.HasStoredSizeExpr = sz != nullptr;
if (ConstantArrayTypeBits.HasStoredSizeExpr) {
assert(!can.isNull() && "canonical constant array should not have size");
*getTrailingObjects<const Expr*>() = sz;
}
}

ConstantArrayType(TypeClass tc, QualType et, QualType can,
const llvm::APInt &size, ArraySizeModifier sm, unsigned tq)
: ArrayType(tc, et, can, sm, tq, et->containsUnexpandedParameterPack()),
Size(size) {}
unsigned numTrailingObjects(OverloadToken<const Expr*>) const {
return ConstantArrayTypeBits.HasStoredSizeExpr;
}

public:
const llvm::APInt &getSize() const { return Size; }
const Expr *getSizeExpr() const {
return ConstantArrayTypeBits.HasStoredSizeExpr
? *getTrailingObjects<const Expr *>()
: nullptr;
}
bool isSugared() const { return false; }
QualType desugar() const { return QualType(this, 0); }

Expand All @@ -2939,19 +2945,15 @@ class ConstantArrayType : public ArrayType {
/// can require, which limits the maximum size of the array.
static unsigned getMaxSizeBits(const ASTContext &Context);

void Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, getElementType(), getSize(),
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx) {
Profile(ID, Ctx, getElementType(), getSize(), getSizeExpr(),
getSizeModifier(), getIndexTypeCVRQualifiers());
}

static void Profile(llvm::FoldingSetNodeID &ID, QualType ET,
const llvm::APInt &ArraySize, ArraySizeModifier SizeMod,
unsigned TypeQuals) {
ID.AddPointer(ET.getAsOpaquePtr());
ID.AddInteger(ArraySize.getZExtValue());
ID.AddInteger(SizeMod);
ID.AddInteger(TypeQuals);
}
static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx,
QualType ET, const llvm::APInt &ArraySize,
const Expr *SizeExpr, ArraySizeModifier SizeMod,
unsigned TypeQuals);

static bool classof(const Type *T) {
return T->getTypeClass() == ConstantArray;
Expand All @@ -2966,8 +2968,7 @@ class IncompleteArrayType : public ArrayType {

IncompleteArrayType(QualType et, QualType can,
ArraySizeModifier sm, unsigned tq)
: ArrayType(IncompleteArray, et, can, sm, tq,
et->containsUnexpandedParameterPack()) {}
: ArrayType(IncompleteArray, et, can, sm, tq) {}

public:
friend class StmtIteratorBase;
Expand Down Expand Up @@ -3019,8 +3020,7 @@ class VariableArrayType : public ArrayType {
VariableArrayType(QualType et, QualType can, Expr *e,
ArraySizeModifier sm, unsigned tq,
SourceRange brackets)
: ArrayType(VariableArray, et, can, sm, tq,
et->containsUnexpandedParameterPack()),
: ArrayType(VariableArray, et, can, sm, tq, e),
SizeExpr((Stmt*) e), Brackets(brackets) {}

public:
Expand Down
59 changes: 38 additions & 21 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -829,7 +829,8 @@ static bool isAddrSpaceMapManglingEnabled(const TargetInfo &TI,
ASTContext::ASTContext(LangOptions &LOpts, SourceManager &SM,
IdentifierTable &idents, SelectorTable &sels,
Builtin::Context &builtins)
: FunctionProtoTypes(this_()), TemplateSpecializationTypes(this_()),
: ConstantArrayTypes(this_()), FunctionProtoTypes(this_()),
TemplateSpecializationTypes(this_()),
DependentTemplateSpecializationTypes(this_()),
SubstTemplateTemplateParmPacks(this_()), SourceMgr(SM), LangOpts(LOpts),
SanitizerBL(new SanitizerBlacklist(LangOpts.SanitizerBlacklistFiles, SM)),
Expand Down Expand Up @@ -3165,31 +3166,38 @@ QualType ASTContext::getMemberPointerType(QualType T, const Type *Cls) const {
/// array of the specified element type.
QualType ASTContext::getConstantArrayType(QualType EltTy,
const llvm::APInt &ArySizeIn,
const Expr *SizeExpr,
ArrayType::ArraySizeModifier ASM,
unsigned IndexTypeQuals) const {
assert((EltTy->isDependentType() ||
EltTy->isIncompleteType() || EltTy->isConstantSizeType()) &&
"Constant array of VLAs is illegal!");

// We only need the size as part of the type if it's instantiation-dependent.
if (SizeExpr && !SizeExpr->isInstantiationDependent())
SizeExpr = nullptr;

// Convert the array size into a canonical width matching the pointer size for
// the target.
llvm::APInt ArySize(ArySizeIn);
ArySize = ArySize.zextOrTrunc(Target->getMaxPointerWidth());

llvm::FoldingSetNodeID ID;
ConstantArrayType::Profile(ID, EltTy, ArySize, ASM, IndexTypeQuals);
ConstantArrayType::Profile(ID, *this, EltTy, ArySize, SizeExpr, ASM,
IndexTypeQuals);

void *InsertPos = nullptr;
if (ConstantArrayType *ATP =
ConstantArrayTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(ATP, 0);

// If the element type isn't canonical or has qualifiers, this won't
// be a canonical type either, so fill in the canonical type field.
// If the element type isn't canonical or has qualifiers, or the array bound
// is instantiation-dependent, this won't be a canonical type either, so fill
// in the canonical type field.
QualType Canon;
if (!EltTy.isCanonical() || EltTy.hasLocalQualifiers()) {
if (!EltTy.isCanonical() || EltTy.hasLocalQualifiers() || SizeExpr) {
SplitQualType canonSplit = getCanonicalType(EltTy).split();
Canon = getConstantArrayType(QualType(canonSplit.Ty, 0), ArySize,
Canon = getConstantArrayType(QualType(canonSplit.Ty, 0), ArySize, nullptr,
ASM, IndexTypeQuals);
Canon = getQualifiedType(Canon, canonSplit.Quals);

Expand All @@ -3199,8 +3207,11 @@ QualType ASTContext::getConstantArrayType(QualType EltTy,
assert(!NewIP && "Shouldn't be in the map!"); (void)NewIP;
}

auto *New = new (*this,TypeAlignment)
ConstantArrayType(EltTy, Canon, ArySize, ASM, IndexTypeQuals);
void *Mem = Allocate(
ConstantArrayType::totalSizeToAlloc<const Expr *>(SizeExpr ? 1 : 0),
TypeAlignment);
auto *New = new (Mem)
ConstantArrayType(EltTy, Canon, ArySize, SizeExpr, ASM, IndexTypeQuals);
ConstantArrayTypes.InsertNode(New, InsertPos);
Types.push_back(New);
return QualType(New, 0);
Expand Down Expand Up @@ -3297,6 +3308,7 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const {
result = getConstantArrayType(
getVariableArrayDecayedType(cat->getElementType()),
cat->getSize(),
cat->getSizeExpr(),
cat->getSizeModifier(),
cat->getIndexTypeCVRQualifiers());
break;
Expand Down Expand Up @@ -5192,7 +5204,7 @@ QualType ASTContext::getUnqualifiedArrayType(QualType type,

if (const auto *CAT = dyn_cast<ConstantArrayType>(AT)) {
return getConstantArrayType(unqualElementType, CAT->getSize(),
CAT->getSizeModifier(), 0);
CAT->getSizeExpr(), CAT->getSizeModifier(), 0);
}

if (const auto *IAT = dyn_cast<IncompleteArrayType>(AT)) {
Expand Down Expand Up @@ -5565,6 +5577,7 @@ const ArrayType *ASTContext::getAsArrayType(QualType T) const {

if (const auto *CAT = dyn_cast<ConstantArrayType>(ATy))
return cast<ArrayType>(getConstantArrayType(NewEltTy, CAT->getSize(),
CAT->getSizeExpr(),
CAT->getSizeModifier(),
CAT->getIndexTypeCVRQualifiers()));
if (const auto *IAT = dyn_cast<IncompleteArrayType>(ATy))
Expand Down Expand Up @@ -7471,7 +7484,7 @@ static TypedefDecl *CreatePowerABIBuiltinVaListDecl(const ASTContext *Context) {
llvm::APInt Size(Context->getTypeSize(Context->getSizeType()), 1);
QualType VaListTagArrayType
= Context->getConstantArrayType(VaListTagTypedefType,
Size, ArrayType::Normal, 0);
Size, nullptr, ArrayType::Normal, 0);
return Context->buildImplicitTypedef(VaListTagArrayType, "__builtin_va_list");
}

Expand Down Expand Up @@ -7524,16 +7537,16 @@ CreateX86_64ABIBuiltinVaListDecl(const ASTContext *Context) {

// typedef struct __va_list_tag __builtin_va_list[1];
llvm::APInt Size(Context->getTypeSize(Context->getSizeType()), 1);
QualType VaListTagArrayType =
Context->getConstantArrayType(VaListTagType, Size, ArrayType::Normal, 0);
QualType VaListTagArrayType = Context->getConstantArrayType(
VaListTagType, Size, nullptr, ArrayType::Normal, 0);
return Context->buildImplicitTypedef(VaListTagArrayType, "__builtin_va_list");
}

static TypedefDecl *CreatePNaClABIBuiltinVaListDecl(const ASTContext *Context) {
// typedef int __builtin_va_list[4];
llvm::APInt Size(Context->getTypeSize(Context->getSizeType()), 4);
QualType IntArrayType =
Context->getConstantArrayType(Context->IntTy, Size, ArrayType::Normal, 0);
QualType IntArrayType = Context->getConstantArrayType(
Context->IntTy, Size, nullptr, ArrayType::Normal, 0);
return Context->buildImplicitTypedef(IntArrayType, "__builtin_va_list");
}

Expand Down Expand Up @@ -7627,8 +7640,8 @@ CreateSystemZBuiltinVaListDecl(const ASTContext *Context) {

// typedef __va_list_tag __builtin_va_list[1];
llvm::APInt Size(Context->getTypeSize(Context->getSizeType()), 1);
QualType VaListTagArrayType =
Context->getConstantArrayType(VaListTagType, Size, ArrayType::Normal, 0);
QualType VaListTagArrayType = Context->getConstantArrayType(
VaListTagType, Size, nullptr, ArrayType::Normal, 0);

return Context->buildImplicitTypedef(VaListTagArrayType, "__builtin_va_list");
}
Expand Down Expand Up @@ -9072,10 +9085,14 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
return LHS;
if (RCAT && getCanonicalType(RHSElem) == getCanonicalType(ResultType))
return RHS;
if (LCAT) return getConstantArrayType(ResultType, LCAT->getSize(),
ArrayType::ArraySizeModifier(), 0);
if (RCAT) return getConstantArrayType(ResultType, RCAT->getSize(),
ArrayType::ArraySizeModifier(), 0);
if (LCAT)
return getConstantArrayType(ResultType, LCAT->getSize(),
LCAT->getSizeExpr(),
ArrayType::ArraySizeModifier(), 0);
if (RCAT)
return getConstantArrayType(ResultType, RCAT->getSize(),
RCAT->getSizeExpr(),
ArrayType::ArraySizeModifier(), 0);
if (LVAT && getCanonicalType(LHSElem) == getCanonicalType(ResultType))
return LHS;
if (RVAT && getCanonicalType(RHSElem) == getCanonicalType(ResultType))
Expand Down Expand Up @@ -10317,7 +10334,7 @@ QualType ASTContext::getStringLiteralArrayType(QualType EltTy,

// Get an array type for the string, according to C99 6.4.5. This includes
// the null terminator character.
return getConstantArrayType(EltTy, llvm::APInt(32, Length + 1),
return getConstantArrayType(EltTy, llvm::APInt(32, Length + 1), nullptr,
ArrayType::Normal, /*IndexTypeQuals*/ 0);
}

Expand Down
16 changes: 9 additions & 7 deletions clang/lib/AST/ASTImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1098,14 +1098,16 @@ ASTNodeImporter::VisitMemberPointerType(const MemberPointerType *T) {

ExpectedType
ASTNodeImporter::VisitConstantArrayType(const ConstantArrayType *T) {
ExpectedType ToElementTypeOrErr = import(T->getElementType());
if (!ToElementTypeOrErr)
return ToElementTypeOrErr.takeError();
QualType ToElementType;
const Expr *ToSizeExpr;
if (auto Imp = importSeq(T->getElementType(), T->getSizeExpr()))
std::tie(ToElementType, ToSizeExpr) = *Imp;
else
return Imp.takeError();

return Importer.getToContext().getConstantArrayType(*ToElementTypeOrErr,
T->getSize(),
T->getSizeModifier(),
T->getIndexTypeCVRQualifiers());
return Importer.getToContext().getConstantArrayType(
ToElementType, T->getSize(), ToSizeExpr, T->getSizeModifier(),
T->getIndexTypeCVRQualifiers());
}

ExpectedType
Expand Down
6 changes: 3 additions & 3 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6004,8 +6004,8 @@ static bool HandleOperatorNewCall(EvalInfo &Info, const CallExpr *E,
return false;
}

QualType AllocType =
Info.Ctx.getConstantArrayType(ElemType, Size, ArrayType::Normal, 0);
QualType AllocType = Info.Ctx.getConstantArrayType(ElemType, Size, nullptr,
ArrayType::Normal, 0);
APValue *Val = Info.createHeapAlloc(E, AllocType, Result);
*Val = APValue(APValue::UninitArray(), 0, Size.getZExtValue());
Result.addArray(Info, E, cast<ConstantArrayType>(AllocType));
Expand Down Expand Up @@ -8561,7 +8561,7 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
ResizedArrayILE = cast<InitListExpr>(Init);
}

AllocType = Info.Ctx.getConstantArrayType(AllocType, ArrayBound,
AllocType = Info.Ctx.getConstantArrayType(AllocType, ArrayBound, nullptr,
ArrayType::Normal, 0);
} else {
assert(!AllocType->isArrayType() &&
Expand Down
Loading

0 comments on commit 772e266

Please sign in to comment.