18 changes: 10 additions & 8 deletions clang/lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2913,10 +2913,10 @@ VarDecl::setInstantiationOfStaticDataMember(VarDecl *VD,
//===----------------------------------------------------------------------===//

ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation StartLoc,
SourceLocation IdLoc, IdentifierInfo *Id,
QualType T, TypeSourceInfo *TInfo,
StorageClass S, Expr *DefArg) {
SourceLocation StartLoc, SourceLocation IdLoc,
const IdentifierInfo *Id, QualType T,
TypeSourceInfo *TInfo, StorageClass S,
Expr *DefArg) {
return new (C, DC) ParmVarDecl(ParmVar, C, DC, StartLoc, IdLoc, Id, T, TInfo,
S, DefArg);
}
Expand Down Expand Up @@ -4511,7 +4511,7 @@ unsigned FunctionDecl::getODRHash() {

FieldDecl *FieldDecl::Create(const ASTContext &C, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
IdentifierInfo *Id, QualType T,
const IdentifierInfo *Id, QualType T,
TypeSourceInfo *TInfo, Expr *BW, bool Mutable,
InClassInitStyle InitStyle) {
return new (C, DC) FieldDecl(Decl::Field, DC, StartLoc, IdLoc, Id, T, TInfo,
Expand Down Expand Up @@ -5438,7 +5438,7 @@ IndirectFieldDecl::IndirectFieldDecl(ASTContext &C, DeclContext *DC,

IndirectFieldDecl *
IndirectFieldDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
IdentifierInfo *Id, QualType T,
const IdentifierInfo *Id, QualType T,
llvm::MutableArrayRef<NamedDecl *> CH) {
return new (C, DC) IndirectFieldDecl(C, DC, L, Id, T, CH);
}
Expand All @@ -5461,7 +5461,8 @@ void TypeDecl::anchor() {}

TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
IdentifierInfo *Id, TypeSourceInfo *TInfo) {
const IdentifierInfo *Id,
TypeSourceInfo *TInfo) {
return new (C, DC) TypedefDecl(C, DC, StartLoc, IdLoc, Id, TInfo);
}

Expand Down Expand Up @@ -5511,7 +5512,8 @@ TypedefDecl *TypedefDecl::CreateDeserialized(ASTContext &C, unsigned ID) {

TypeAliasDecl *TypeAliasDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation StartLoc,
SourceLocation IdLoc, IdentifierInfo *Id,
SourceLocation IdLoc,
const IdentifierInfo *Id,
TypeSourceInfo *TInfo) {
return new (C, DC) TypeAliasDecl(C, DC, StartLoc, IdLoc, Id, TInfo);
}
Expand Down
94 changes: 38 additions & 56 deletions clang/lib/AST/DeclObjC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ void ObjCProtocolList::set(ObjCProtocolDecl* const* InList, unsigned Elts,
//===----------------------------------------------------------------------===//

ObjCContainerDecl::ObjCContainerDecl(Kind DK, DeclContext *DC,
IdentifierInfo *Id, SourceLocation nameLoc,
const IdentifierInfo *Id,
SourceLocation nameLoc,
SourceLocation atStartLoc)
: NamedDecl(DK, DC, nameLoc, Id), DeclContext(DK) {
setAtStartLoc(atStartLoc);
Expand Down Expand Up @@ -378,10 +379,8 @@ SourceLocation ObjCInterfaceDecl::getSuperClassLoc() const {
/// FindPropertyVisibleInPrimaryClass - Finds declaration of the property
/// with name 'PropertyId' in the primary class; including those in protocols
/// (direct or indirect) used by the primary class.
ObjCPropertyDecl *
ObjCInterfaceDecl::FindPropertyVisibleInPrimaryClass(
IdentifierInfo *PropertyId,
ObjCPropertyQueryKind QueryKind) const {
ObjCPropertyDecl *ObjCInterfaceDecl::FindPropertyVisibleInPrimaryClass(
const IdentifierInfo *PropertyId, ObjCPropertyQueryKind QueryKind) const {
// FIXME: Should make sure no callers ever do this.
if (!hasDefinition())
return nullptr;
Expand Down Expand Up @@ -1539,14 +1538,10 @@ void ObjCTypeParamList::gatherDefaultTypeArgs(
// ObjCInterfaceDecl
//===----------------------------------------------------------------------===//

ObjCInterfaceDecl *ObjCInterfaceDecl::Create(const ASTContext &C,
DeclContext *DC,
SourceLocation atLoc,
IdentifierInfo *Id,
ObjCTypeParamList *typeParamList,
ObjCInterfaceDecl *PrevDecl,
SourceLocation ClassLoc,
bool isInternal){
ObjCInterfaceDecl *ObjCInterfaceDecl::Create(
const ASTContext &C, DeclContext *DC, SourceLocation atLoc,
const IdentifierInfo *Id, ObjCTypeParamList *typeParamList,
ObjCInterfaceDecl *PrevDecl, SourceLocation ClassLoc, bool isInternal) {
auto *Result = new (C, DC)
ObjCInterfaceDecl(C, DC, atLoc, Id, typeParamList, ClassLoc, PrevDecl,
isInternal);
Expand All @@ -1564,12 +1559,10 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::CreateDeserialized(const ASTContext &C,
return Result;
}

ObjCInterfaceDecl::ObjCInterfaceDecl(const ASTContext &C, DeclContext *DC,
SourceLocation AtLoc, IdentifierInfo *Id,
ObjCTypeParamList *typeParamList,
SourceLocation CLoc,
ObjCInterfaceDecl *PrevDecl,
bool IsInternal)
ObjCInterfaceDecl::ObjCInterfaceDecl(
const ASTContext &C, DeclContext *DC, SourceLocation AtLoc,
const IdentifierInfo *Id, ObjCTypeParamList *typeParamList,
SourceLocation CLoc, ObjCInterfaceDecl *PrevDecl, bool IsInternal)
: ObjCContainerDecl(ObjCInterface, DC, Id, CLoc, AtLoc),
redeclarable_base(C) {
setPreviousDecl(PrevDecl);
Expand Down Expand Up @@ -1751,8 +1744,8 @@ ObjCIvarDecl *ObjCInterfaceDecl::all_declared_ivar_begin() {
/// categories for this class and returns it. Name of the category is passed
/// in 'CategoryId'. If category not found, return 0;
///
ObjCCategoryDecl *
ObjCInterfaceDecl::FindCategoryDeclaration(IdentifierInfo *CategoryId) const {
ObjCCategoryDecl *ObjCInterfaceDecl::FindCategoryDeclaration(
const IdentifierInfo *CategoryId) const {
// FIXME: Should make sure no callers ever do this.
if (!hasDefinition())
return nullptr;
Expand Down Expand Up @@ -1838,10 +1831,10 @@ void ObjCIvarDecl::anchor() {}

ObjCIvarDecl *ObjCIvarDecl::Create(ASTContext &C, ObjCContainerDecl *DC,
SourceLocation StartLoc,
SourceLocation IdLoc, IdentifierInfo *Id,
QualType T, TypeSourceInfo *TInfo,
AccessControl ac, Expr *BW,
bool synthesized) {
SourceLocation IdLoc,
const IdentifierInfo *Id, QualType T,
TypeSourceInfo *TInfo, AccessControl ac,
Expr *BW, bool synthesized) {
if (DC) {
// Ivar's can only appear in interfaces, implementations (via synthesized
// properties), and class extensions (via direct declaration, or synthesized
Expand Down Expand Up @@ -2120,28 +2113,23 @@ void ObjCProtocolDecl::setHasODRHash(bool HasHash) {

void ObjCCategoryDecl::anchor() {}

ObjCCategoryDecl::ObjCCategoryDecl(DeclContext *DC, SourceLocation AtLoc,
SourceLocation ClassNameLoc,
SourceLocation CategoryNameLoc,
IdentifierInfo *Id, ObjCInterfaceDecl *IDecl,
ObjCTypeParamList *typeParamList,
SourceLocation IvarLBraceLoc,
SourceLocation IvarRBraceLoc)
ObjCCategoryDecl::ObjCCategoryDecl(
DeclContext *DC, SourceLocation AtLoc, SourceLocation ClassNameLoc,
SourceLocation CategoryNameLoc, const IdentifierInfo *Id,
ObjCInterfaceDecl *IDecl, ObjCTypeParamList *typeParamList,
SourceLocation IvarLBraceLoc, SourceLocation IvarRBraceLoc)
: ObjCContainerDecl(ObjCCategory, DC, Id, ClassNameLoc, AtLoc),
ClassInterface(IDecl), CategoryNameLoc(CategoryNameLoc),
IvarLBraceLoc(IvarLBraceLoc), IvarRBraceLoc(IvarRBraceLoc) {
setTypeParamList(typeParamList);
}

ObjCCategoryDecl *ObjCCategoryDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation AtLoc,
SourceLocation ClassNameLoc,
SourceLocation CategoryNameLoc,
IdentifierInfo *Id,
ObjCInterfaceDecl *IDecl,
ObjCTypeParamList *typeParamList,
SourceLocation IvarLBraceLoc,
SourceLocation IvarRBraceLoc) {
ObjCCategoryDecl *ObjCCategoryDecl::Create(
ASTContext &C, DeclContext *DC, SourceLocation AtLoc,
SourceLocation ClassNameLoc, SourceLocation CategoryNameLoc,
const IdentifierInfo *Id, ObjCInterfaceDecl *IDecl,
ObjCTypeParamList *typeParamList, SourceLocation IvarLBraceLoc,
SourceLocation IvarRBraceLoc) {
auto *CatDecl =
new (C, DC) ObjCCategoryDecl(DC, AtLoc, ClassNameLoc, CategoryNameLoc, Id,
IDecl, typeParamList, IvarLBraceLoc,
Expand Down Expand Up @@ -2190,13 +2178,10 @@ void ObjCCategoryDecl::setTypeParamList(ObjCTypeParamList *TPL) {

void ObjCCategoryImplDecl::anchor() {}

ObjCCategoryImplDecl *
ObjCCategoryImplDecl::Create(ASTContext &C, DeclContext *DC,
IdentifierInfo *Id,
ObjCInterfaceDecl *ClassInterface,
SourceLocation nameLoc,
SourceLocation atStartLoc,
SourceLocation CategoryNameLoc) {
ObjCCategoryImplDecl *ObjCCategoryImplDecl::Create(
ASTContext &C, DeclContext *DC, const IdentifierInfo *Id,
ObjCInterfaceDecl *ClassInterface, SourceLocation nameLoc,
SourceLocation atStartLoc, SourceLocation CategoryNameLoc) {
if (ClassInterface && ClassInterface->hasDefinition())
ClassInterface = ClassInterface->getDefinition();
return new (C, DC) ObjCCategoryImplDecl(DC, Id, ClassInterface, nameLoc,
Expand Down Expand Up @@ -2365,14 +2350,11 @@ ObjCCompatibleAliasDecl::CreateDeserialized(ASTContext &C, unsigned ID) {

void ObjCPropertyDecl::anchor() {}

ObjCPropertyDecl *ObjCPropertyDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
IdentifierInfo *Id,
SourceLocation AtLoc,
SourceLocation LParenLoc,
QualType T,
TypeSourceInfo *TSI,
PropertyControl propControl) {
ObjCPropertyDecl *
ObjCPropertyDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
const IdentifierInfo *Id, SourceLocation AtLoc,
SourceLocation LParenLoc, QualType T,
TypeSourceInfo *TSI, PropertyControl propControl) {
return new (C, DC) ObjCPropertyDecl(DC, L, Id, AtLoc, LParenLoc, T, TSI,
propControl);
}
Expand Down
179 changes: 47 additions & 132 deletions clang/lib/AST/DeclPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/PrettyPrinter.h"
#include "clang/Basic/Module.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;

Expand Down Expand Up @@ -49,18 +50,6 @@ namespace {

void PrintObjCTypeParams(ObjCTypeParamList *Params);

enum class AttrPrintLoc {
None = 0,
Left = 1,
Right = 2,
Any = Left | Right,

LLVM_MARK_AS_BITMASK_ENUM(/*DefaultValue=*/Any)
};

void prettyPrintAttributes(Decl *D, raw_ostream &out,
AttrPrintLoc loc = AttrPrintLoc::Any);

public:
DeclPrinter(raw_ostream &Out, const PrintingPolicy &Policy,
const ASTContext &Context, unsigned Indentation = 0,
Expand Down Expand Up @@ -129,11 +118,10 @@ namespace {
const TemplateParameterList *Params);
void printTemplateArguments(llvm::ArrayRef<TemplateArgumentLoc> Args,
const TemplateParameterList *Params);

inline void prettyPrintAttributes(Decl *D) {
prettyPrintAttributes(D, Out);
}

enum class AttrPosAsWritten { Default = 0, Left, Right };
void
prettyPrintAttributes(const Decl *D,
AttrPosAsWritten Pos = AttrPosAsWritten::Default);
void prettyPrintPragmas(Decl *D);
void printDeclType(QualType T, StringRef DeclName, bool Pack = false);
};
Expand Down Expand Up @@ -250,87 +238,48 @@ raw_ostream& DeclPrinter::Indent(unsigned Indentation) {
return Out;
}

// For CLANG_ATTR_LIST_CanPrintOnLeft macro.
#include "clang/Basic/AttrLeftSideCanPrintList.inc"
static DeclPrinter::AttrPosAsWritten getPosAsWritten(const Attr *A,
const Decl *D) {
SourceLocation ALoc = A->getLoc();
SourceLocation DLoc = D->getLocation();
const ASTContext &C = D->getASTContext();
if (ALoc.isInvalid() || DLoc.isInvalid())
return DeclPrinter::AttrPosAsWritten::Left;

// For CLANG_ATTR_LIST_PrintOnLeft macro.
#include "clang/Basic/AttrLeftSideMustPrintList.inc"
if (C.getSourceManager().isBeforeInTranslationUnit(ALoc, DLoc))
return DeclPrinter::AttrPosAsWritten::Left;

static bool canPrintOnLeftSide(attr::Kind kind) {
#ifdef CLANG_ATTR_LIST_CanPrintOnLeft
switch (kind) {
CLANG_ATTR_LIST_CanPrintOnLeft
return true;
default:
return false;
}
#else
return false;
#endif
}

static bool canPrintOnLeftSide(const Attr *A) {
if (A->isStandardAttributeSyntax())
return false;

return canPrintOnLeftSide(A->getKind());
return DeclPrinter::AttrPosAsWritten::Right;
}

static bool mustPrintOnLeftSide(attr::Kind kind) {
#ifdef CLANG_ATTR_LIST_PrintOnLeft
switch (kind) {
CLANG_ATTR_LIST_PrintOnLeft
return true;
default:
return false;
}
#else
return false;
#endif
}

static bool mustPrintOnLeftSide(const Attr *A) {
if (A->isDeclspecAttribute())
return true;

return mustPrintOnLeftSide(A->getKind());
}

void DeclPrinter::prettyPrintAttributes(Decl *D, llvm::raw_ostream &Out,
AttrPrintLoc Loc) {
void DeclPrinter::prettyPrintAttributes(const Decl *D,
AttrPosAsWritten Pos /*=Default*/) {
if (Policy.PolishForDeclaration)
return;

if (D->hasAttrs()) {
AttrVec &Attrs = D->getAttrs();
const AttrVec &Attrs = D->getAttrs();
for (auto *A : Attrs) {
if (A->isInherited() || A->isImplicit())
continue;

AttrPrintLoc AttrLoc = AttrPrintLoc::Right;
if (mustPrintOnLeftSide(A)) {
// If we must always print on left side (e.g. declspec), then mark as
// so.
AttrLoc = AttrPrintLoc::Left;
} else if (canPrintOnLeftSide(A)) {
// For functions with body defined we print the attributes on the left
// side so that GCC accept our dumps as well.
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
FD && FD->isThisDeclarationADefinition())
// In case Decl is a function with a body, then attrs should be print
// on the left side.
AttrLoc = AttrPrintLoc::Left;

// In case it is a variable declaration with a ctor, then allow
// printing on the left side for readbility.
else if (const VarDecl *VD = dyn_cast<VarDecl>(D);
VD && VD->getInit() &&
VD->getInitStyle() == VarDecl::CallInit)
AttrLoc = AttrPrintLoc::Left;
switch (A->getKind()) {
#define ATTR(X)
#define PRAGMA_SPELLING_ATTR(X) case attr::X:
#include "clang/Basic/AttrList.inc"
break;
default:
AttrPosAsWritten APos = getPosAsWritten(A, D);
assert(APos != AttrPosAsWritten::Default &&
"Default not a valid for an attribute location");
if (Pos == AttrPosAsWritten::Default || Pos == APos) {
if (Pos != AttrPosAsWritten::Left)
Out << ' ';
A->printPretty(Out, Policy);
if (Pos == AttrPosAsWritten::Left)
Out << ' ';
}
break;
}
// Only print the side matches the user requested.
if ((Loc & AttrLoc) != AttrPrintLoc::None)
A->printPretty(Out, Policy);
}
}
}
Expand Down Expand Up @@ -691,8 +640,10 @@ static void MaybePrintTagKeywordIfSupressingScopes(PrintingPolicy &Policy,

void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
if (!D->getDescribedFunctionTemplate() &&
!D->isFunctionTemplateSpecialization())
!D->isFunctionTemplateSpecialization()) {
prettyPrintPragmas(D);
prettyPrintAttributes(D, AttrPosAsWritten::Left);
}

if (D->isFunctionTemplateSpecialization())
Out << "template<> ";
Expand All @@ -702,22 +653,6 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
printTemplateParameters(D->getTemplateParameterList(I));
}

std::string LeftsideAttrs;
llvm::raw_string_ostream LSAS(LeftsideAttrs);

prettyPrintAttributes(D, LSAS, AttrPrintLoc::Left);

// prettyPrintAttributes print a space on left side of the attribute.
if (LeftsideAttrs[0] == ' ') {
// Skip the space prettyPrintAttributes generated.
LeftsideAttrs.erase(0, LeftsideAttrs.find_first_not_of(' '));

// Add a single space between the attribute and the Decl name.
LSAS << ' ';
}

Out << LeftsideAttrs;

CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D);
CXXConversionDecl *ConversionDecl = dyn_cast<CXXConversionDecl>(D);
CXXDeductionGuideDecl *GuideDecl = dyn_cast<CXXDeductionGuideDecl>(D);
Expand Down Expand Up @@ -883,7 +818,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
Ty.print(Out, Policy, Proto);
}

prettyPrintAttributes(D, Out, AttrPrintLoc::Right);
prettyPrintAttributes(D, AttrPosAsWritten::Right);

if (D->isPureVirtual())
Out << " = 0";
Expand Down Expand Up @@ -976,27 +911,12 @@ void DeclPrinter::VisitLabelDecl(LabelDecl *D) {
void DeclPrinter::VisitVarDecl(VarDecl *D) {
prettyPrintPragmas(D);

prettyPrintAttributes(D, AttrPosAsWritten::Left);

if (const auto *Param = dyn_cast<ParmVarDecl>(D);
Param && Param->isExplicitObjectParameter())
Out << "this ";

std::string LeftSide;
llvm::raw_string_ostream LeftSideStream(LeftSide);

// Print attributes that should be placed on the left, such as __declspec.
prettyPrintAttributes(D, LeftSideStream, AttrPrintLoc::Left);

// prettyPrintAttributes print a space on left side of the attribute.
if (LeftSide[0] == ' ') {
// Skip the space prettyPrintAttributes generated.
LeftSide.erase(0, LeftSide.find_first_not_of(' '));

// Add a single space between the attribute and the Decl name.
LeftSideStream << ' ';
}

Out << LeftSide;

QualType T = D->getTypeSourceInfo()
? D->getTypeSourceInfo()->getType()
: D->getASTContext().getUnqualifiedObjCPointerType(D->getType());
Expand Down Expand Up @@ -1029,21 +949,16 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) {
}
}

StringRef Name;

Name = (isa<ParmVarDecl>(D) && Policy.CleanUglifiedParameters &&
D->getIdentifier())
? D->getIdentifier()->deuglifiedName()
: D->getName();

if (!Policy.SuppressTagKeyword && Policy.SuppressScope &&
!Policy.SuppressUnwrittenScope)
MaybePrintTagKeywordIfSupressingScopes(Policy, T, Out);
printDeclType(T, Name);

// Print the attributes that should be placed right before the end of the
// decl.
prettyPrintAttributes(D, Out, AttrPrintLoc::Right);
printDeclType(T, (isa<ParmVarDecl>(D) && Policy.CleanUglifiedParameters &&
D->getIdentifier())
? D->getIdentifier()->deuglifiedName()
: D->getName());

prettyPrintAttributes(D, AttrPosAsWritten::Right);

Expr *Init = D->getInit();
if (!Policy.SuppressInitializers && Init) {
Expand Down
14 changes: 6 additions & 8 deletions clang/lib/AST/DeclTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -715,7 +715,7 @@ void TemplateTypeParmDecl::setTypeConstraint(

NonTypeTemplateParmDecl::NonTypeTemplateParmDecl(
DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, unsigned D,
unsigned P, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo,
unsigned P, const IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo,
ArrayRef<QualType> ExpandedTypes, ArrayRef<TypeSourceInfo *> ExpandedTInfos)
: DeclaratorDecl(NonTypeTemplateParm, DC, IdLoc, Id, T, TInfo, StartLoc),
TemplateParmPosition(D, P), ParameterPack(true),
Expand All @@ -730,12 +730,10 @@ NonTypeTemplateParmDecl::NonTypeTemplateParmDecl(
}
}

NonTypeTemplateParmDecl *
NonTypeTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
unsigned D, unsigned P, IdentifierInfo *Id,
QualType T, bool ParameterPack,
TypeSourceInfo *TInfo) {
NonTypeTemplateParmDecl *NonTypeTemplateParmDecl::Create(
const ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, unsigned D, unsigned P, const IdentifierInfo *Id,
QualType T, bool ParameterPack, TypeSourceInfo *TInfo) {
AutoType *AT =
C.getLangOpts().CPlusPlus20 ? T->getContainedAutoType() : nullptr;
return new (C, DC,
Expand All @@ -748,7 +746,7 @@ NonTypeTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,

NonTypeTemplateParmDecl *NonTypeTemplateParmDecl::Create(
const ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, unsigned D, unsigned P, IdentifierInfo *Id,
SourceLocation IdLoc, unsigned D, unsigned P, const IdentifierInfo *Id,
QualType T, TypeSourceInfo *TInfo, ArrayRef<QualType> ExpandedTypes,
ArrayRef<TypeSourceInfo *> ExpandedTInfos) {
AutoType *AT = TInfo->getType()->getContainedAutoType();
Expand Down
112 changes: 102 additions & 10 deletions clang/lib/AST/Interp/ByteCodeExprGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,10 +173,18 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
return this->emitCastFloatingIntegral(*ToT, CE);
}

case CK_NullToPointer:
case CK_NullToPointer: {
if (DiscardResult)
return true;
return this->emitNull(classifyPrim(CE->getType()), CE);

const Descriptor *Desc = nullptr;
const QualType PointeeType = CE->getType()->getPointeeType();
if (!PointeeType.isNull()) {
if (std::optional<PrimType> T = classify(PointeeType))
Desc = P.createDescriptor(SubExpr, *T);
}
return this->emitNull(classifyPrim(CE->getType()), Desc, CE);
}

case CK_PointerToIntegral: {
if (DiscardResult)
Expand All @@ -199,6 +207,41 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
return true;
}

case CK_IntegralToPointer: {
QualType IntType = SubExpr->getType();
assert(IntType->isIntegralOrEnumerationType());
if (!this->visit(SubExpr))
return false;
// FIXME: I think the discard is wrong since the int->ptr cast might cause a
// diagnostic.
PrimType T = classifyPrim(IntType);
if (DiscardResult)
return this->emitPop(T, CE);

QualType PtrType = CE->getType();
assert(PtrType->isPointerType());

const Descriptor *Desc;
if (std::optional<PrimType> T = classify(PtrType->getPointeeType()))
Desc = P.createDescriptor(SubExpr, *T);
else if (PtrType->getPointeeType()->isVoidType())
Desc = nullptr;
else
Desc = P.createDescriptor(CE, PtrType->getPointeeType().getTypePtr(),
Descriptor::InlineDescMD, true, false,
/*IsMutable=*/false, nullptr);

if (!this->emitGetIntPtr(T, Desc, CE))
return false;

PrimType DestPtrT = classifyPrim(PtrType);
if (DestPtrT == PT_Ptr)
return true;

// In case we're converting the integer to a non-Pointer.
return this->emitDecayPtr(PT_Ptr, DestPtrT, CE);
}

case CK_AtomicToNonAtomic:
case CK_ConstructorConversion:
case CK_FunctionToPointerDecay:
Expand All @@ -207,13 +250,31 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
case CK_UserDefinedConversion:
return this->delegate(SubExpr);

case CK_BitCast:
case CK_BitCast: {
// Reject bitcasts to atomic types.
if (CE->getType()->isAtomicType()) {
if (!this->discard(SubExpr))
return false;
return this->emitInvalidCast(CastKind::Reinterpret, CE);
}
return this->delegate(SubExpr);

if (DiscardResult)
return this->discard(SubExpr);

std::optional<PrimType> FromT = classify(SubExpr->getType());
std::optional<PrimType> ToT = classifyPrim(CE->getType());
if (!FromT || !ToT)
return false;

assert(isPtrType(*FromT));
assert(isPtrType(*ToT));
if (FromT == ToT)
return this->delegate(SubExpr);

if (!this->visit(SubExpr))
return false;
return this->emitDecayPtr(*FromT, *ToT, CE);
}

case CK_IntegralToBoolean:
case CK_IntegralCast: {
Expand Down Expand Up @@ -245,7 +306,7 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
if (!this->visit(SubExpr))
return false;

if (!this->emitNull(PtrT, CE))
if (!this->emitNull(PtrT, nullptr, CE))
return false;

return this->emitNE(PtrT, CE);
Expand Down Expand Up @@ -455,7 +516,7 @@ bool ByteCodeExprGen<Emitter>::VisitBinaryOperator(const BinaryOperator *BO) {

// Pointer arithmetic special case.
if (BO->getOpcode() == BO_Add || BO->getOpcode() == BO_Sub) {
if (T == PT_Ptr || (LT == PT_Ptr && RT == PT_Ptr))
if (isPtrType(*T) || (isPtrType(*LT) && isPtrType(*RT)))
return this->VisitPointerArithBinOp(BO);
}

Expand Down Expand Up @@ -1033,6 +1094,34 @@ bool ByteCodeExprGen<Emitter>::VisitInitListExpr(const InitListExpr *E) {
return true;
}

if (const auto *VecT = E->getType()->getAs<VectorType>()) {
unsigned NumVecElements = VecT->getNumElements();
assert(NumVecElements >= E->getNumInits());

QualType ElemQT = VecT->getElementType();
PrimType ElemT = classifyPrim(ElemQT);

// All initializer elements.
unsigned InitIndex = 0;
for (const Expr *Init : E->inits()) {
if (!this->visit(Init))
return false;

if (!this->emitInitElem(ElemT, InitIndex, E))
return false;
++InitIndex;
}

// Fill the rest with zeroes.
for (; InitIndex != NumVecElements; ++InitIndex) {
if (!this->visitZeroInitializer(ElemT, ElemQT, E))
return false;
if (!this->emitInitElem(ElemT, InitIndex, E))
return false;
}
return true;
}

return false;
}

Expand Down Expand Up @@ -1084,6 +1173,9 @@ static CharUnits AlignOfType(QualType T, const ASTContext &ASTCtx,
if (const auto *Ref = T->getAs<ReferenceType>())
T = Ref->getPointeeType();

if (T.getQualifiers().hasUnaligned())
return CharUnits::One();

// __alignof is defined to return the preferred alignment.
// Before 8, clang returned the preferred alignment for alignof and
// _Alignof as well.
Expand Down Expand Up @@ -2323,7 +2415,7 @@ bool ByteCodeExprGen<Emitter>::visitBool(const Expr *E) {

// Convert pointers to bool.
if (T == PT_Ptr || T == PT_FnPtr) {
if (!this->emitNull(*T, E))
if (!this->emitNull(*T, nullptr, E))
return false;
return this->emitNE(*T, E);
}
Expand Down Expand Up @@ -2363,9 +2455,9 @@ bool ByteCodeExprGen<Emitter>::visitZeroInitializer(PrimType T, QualType QT,
case PT_IntAPS:
return this->emitZeroIntAPS(Ctx.getBitWidth(QT), E);
case PT_Ptr:
return this->emitNullPtr(E);
return this->emitNullPtr(nullptr, E);
case PT_FnPtr:
return this->emitNullFnPtr(E);
return this->emitNullFnPtr(nullptr, E);
case PT_Float: {
return this->emitConstFloat(APFloat::getZero(Ctx.getFloatSemantics(QT)), E);
}
Expand Down Expand Up @@ -2949,7 +3041,7 @@ bool ByteCodeExprGen<Emitter>::VisitCXXNullPtrLiteralExpr(
if (DiscardResult)
return true;

return this->emitNullPtr(E);
return this->emitNullPtr(nullptr, E);
}

template <class Emitter>
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/Interp/ByteCodeStmtGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ bool ByteCodeStmtGen<Emitter>::emitLambdaStaticInvokerBody(
// one here, and we don't need one either because the lambda cannot have
// any captures, as verified above. Emit a null pointer. This is then
// special-cased when interpreting to not emit any misleading diagnostics.
if (!this->emitNullPtr(MD))
if (!this->emitNullPtr(nullptr, MD))
return false;

// Forward all arguments from the static invoker to the lambda call operator.
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/AST/Interp/Context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,8 @@ std::optional<PrimType> Context::classify(QualType T) const {
if (T->isBooleanType())
return PT_Bool;

if (T->isAnyComplexType())
// We map these to primitive arrays.
if (T->isAnyComplexType() || T->isVectorType())
return std::nullopt;

if (T->isSignedIntegerOrEnumerationType()) {
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/Interp/Descriptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ struct Descriptor final {

const Decl *asDecl() const { return Source.dyn_cast<const Decl *>(); }
const Expr *asExpr() const { return Source.dyn_cast<const Expr *>(); }
const DeclTy &getSource() const { return Source; }

const ValueDecl *asValueDecl() const {
return dyn_cast_if_present<ValueDecl>(asDecl());
Expand Down
31 changes: 31 additions & 0 deletions clang/lib/AST/Interp/Disasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -233,3 +233,34 @@ LLVM_DUMP_METHOD void InterpFrame::dump(llvm::raw_ostream &OS,
F = F->Caller;
}
}

LLVM_DUMP_METHOD void Record::dump(llvm::raw_ostream &OS, unsigned Indentation,
unsigned Offset) const {
unsigned Indent = Indentation * 2;
OS.indent(Indent);
{
ColorScope SC(OS, true, {llvm::raw_ostream::BLUE, true});
OS << getName() << "\n";
}

unsigned I = 0;
for (const Record::Base &B : bases()) {
OS.indent(Indent) << "- Base " << I << ". Offset " << (Offset + B.Offset)
<< "\n";
B.R->dump(OS, Indentation + 1, Offset + B.Offset);
++I;
}

// FIXME: Virtual bases.

I = 0;
for (const Record::Field &F : fields()) {
OS.indent(Indent) << "- Field " << I << ": ";
{
ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_RED, true});
OS << F.Decl->getName();
}
OS << ". Offset " << (Offset + F.Offset) << "\n";
++I;
}
}
3 changes: 2 additions & 1 deletion clang/lib/AST/Interp/EvalEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ EvaluationResult EvalEmitter::interpretDecl(const VarDecl *VD,
this->CheckFullyInitialized = CheckFullyInitialized;
this->ConvertResultToRValue =
VD->getAnyInitializer() &&
(VD->getAnyInitializer()->getType()->isAnyComplexType());
(VD->getAnyInitializer()->getType()->isAnyComplexType() ||
VD->getAnyInitializer()->getType()->isVectorType());
EvalResult.setSource(VD);

if (!this->visitDecl(VD) && EvalResult.empty())
Expand Down
10 changes: 9 additions & 1 deletion clang/lib/AST/Interp/FunctionPointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ class FunctionPointer final {
const Function *Func;

public:
FunctionPointer() : Func(nullptr) {}
// FIXME: We might want to track the fact that the Function pointer
// has been created from an integer and is most likely garbage anyway.
FunctionPointer(uintptr_t IntVal = 0, const Descriptor *Desc = nullptr)
: Func(reinterpret_cast<const Function *>(IntVal)) {}

FunctionPointer(const Function *Func) : Func(Func) { assert(Func); }

const Function *getFunction() const { return Func; }
Expand Down Expand Up @@ -53,6 +57,10 @@ class FunctionPointer final {
return toAPValue().getAsString(Ctx, Func->getDecl()->getType());
}

uint64_t getIntegerRepresentation() const {
return static_cast<uint64_t>(reinterpret_cast<uintptr_t>(Func));
}

ComparisonCategoryResult compare(const FunctionPointer &RHS) const {
if (Func == RHS.Func)
return ComparisonCategoryResult::Equal;
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/AST/Interp/Interp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,8 @@ bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
}

static bool CheckConstant(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
if (Ptr.isIntegralPointer())
return true;
return CheckConstant(S, OpPC, Ptr.getDeclDesc());
}

Expand Down Expand Up @@ -335,6 +337,9 @@ bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
return true;
}

if (!Ptr.isBlockPointer())
return false;

const QualType Ty = Ptr.getType();
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_modify_const_type) << Ty;
Expand Down
107 changes: 84 additions & 23 deletions clang/lib/AST/Interp/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -801,6 +801,17 @@ inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
return true;
}

for (const auto &P : {LHS, RHS}) {
if (P.isZero())
continue;
if (P.isWeak()) {
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison)
<< P.toDiagnosticString(S.getCtx());
return false;
}
}

if (!Pointer::hasSameBase(LHS, RHS)) {
S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Unordered)));
return true;
Expand All @@ -812,9 +823,9 @@ inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
// element in the same array are NOT equal. They have the same Base value,
// but a different Offset. This is a pretty rare case, so we fix this here
// by comparing pointers to the first elements.
if (!LHS.isDummy() && LHS.isArrayRoot())
if (!LHS.isZero() && !LHS.isDummy() && LHS.isArrayRoot())
VL = LHS.atIndex(0).getByteOffset();
if (!RHS.isDummy() && RHS.isArrayRoot())
if (!RHS.isZero() && !RHS.isDummy() && RHS.isArrayRoot())
VR = RHS.atIndex(0).getByteOffset();

S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
Expand Down Expand Up @@ -1333,6 +1344,11 @@ inline bool FinishInit(InterpState &S, CodePtr OpPC) {
return true;
}

inline bool Dump(InterpState &S, CodePtr OpPC) {
S.Stk.dump();
return true;
}

inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl,
const Pointer &Ptr) {
Pointer Base = Ptr;
Expand Down Expand Up @@ -1370,6 +1386,8 @@ bool Load(InterpState &S, CodePtr OpPC) {
const Pointer &Ptr = S.Stk.peek<Pointer>();
if (!CheckLoad(S, OpPC, Ptr))
return false;
if (!Ptr.isBlockPointer())
return false;
S.Stk.push<T>(Ptr.deref<T>());
return true;
}
Expand All @@ -1379,6 +1397,8 @@ bool LoadPop(InterpState &S, CodePtr OpPC) {
const Pointer &Ptr = S.Stk.pop<Pointer>();
if (!CheckLoad(S, OpPC, Ptr))
return false;
if (!Ptr.isBlockPointer())
return false;
S.Stk.push<T>(Ptr.deref<T>());
return true;
}
Expand Down Expand Up @@ -1517,8 +1537,12 @@ bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset,
return true;
}

if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex))
return false;
if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex)) {
// The CheckNull will have emitted a note already, but we only
// abort in C++, since this is fine in C.
if (S.getLangOpts().CPlusPlus)
return false;
}

// Arrays of unknown bounds cannot have pointers into them.
if (!CheckArray(S, OpPC, Ptr))
Expand All @@ -1544,23 +1568,25 @@ bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset,
Invalid = true;
};

T MaxOffset = T::from(MaxIndex - Index, Offset.bitWidth());
if constexpr (Op == ArithOp::Add) {
// If the new offset would be negative, bail out.
if (Offset.isNegative() && (Offset.isMin() || -Offset > Index))
DiagInvalidOffset();

// If the new offset would be out of bounds, bail out.
if (Offset.isPositive() && Offset > MaxOffset)
DiagInvalidOffset();
} else {
// If the new offset would be negative, bail out.
if (Offset.isPositive() && Index < Offset)
DiagInvalidOffset();

// If the new offset would be out of bounds, bail out.
if (Offset.isNegative() && (Offset.isMin() || -Offset > MaxOffset))
DiagInvalidOffset();
if (Ptr.isBlockPointer()) {
T MaxOffset = T::from(MaxIndex - Index, Offset.bitWidth());
if constexpr (Op == ArithOp::Add) {
// If the new offset would be negative, bail out.
if (Offset.isNegative() && (Offset.isMin() || -Offset > Index))
DiagInvalidOffset();

// If the new offset would be out of bounds, bail out.
if (Offset.isPositive() && Offset > MaxOffset)
DiagInvalidOffset();
} else {
// If the new offset would be negative, bail out.
if (Offset.isPositive() && Index < Offset)
DiagInvalidOffset();

// If the new offset would be out of bounds, bail out.
if (Offset.isNegative() && (Offset.isMin() || -Offset > MaxOffset))
DiagInvalidOffset();
}
}

if (Invalid && !Ptr.isDummy() && S.getLangOpts().CPlusPlus)
Expand Down Expand Up @@ -1644,6 +1670,11 @@ inline bool SubPtr(InterpState &S, CodePtr OpPC) {
const Pointer &LHS = S.Stk.pop<Pointer>();
const Pointer &RHS = S.Stk.pop<Pointer>();

if (RHS.isZero()) {
S.Stk.push<T>(T::from(LHS.getIndex()));
return true;
}

if (!Pointer::hasSameBase(LHS, RHS) && S.getLangOpts().CPlusPlus) {
// TODO: Diagnose.
return false;
Expand Down Expand Up @@ -1822,8 +1853,9 @@ static inline bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
}

template <PrimType Name, class T = typename PrimConv<Name>::T>
inline bool Null(InterpState &S, CodePtr OpPC) {
S.Stk.push<T>();
inline bool Null(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
// Note: Desc can be null.
S.Stk.push<T>(0, Desc);
return true;
}

Expand All @@ -1841,6 +1873,15 @@ inline bool This(InterpState &S, CodePtr OpPC) {
if (!CheckThis(S, OpPC, This))
return false;

// Ensure the This pointer has been cast to the correct base.
if (!This.isDummy()) {
assert(isa<CXXMethodDecl>(S.Current->getFunction()->getDecl()));
assert(This.getRecord());
assert(
This.getRecord()->getDecl() ==
cast<CXXMethodDecl>(S.Current->getFunction()->getDecl())->getParent());
}

S.Stk.push<Pointer>(This);
return true;
}
Expand Down Expand Up @@ -2218,6 +2259,14 @@ inline bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func) {
return true;
}

template <PrimType Name, class T = typename PrimConv<Name>::T>
inline bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
const T &IntVal = S.Stk.pop<T>();

S.Stk.push<Pointer>(static_cast<uint64_t>(IntVal), Desc);
return true;
}

/// Just emit a diagnostic. The expression that caused emission of this
/// op is not valid in a constant context.
inline bool Invalid(InterpState &S, CodePtr OpPC) {
Expand Down Expand Up @@ -2274,6 +2323,18 @@ inline bool CheckNonNullArg(InterpState &S, CodePtr OpPC) {
return false;
}

/// OldPtr -> Integer -> NewPtr.
template <PrimType TIn, PrimType TOut>
inline bool DecayPtr(InterpState &S, CodePtr OpPC) {
static_assert(isPtrType(TIn) && isPtrType(TOut));
using FromT = typename PrimConv<TIn>::T;
using ToT = typename PrimConv<TOut>::T;

const FromT &OldPtr = S.Stk.pop<FromT>();
S.Stk.push<ToT>(ToT(OldPtr.getIntegerRepresentation(), nullptr));
return true;
}

//===----------------------------------------------------------------------===//
// Read opcode arguments
//===----------------------------------------------------------------------===//
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/AST/Interp/InterpBlock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ void Block::replacePointer(Pointer *Old, Pointer *New) {
removePointer(Old);
addPointer(New);

Old->Pointee = nullptr;
Old->PointeeStorage.BS.Pointee = nullptr;

#ifndef NDEBUG
assert(!hasPointer(Old));
Expand Down Expand Up @@ -104,7 +104,7 @@ DeadBlock::DeadBlock(DeadBlock *&Root, Block *Blk)
// Transfer pointers.
B.Pointers = Blk->Pointers;
for (Pointer *P = Blk->Pointers; P; P = P->Next)
P->Pointee = &B;
P->PointeeStorage.BS.Pointee = &B;
}

void DeadBlock::free() {
Expand Down
46 changes: 40 additions & 6 deletions clang/lib/AST/Interp/InterpBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@
namespace clang {
namespace interp {

static unsigned callArgSize(const InterpState &S, const CallExpr *C) {
unsigned O = 0;

for (const Expr *E : C->arguments()) {
O += align(primSize(*S.getContext().classify(E)));
}

return O;
}

template <typename T>
static T getParam(const InterpFrame *Frame, unsigned Index) {
assert(Frame->getFunction()->getNumParams() > Index);
Expand Down Expand Up @@ -816,18 +826,30 @@ static bool interp__builtin_carryop(InterpState &S, CodePtr OpPC,
static bool interp__builtin_clz(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame, const Function *Func,
const CallExpr *Call) {
unsigned CallSize = callArgSize(S, Call);
unsigned BuiltinOp = Func->getBuiltinID();
PrimType ValT = *S.getContext().classify(Call->getArg(0));
const APSInt &Val = peekToAPSInt(S.Stk, ValT);
const APSInt &Val = peekToAPSInt(S.Stk, ValT, CallSize);

// When the argument is 0, the result of GCC builtins is undefined, whereas
// for Microsoft intrinsics, the result is the bit-width of the argument.
bool ZeroIsUndefined = BuiltinOp != Builtin::BI__lzcnt16 &&
BuiltinOp != Builtin::BI__lzcnt &&
BuiltinOp != Builtin::BI__lzcnt64;

if (ZeroIsUndefined && Val == 0)
return false;
if (Val == 0) {
if (Func->getBuiltinID() == Builtin::BI__builtin_clzg &&
Call->getNumArgs() == 2) {
// We have a fallback parameter.
PrimType FallbackT = *S.getContext().classify(Call->getArg(1));
const APSInt &Fallback = peekToAPSInt(S.Stk, FallbackT);
pushInteger(S, Fallback, Call->getType());
return true;
}

if (ZeroIsUndefined)
return false;
}

pushInteger(S, Val.countl_zero(), Call->getType());
return true;
Expand All @@ -836,11 +858,21 @@ static bool interp__builtin_clz(InterpState &S, CodePtr OpPC,
static bool interp__builtin_ctz(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame, const Function *Func,
const CallExpr *Call) {
unsigned CallSize = callArgSize(S, Call);
PrimType ValT = *S.getContext().classify(Call->getArg(0));
const APSInt &Val = peekToAPSInt(S.Stk, ValT);

if (Val == 0)
const APSInt &Val = peekToAPSInt(S.Stk, ValT, CallSize);

if (Val == 0) {
if (Func->getBuiltinID() == Builtin::BI__builtin_ctzg &&
Call->getNumArgs() == 2) {
// We have a fallback parameter.
PrimType FallbackT = *S.getContext().classify(Call->getArg(1));
const APSInt &Fallback = peekToAPSInt(S.Stk, FallbackT);
pushInteger(S, Fallback, Call->getType());
return true;
}
return false;
}

pushInteger(S, Val.countr_zero(), Call->getType());
return true;
Expand Down Expand Up @@ -1223,6 +1255,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
case Builtin::BI__builtin_clzl:
case Builtin::BI__builtin_clzll:
case Builtin::BI__builtin_clzs:
case Builtin::BI__builtin_clzg:
case Builtin::BI__lzcnt16: // Microsoft variants of count leading-zeroes
case Builtin::BI__lzcnt:
case Builtin::BI__lzcnt64:
Expand All @@ -1234,6 +1267,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
case Builtin::BI__builtin_ctzl:
case Builtin::BI__builtin_ctzll:
case Builtin::BI__builtin_ctzs:
case Builtin::BI__builtin_ctzg:
if (!interp__builtin_ctz(S, OpPC, Frame, F, Call))
return false;
break;
Expand Down
17 changes: 17 additions & 0 deletions clang/lib/AST/Interp/Opcodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ def ArgCastKind : ArgType { let Name = "CastKind"; }
def ArgCallExpr : ArgType { let Name = "const CallExpr *"; }
def ArgOffsetOfExpr : ArgType { let Name = "const OffsetOfExpr *"; }
def ArgDeclRef : ArgType { let Name = "const DeclRefExpr *"; }
def ArgDesc : ArgType { let Name = "const Descriptor *"; }
def ArgCCI : ArgType { let Name = "const ComparisonCategoryInfo *"; }

//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -272,6 +273,7 @@ def ZeroIntAPS : Opcode {
// [] -> [Pointer]
def Null : Opcode {
let Types = [PtrTypeClass];
let Args = [ArgDesc];
let HasGroup = 1;
}

Expand Down Expand Up @@ -530,6 +532,11 @@ def GetFnPtr : Opcode {
let Args = [ArgFunction];
}

def GetIntPtr : Opcode {
let Types = [AluTypeClass];
let Args = [ArgDesc];
let HasGroup = 1;
}

//===----------------------------------------------------------------------===//
// Binary operators.
Expand Down Expand Up @@ -662,6 +669,11 @@ def CastPointerIntegral : Opcode {
let HasGroup = 1;
}

def DecayPtr : Opcode {
let Types = [PtrTypeClass, PtrTypeClass];
let HasGroup = 1;
}

//===----------------------------------------------------------------------===//
// Comparison opcodes.
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -723,3 +735,8 @@ def CheckNonNullArg : Opcode {
}

def Memcpy : Opcode;

//===----------------------------------------------------------------------===//
// Debugging.
//===----------------------------------------------------------------------===//
def Dump : Opcode;
191 changes: 152 additions & 39 deletions clang/lib/AST/Interp/Pointer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,60 +26,95 @@ Pointer::Pointer(Block *Pointee)
Pointer::Pointer(Block *Pointee, unsigned BaseAndOffset)
: Pointer(Pointee, BaseAndOffset, BaseAndOffset) {}

Pointer::Pointer(const Pointer &P) : Pointer(P.Pointee, P.Base, P.Offset) {}
Pointer::Pointer(const Pointer &P)
: Offset(P.Offset), PointeeStorage(P.PointeeStorage),
StorageKind(P.StorageKind) {

Pointer::Pointer(Pointer &&P)
: Pointee(P.Pointee), Base(P.Base), Offset(P.Offset) {
if (Pointee)
Pointee->replacePointer(&P, this);
if (isBlockPointer() && PointeeStorage.BS.Pointee)
PointeeStorage.BS.Pointee->addPointer(this);
}

Pointer::Pointer(Block *Pointee, unsigned Base, unsigned Offset)
: Pointee(Pointee), Base(Base), Offset(Offset) {
: Offset(Offset), StorageKind(Storage::Block) {
assert((Base == RootPtrMark || Base % alignof(void *) == 0) && "wrong base");

PointeeStorage.BS = {Pointee, Base};

if (Pointee)
Pointee->addPointer(this);
}

Pointer::Pointer(Pointer &&P)
: Offset(P.Offset), PointeeStorage(P.PointeeStorage),
StorageKind(P.StorageKind) {

if (StorageKind == Storage::Block && PointeeStorage.BS.Pointee)
PointeeStorage.BS.Pointee->replacePointer(&P, this);
}

Pointer::~Pointer() {
if (Pointee) {
Pointee->removePointer(this);
Pointee->cleanup();
if (isIntegralPointer())
return;

if (PointeeStorage.BS.Pointee) {
PointeeStorage.BS.Pointee->removePointer(this);
PointeeStorage.BS.Pointee->cleanup();
}
}

void Pointer::operator=(const Pointer &P) {
Block *Old = Pointee;

if (Pointee)
Pointee->removePointer(this);
if (!this->isIntegralPointer() || !P.isBlockPointer())
assert(P.StorageKind == StorageKind);

Offset = P.Offset;
Base = P.Base;
bool WasBlockPointer = isBlockPointer();
StorageKind = P.StorageKind;
if (StorageKind == Storage::Block) {
Block *Old = PointeeStorage.BS.Pointee;
if (WasBlockPointer && PointeeStorage.BS.Pointee)
PointeeStorage.BS.Pointee->removePointer(this);

Pointee = P.Pointee;
if (Pointee)
Pointee->addPointer(this);
Offset = P.Offset;
PointeeStorage.BS = P.PointeeStorage.BS;

if (PointeeStorage.BS.Pointee)
PointeeStorage.BS.Pointee->addPointer(this);

if (WasBlockPointer && Old)
Old->cleanup();

if (Old)
Old->cleanup();
} else if (StorageKind == Storage::Int) {
PointeeStorage.Int = P.PointeeStorage.Int;
} else {
assert(false && "Unhandled storage kind");
}
}

void Pointer::operator=(Pointer &&P) {
Block *Old = Pointee;
if (!this->isIntegralPointer() || !P.isBlockPointer())
assert(P.StorageKind == StorageKind);

if (Pointee)
Pointee->removePointer(this);
bool WasBlockPointer = isBlockPointer();
StorageKind = P.StorageKind;
if (StorageKind == Storage::Block) {
Block *Old = PointeeStorage.BS.Pointee;
if (WasBlockPointer && PointeeStorage.BS.Pointee)
PointeeStorage.BS.Pointee->removePointer(this);

Offset = P.Offset;
Base = P.Base;
Offset = P.Offset;
PointeeStorage.BS = P.PointeeStorage.BS;

Pointee = P.Pointee;
if (Pointee)
Pointee->replacePointer(&P, this);
if (PointeeStorage.BS.Pointee)
PointeeStorage.BS.Pointee->addPointer(this);

if (Old)
Old->cleanup();
if (WasBlockPointer && Old)
Old->cleanup();

} else if (StorageKind == Storage::Int) {
PointeeStorage.Int = P.PointeeStorage.Int;
} else {
assert(false && "Unhandled storage kind");
}
}

APValue Pointer::toAPValue() const {
Expand All @@ -88,6 +123,11 @@ APValue Pointer::toAPValue() const {
if (isZero())
return APValue(static_cast<const Expr *>(nullptr), CharUnits::Zero(), Path,
/*IsOnePastEnd=*/false, /*IsNullPtr=*/true);
if (isIntegralPointer())
return APValue(static_cast<const Expr *>(nullptr),
CharUnits::fromQuantity(asIntPointer().Value + this->Offset),
Path,
/*IsOnePastEnd=*/false, /*IsNullPtr=*/false);

// Build the lvalue base from the block.
const Descriptor *Desc = getDeclDesc();
Expand Down Expand Up @@ -137,19 +177,52 @@ APValue Pointer::toAPValue() const {
return APValue(Base, Offset, Path, IsOnePastEnd, /*IsNullPtr=*/false);
}

void Pointer::print(llvm::raw_ostream &OS) const {
OS << PointeeStorage.BS.Pointee << " (";
if (isBlockPointer()) {
OS << "Block) {";

if (PointeeStorage.BS.Base == RootPtrMark)
OS << "rootptr, ";
else
OS << PointeeStorage.BS.Base << ", ";

if (Offset == PastEndMark)
OS << "pastend, ";
else
OS << Offset << ", ";

if (isBlockPointer() && PointeeStorage.BS.Pointee)
OS << PointeeStorage.BS.Pointee->getSize();
else
OS << "nullptr";
} else {
OS << "Int) {";
OS << PointeeStorage.Int.Value << ", " << PointeeStorage.Int.Desc;
}
OS << "}";
}

std::string Pointer::toDiagnosticString(const ASTContext &Ctx) const {
if (!Pointee)
if (isZero())
return "nullptr";

if (isIntegralPointer())
return (Twine("&(") + Twine(asIntPointer().Value + Offset) + ")").str();

return toAPValue().getAsString(Ctx, getType());
}

bool Pointer::isInitialized() const {
assert(Pointee && "Cannot check if null pointer was initialized");
if (isIntegralPointer())
return true;

assert(PointeeStorage.BS.Pointee &&
"Cannot check if null pointer was initialized");
const Descriptor *Desc = getFieldDesc();
assert(Desc);
if (Desc->isPrimitiveArray()) {
if (isStatic() && Base == 0)
if (isStatic() && PointeeStorage.BS.Base == 0)
return true;

InitMapPtr &IM = getInitMap();
Expand All @@ -164,17 +237,24 @@ bool Pointer::isInitialized() const {
}

// Field has its bit in an inline descriptor.
return Base == 0 || getInlineDesc()->IsInitialized;
return PointeeStorage.BS.Base == 0 || getInlineDesc()->IsInitialized;
}

void Pointer::initialize() const {
assert(Pointee && "Cannot initialize null pointer");
if (isIntegralPointer())
return;

assert(PointeeStorage.BS.Pointee && "Cannot initialize null pointer");
const Descriptor *Desc = getFieldDesc();

assert(Desc);
if (Desc->isPrimitiveArray()) {
// Primitive global arrays don't have an initmap.
if (isStatic() && Base == 0)
if (isStatic() && PointeeStorage.BS.Base == 0)
return;

// Nothing to do for these.
if (Desc->getNumElems() == 0)
return;

InitMapPtr &IM = getInitMap();
Expand All @@ -196,13 +276,15 @@ void Pointer::initialize() const {
}

// Field has its bit in an inline descriptor.
assert(Base != 0 && "Only composite fields can be initialised");
assert(PointeeStorage.BS.Base != 0 &&
"Only composite fields can be initialised");
getInlineDesc()->IsInitialized = true;
}

void Pointer::activate() const {
// Field has its bit in an inline descriptor.
assert(Base != 0 && "Only composite fields can be initialised");
assert(PointeeStorage.BS.Base != 0 &&
"Only composite fields can be initialised");
getInlineDesc()->IsActive = true;
}

Expand All @@ -211,11 +293,23 @@ void Pointer::deactivate() const {
}

bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {
return A.Pointee == B.Pointee;
// Two null pointers always have the same base.
if (A.isZero() && B.isZero())
return true;

if (A.isIntegralPointer() && B.isIntegralPointer())
return true;

if (A.isIntegralPointer() || B.isIntegralPointer())
return A.getSource() == B.getSource();

return A.asBlockPointer().Pointee == B.asBlockPointer().Pointee;
}

bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) {
return hasSameBase(A, B) && A.Base == B.Base && A.getFieldDesc()->IsArray;
return hasSameBase(A, B) &&
A.PointeeStorage.BS.Base == B.PointeeStorage.BS.Base &&
A.getFieldDesc()->IsArray;
}

std::optional<APValue> Pointer::toRValue(const Context &Ctx) const {
Expand Down Expand Up @@ -338,6 +432,25 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx) const {
return false;
}

// Vector types.
if (const auto *VT = Ty->getAs<VectorType>()) {
assert(Ptr.getFieldDesc()->isPrimitiveArray());
QualType ElemTy = VT->getElementType();
PrimType ElemT = *Ctx.classify(ElemTy);

SmallVector<APValue> Values;
Values.reserve(VT->getNumElements());
for (unsigned I = 0; I != VT->getNumElements(); ++I) {
TYPE_SWITCH(ElemT, {
Values.push_back(Ptr.atIndex(I).deref<T>().toAPValue());
});
}

assert(Values.size() == VT->getNumElements());
R = APValue(Values.data(), Values.size());
return true;
}

llvm_unreachable("invalid value to return");
};

Expand Down
383 changes: 279 additions & 104 deletions clang/lib/AST/Interp/Pointer.h

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions clang/lib/AST/Interp/PrimType.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ enum PrimType : unsigned {
PT_FnPtr,
};

inline constexpr bool isPtrType(PrimType T) {
return T == PT_Ptr || T == PT_FnPtr;
}

enum class CastKind : uint8_t {
Reinterpret,
Atomic,
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/AST/Interp/Program.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -411,5 +411,12 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty,
IsMutable);
}

// Same with vector types.
if (const auto *VT = Ty->getAs<VectorType>()) {
PrimType ElemTy = *Ctx.classify(VT->getElementType());
return allocateDescriptor(D, ElemTy, MDSize, VT->getNumElements(), IsConst,
IsTemporary, IsMutable);
}

return nullptr;
}
9 changes: 9 additions & 0 deletions clang/lib/AST/Interp/Record.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//

#include "Record.h"
#include "clang/AST/ASTContext.h"

using namespace clang;
using namespace clang::interp;
Expand All @@ -27,6 +28,14 @@ Record::Record(const RecordDecl *Decl, BaseList &&SrcBases,
VirtualBaseMap[V.Decl] = &V;
}

const std::string Record::getName() const {
std::string Ret;
llvm::raw_string_ostream OS(Ret);
Decl->getNameForDiagnostic(OS, Decl->getASTContext().getPrintingPolicy(),
/*Qualified=*/true);
return Ret;
}

const Record::Field *Record::getField(const FieldDecl *FD) const {
auto It = FieldMap.find(FD);
assert(It != FieldMap.end() && "Missing field");
Expand Down
6 changes: 5 additions & 1 deletion clang/lib/AST/Interp/Record.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class Record final {
/// Returns the underlying declaration.
const RecordDecl *getDecl() const { return Decl; }
/// Returns the name of the underlying declaration.
const std::string getName() const { return Decl->getNameAsString(); }
const std::string getName() const;
/// Checks if the record is a union.
bool isUnion() const { return getDecl()->isUnion(); }
/// Returns the size of the record.
Expand Down Expand Up @@ -100,6 +100,10 @@ class Record final {
unsigned getNumVirtualBases() const { return VirtualBases.size(); }
const Base *getVirtualBase(unsigned I) const { return &VirtualBases[I]; }

void dump(llvm::raw_ostream &OS, unsigned Indentation = 0,
unsigned Offset = 0) const;
void dump() const { dump(llvm::errs()); }

private:
/// Constructor used by Program to create record descriptors.
Record(const RecordDecl *, BaseList &&Bases, FieldList &&Fields,
Expand Down
104 changes: 37 additions & 67 deletions clang/lib/AST/NSAPI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,8 @@ Selector NSAPI::getNSStringSelector(NSStringMethodKind MK) const {
&Ctx.Idents.get("initWithUTF8String"));
break;
case NSStr_stringWithCStringEncoding: {
IdentifierInfo *KeyIdents[] = {
&Ctx.Idents.get("stringWithCString"),
&Ctx.Idents.get("encoding")
};
const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("stringWithCString"),
&Ctx.Idents.get("encoding")};
Sel = Ctx.Selectors.getSelector(2, KeyIdents);
break;
}
Expand Down Expand Up @@ -93,10 +91,8 @@ Selector NSAPI::getNSArraySelector(NSArrayMethodKind MK) const {
Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("arrayWithObjects"));
break;
case NSArr_arrayWithObjectsCount: {
IdentifierInfo *KeyIdents[] = {
&Ctx.Idents.get("arrayWithObjects"),
&Ctx.Idents.get("count")
};
const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("arrayWithObjects"),
&Ctx.Idents.get("count")};
Sel = Ctx.Selectors.getSelector(2, KeyIdents);
break;
}
Expand All @@ -110,29 +106,24 @@ Selector NSAPI::getNSArraySelector(NSArrayMethodKind MK) const {
Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("objectAtIndex"));
break;
case NSMutableArr_replaceObjectAtIndex: {
IdentifierInfo *KeyIdents[] = {
&Ctx.Idents.get("replaceObjectAtIndex"),
&Ctx.Idents.get("withObject")
};
const IdentifierInfo *KeyIdents[] = {
&Ctx.Idents.get("replaceObjectAtIndex"),
&Ctx.Idents.get("withObject")};
Sel = Ctx.Selectors.getSelector(2, KeyIdents);
break;
}
case NSMutableArr_addObject:
Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("addObject"));
break;
case NSMutableArr_insertObjectAtIndex: {
IdentifierInfo *KeyIdents[] = {
&Ctx.Idents.get("insertObject"),
&Ctx.Idents.get("atIndex")
};
const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("insertObject"),
&Ctx.Idents.get("atIndex")};
Sel = Ctx.Selectors.getSelector(2, KeyIdents);
break;
}
case NSMutableArr_setObjectAtIndexedSubscript: {
IdentifierInfo *KeyIdents[] = {
&Ctx.Idents.get("setObject"),
&Ctx.Idents.get("atIndexedSubscript")
};
const IdentifierInfo *KeyIdents[] = {
&Ctx.Idents.get("setObject"), &Ctx.Idents.get("atIndexedSubscript")};
Sel = Ctx.Selectors.getSelector(2, KeyIdents);
break;
}
Expand Down Expand Up @@ -167,27 +158,21 @@ Selector NSAPI::getNSDictionarySelector(
&Ctx.Idents.get("dictionaryWithDictionary"));
break;
case NSDict_dictionaryWithObjectForKey: {
IdentifierInfo *KeyIdents[] = {
&Ctx.Idents.get("dictionaryWithObject"),
&Ctx.Idents.get("forKey")
};
const IdentifierInfo *KeyIdents[] = {
&Ctx.Idents.get("dictionaryWithObject"), &Ctx.Idents.get("forKey")};
Sel = Ctx.Selectors.getSelector(2, KeyIdents);
break;
}
case NSDict_dictionaryWithObjectsForKeys: {
IdentifierInfo *KeyIdents[] = {
&Ctx.Idents.get("dictionaryWithObjects"),
&Ctx.Idents.get("forKeys")
};
const IdentifierInfo *KeyIdents[] = {
&Ctx.Idents.get("dictionaryWithObjects"), &Ctx.Idents.get("forKeys")};
Sel = Ctx.Selectors.getSelector(2, KeyIdents);
break;
}
case NSDict_dictionaryWithObjectsForKeysCount: {
IdentifierInfo *KeyIdents[] = {
&Ctx.Idents.get("dictionaryWithObjects"),
&Ctx.Idents.get("forKeys"),
&Ctx.Idents.get("count")
};
const IdentifierInfo *KeyIdents[] = {
&Ctx.Idents.get("dictionaryWithObjects"), &Ctx.Idents.get("forKeys"),
&Ctx.Idents.get("count")};
Sel = Ctx.Selectors.getSelector(3, KeyIdents);
break;
}
Expand All @@ -204,37 +189,29 @@ Selector NSAPI::getNSDictionarySelector(
&Ctx.Idents.get("initWithObjectsAndKeys"));
break;
case NSDict_initWithObjectsForKeys: {
IdentifierInfo *KeyIdents[] = {
&Ctx.Idents.get("initWithObjects"),
&Ctx.Idents.get("forKeys")
};
const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("initWithObjects"),
&Ctx.Idents.get("forKeys")};
Sel = Ctx.Selectors.getSelector(2, KeyIdents);
break;
}
case NSDict_objectForKey:
Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("objectForKey"));
break;
case NSMutableDict_setObjectForKey: {
IdentifierInfo *KeyIdents[] = {
&Ctx.Idents.get("setObject"),
&Ctx.Idents.get("forKey")
};
const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("setObject"),
&Ctx.Idents.get("forKey")};
Sel = Ctx.Selectors.getSelector(2, KeyIdents);
break;
}
case NSMutableDict_setObjectForKeyedSubscript: {
IdentifierInfo *KeyIdents[] = {
&Ctx.Idents.get("setObject"),
&Ctx.Idents.get("forKeyedSubscript")
};
const IdentifierInfo *KeyIdents[] = {
&Ctx.Idents.get("setObject"), &Ctx.Idents.get("forKeyedSubscript")};
Sel = Ctx.Selectors.getSelector(2, KeyIdents);
break;
}
case NSMutableDict_setValueForKey: {
IdentifierInfo *KeyIdents[] = {
&Ctx.Idents.get("setValue"),
&Ctx.Idents.get("forKey")
};
const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("setValue"),
&Ctx.Idents.get("forKey")};
Sel = Ctx.Selectors.getSelector(2, KeyIdents);
break;
}
Expand Down Expand Up @@ -264,34 +241,27 @@ Selector NSAPI::getNSSetSelector(NSSetMethodKind MK) const {
Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("addObject"));
break;
case NSOrderedSet_insertObjectAtIndex: {
IdentifierInfo *KeyIdents[] = {
&Ctx.Idents.get("insertObject"),
&Ctx.Idents.get("atIndex")
};
const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("insertObject"),
&Ctx.Idents.get("atIndex")};
Sel = Ctx.Selectors.getSelector(2, KeyIdents);
break;
}
case NSOrderedSet_setObjectAtIndex: {
IdentifierInfo *KeyIdents[] = {
&Ctx.Idents.get("setObject"),
&Ctx.Idents.get("atIndex")
};
const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("setObject"),
&Ctx.Idents.get("atIndex")};
Sel = Ctx.Selectors.getSelector(2, KeyIdents);
break;
}
case NSOrderedSet_setObjectAtIndexedSubscript: {
IdentifierInfo *KeyIdents[] = {
&Ctx.Idents.get("setObject"),
&Ctx.Idents.get("atIndexedSubscript")
};
const IdentifierInfo *KeyIdents[] = {
&Ctx.Idents.get("setObject"), &Ctx.Idents.get("atIndexedSubscript")};
Sel = Ctx.Selectors.getSelector(2, KeyIdents);
break;
}
case NSOrderedSet_replaceObjectAtIndexWithObject: {
IdentifierInfo *KeyIdents[] = {
&Ctx.Idents.get("replaceObjectAtIndex"),
&Ctx.Idents.get("withObject")
};
const IdentifierInfo *KeyIdents[] = {
&Ctx.Idents.get("replaceObjectAtIndex"),
&Ctx.Idents.get("withObject")};
Sel = Ctx.Selectors.getSelector(2, KeyIdents);
break;
}
Expand Down Expand Up @@ -606,7 +576,7 @@ bool NSAPI::isObjCEnumerator(const Expr *E,
Selector NSAPI::getOrInitSelector(ArrayRef<StringRef> Ids,
Selector &Sel) const {
if (Sel.isNull()) {
SmallVector<IdentifierInfo *, 4> Idents;
SmallVector<const IdentifierInfo *, 4> Idents;
for (ArrayRef<StringRef>::const_iterator
I = Ids.begin(), E = Ids.end(); I != E; ++I)
Idents.push_back(&Ctx.Idents.get(*I));
Expand All @@ -617,7 +587,7 @@ Selector NSAPI::getOrInitSelector(ArrayRef<StringRef> Ids,

Selector NSAPI::getOrInitNullarySelector(StringRef Id, Selector &Sel) const {
if (Sel.isNull()) {
IdentifierInfo *Ident = &Ctx.Idents.get(Id);
const IdentifierInfo *Ident = &Ctx.Idents.get(Id);
Sel = Ctx.Selectors.getSelector(0, &Ident);
}
return Sel;
Expand Down
18 changes: 9 additions & 9 deletions clang/lib/AST/NestedNameSpecifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,16 @@ NestedNameSpecifier::FindOrInsert(const ASTContext &Context,
return NNS;
}

NestedNameSpecifier *
NestedNameSpecifier::Create(const ASTContext &Context,
NestedNameSpecifier *Prefix, IdentifierInfo *II) {
NestedNameSpecifier *NestedNameSpecifier::Create(const ASTContext &Context,
NestedNameSpecifier *Prefix,
const IdentifierInfo *II) {
assert(II && "Identifier cannot be NULL");
assert((!Prefix || Prefix->isDependent()) && "Prefix must be dependent");

NestedNameSpecifier Mockup;
Mockup.Prefix.setPointer(Prefix);
Mockup.Prefix.setInt(StoredIdentifier);
Mockup.Specifier = II;
Mockup.Specifier = const_cast<IdentifierInfo *>(II);
return FindOrInsert(Context, Mockup);
}

Expand All @@ -87,7 +87,7 @@ NestedNameSpecifier::Create(const ASTContext &Context,
NestedNameSpecifier *
NestedNameSpecifier::Create(const ASTContext &Context,
NestedNameSpecifier *Prefix,
NamespaceAliasDecl *Alias) {
const NamespaceAliasDecl *Alias) {
assert(Alias && "Namespace alias cannot be NULL");
assert((!Prefix ||
(Prefix->getAsType() == nullptr &&
Expand All @@ -96,7 +96,7 @@ NestedNameSpecifier::Create(const ASTContext &Context,
NestedNameSpecifier Mockup;
Mockup.Prefix.setPointer(Prefix);
Mockup.Prefix.setInt(StoredDecl);
Mockup.Specifier = Alias;
Mockup.Specifier = const_cast<NamespaceAliasDecl *>(Alias);
return FindOrInsert(Context, Mockup);
}

Expand All @@ -112,13 +112,13 @@ NestedNameSpecifier::Create(const ASTContext &Context,
return FindOrInsert(Context, Mockup);
}

NestedNameSpecifier *
NestedNameSpecifier::Create(const ASTContext &Context, IdentifierInfo *II) {
NestedNameSpecifier *NestedNameSpecifier::Create(const ASTContext &Context,
const IdentifierInfo *II) {
assert(II && "Identifier cannot be NULL");
NestedNameSpecifier Mockup;
Mockup.Prefix.setPointer(nullptr);
Mockup.Prefix.setInt(StoredIdentifier);
Mockup.Specifier = II;
Mockup.Specifier = const_cast<IdentifierInfo *>(II);
return FindOrInsert(Context, Mockup);
}

Expand Down
19 changes: 19 additions & 0 deletions clang/lib/AST/OpenACCClause.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,22 @@
#include "clang/AST/ASTContext.h"

using namespace clang;

OpenACCDefaultClause *OpenACCDefaultClause::Create(const ASTContext &C,
OpenACCDefaultClauseKind K,
SourceLocation BeginLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
void *Mem =
C.Allocate(sizeof(OpenACCDefaultClause), alignof(OpenACCDefaultClause));

return new (Mem) OpenACCDefaultClause(K, BeginLoc, LParenLoc, EndLoc);
}

//===----------------------------------------------------------------------===//
// OpenACC clauses printing methods
//===----------------------------------------------------------------------===//
void OpenACCClausePrinter::VisitOpenACCDefaultClause(
const OpenACCDefaultClause &C) {
OS << "default(" << C.getDefaultClauseKind() << ")";
}
25 changes: 22 additions & 3 deletions clang/lib/AST/ParentMapContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,26 @@ class ParentMapContext::ParentMap {
template <typename, typename...> friend struct ::MatchParents;

/// Contains parents of a node.
using ParentVector = llvm::SmallVector<DynTypedNode, 2>;
class ParentVector {
public:
ParentVector() = default;
explicit ParentVector(size_t N, const DynTypedNode &Value) {
Items.reserve(N);
for (; N > 0; --N)
push_back(Value);
}
bool contains(const DynTypedNode &Value) {
return Seen.contains(Value);
}
void push_back(const DynTypedNode &Value) {
if (!Value.getMemoizationData() || Seen.insert(Value).second)
Items.push_back(Value);
}
llvm::ArrayRef<DynTypedNode> view() const { return Items; }
private:
llvm::SmallVector<DynTypedNode, 2> Items;
llvm::SmallDenseSet<DynTypedNode, 2> Seen;
};

/// Maps from a node to its parents. This is used for nodes that have
/// pointer identity only, which are more common and we can save space by
Expand Down Expand Up @@ -99,7 +118,7 @@ class ParentMapContext::ParentMap {
return llvm::ArrayRef<DynTypedNode>();
}
if (const auto *V = I->second.template dyn_cast<ParentVector *>()) {
return llvm::ArrayRef(*V);
return V->view();
}
return getSingleDynTypedNodeFromParentMap(I->second);
}
Expand Down Expand Up @@ -252,7 +271,7 @@ class ParentMapContext::ParentMap {
const auto *S = It->second.dyn_cast<const Stmt *>();
if (!S) {
if (auto *Vec = It->second.dyn_cast<ParentVector *>())
return llvm::ArrayRef(*Vec);
return Vec->view();
return getSingleDynTypedNodeFromParentMap(It->second);
}
const auto *P = dyn_cast<Expr>(S);
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/AST/SelectorLocationsKind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,15 @@ static SourceLocation getStandardSelLoc(unsigned Index,
assert(Index == 0);
if (EndLoc.isInvalid())
return SourceLocation();
IdentifierInfo *II = Sel.getIdentifierInfoForSlot(0);
const IdentifierInfo *II = Sel.getIdentifierInfoForSlot(0);
unsigned Len = II ? II->getLength() : 0;
return EndLoc.getLocWithOffset(-Len);
}

assert(Index < NumSelArgs);
if (ArgLoc.isInvalid())
return SourceLocation();
IdentifierInfo *II = Sel.getIdentifierInfoForSlot(Index);
const IdentifierInfo *II = Sel.getIdentifierInfoForSlot(Index);
unsigned Len = /* selector id */ (II ? II->getLength() : 0) + /* ':' */ 1;
if (WithArgSpace)
++Len;
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/AST/StmtOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2431,7 +2431,7 @@ OMPTeamsGenericLoopDirective::CreateEmpty(const ASTContext &C,
OMPTargetTeamsGenericLoopDirective *OMPTargetTeamsGenericLoopDirective::Create(
const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt,
const HelperExprs &Exprs) {
const HelperExprs &Exprs, bool CanBeParallelFor) {
auto *Dir = createDirective<OMPTargetTeamsGenericLoopDirective>(
C, Clauses, AssociatedStmt,
numLoopChildren(CollapsedNum, OMPD_target_teams_loop), StartLoc, EndLoc,
Expand Down Expand Up @@ -2473,6 +2473,7 @@ OMPTargetTeamsGenericLoopDirective *OMPTargetTeamsGenericLoopDirective::Create(
Dir->setCombinedNextUpperBound(Exprs.DistCombinedFields.NUB);
Dir->setCombinedDistCond(Exprs.DistCombinedFields.DistCond);
Dir->setCombinedParForInDistCond(Exprs.DistCombinedFields.ParForInDistCond);
Dir->setCanBeParallelFor(CanBeParallelFor);
return Dir;
}

Expand Down
9 changes: 6 additions & 3 deletions clang/lib/AST/StmtPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -292,8 +292,11 @@ void StmtPrinter::VisitLabelStmt(LabelStmt *Node) {
}

void StmtPrinter::VisitAttributedStmt(AttributedStmt *Node) {
for (const auto *Attr : Node->getAttrs()) {
llvm::ArrayRef<const Attr *> Attrs = Node->getAttrs();
for (const auto *Attr : Attrs) {
Attr->printPretty(OS, Policy);
if (Attr != Attrs.back())
OS << ' ';
}

PrintStmt(Node->getSubStmt(), 0);
Expand Down Expand Up @@ -1444,7 +1447,7 @@ void StmtPrinter::VisitOffsetOfExpr(OffsetOfExpr *Node) {
continue;

// Field or identifier node.
IdentifierInfo *Id = ON.getFieldName();
const IdentifierInfo *Id = ON.getFieldName();
if (!Id)
continue;

Expand Down Expand Up @@ -2345,7 +2348,7 @@ void StmtPrinter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) {
E->getQualifier()->print(OS, Policy);
OS << "~";

if (IdentifierInfo *II = E->getDestroyedTypeIdentifier())
if (const IdentifierInfo *II = E->getDestroyedTypeIdentifier())
OS << II->getName();
else
E->getDestroyedType().print(OS, Policy);
Expand Down
12 changes: 9 additions & 3 deletions clang/lib/AST/StmtProfile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ namespace {
virtual void VisitName(DeclarationName Name, bool TreatAsDecl = false) = 0;

/// Visit identifiers that are not in Decl's or Type's.
virtual void VisitIdentifierInfo(IdentifierInfo *II) = 0;
virtual void VisitIdentifierInfo(const IdentifierInfo *II) = 0;

/// Visit a nested-name-specifier that occurs within an expression
/// or statement.
Expand Down Expand Up @@ -163,7 +163,7 @@ namespace {
ID.AddPointer(Name.getAsOpaquePtr());
}

void VisitIdentifierInfo(IdentifierInfo *II) override {
void VisitIdentifierInfo(const IdentifierInfo *II) override {
ID.AddPointer(II);
}

Expand Down Expand Up @@ -211,7 +211,7 @@ namespace {
}
Hash.AddDeclarationName(Name, TreatAsDecl);
}
void VisitIdentifierInfo(IdentifierInfo *II) override {
void VisitIdentifierInfo(const IdentifierInfo *II) override {
ID.AddBoolean(II);
if (II) {
Hash.AddIdentifierInfo(II);
Expand Down Expand Up @@ -2011,6 +2011,7 @@ void StmtProfiler::VisitMSPropertySubscriptExpr(
void StmtProfiler::VisitCXXThisExpr(const CXXThisExpr *S) {
VisitExpr(S);
ID.AddBoolean(S->isImplicit());
ID.AddBoolean(S->isCapturedByCopyInLambdaWithExplicitObjectParameter());
}

void StmtProfiler::VisitCXXThrowExpr(const CXXThrowExpr *S) {
Expand Down Expand Up @@ -2455,7 +2456,12 @@ class OpenACCClauseProfiler
Visit(Clause);
}
}
void VisitOpenACCDefaultClause(const OpenACCDefaultClause &Clause);
};

/// Nothing to do here, there are no sub-statements.
void OpenACCClauseProfiler::VisitOpenACCDefaultClause(
const OpenACCDefaultClause &Clause) {}
} // namespace

void StmtProfiler::VisitOpenACCComputeConstruct(
Expand Down
10 changes: 9 additions & 1 deletion clang/lib/AST/TextNodeDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,9 @@ void TextNodeDumper::Visit(const OpenACCClause *C) {
// Handle clauses with parens for types that have no children, likely
// because there is no sub expression.
switch (C->getClauseKind()) {
case OpenACCClauseKind::Default:
OS << '(' << cast<OpenACCDefaultClause>(C)->getDefaultClauseKind() << ')';
break;
default:
// Nothing to do here.
break;
Expand Down Expand Up @@ -1202,8 +1205,11 @@ void TextNodeDumper::VisitDeclRefExpr(const DeclRefExpr *Node) {
case NOUR_Constant: OS << " non_odr_use_constant"; break;
case NOUR_Discarded: OS << " non_odr_use_discarded"; break;
}
if (Node->refersToEnclosingVariableOrCapture())
if (Node->isCapturedByCopyInLambdaWithExplicitObjectParameter())
OS << " dependent_capture";
else if (Node->refersToEnclosingVariableOrCapture())
OS << " refers_to_enclosing_variable_or_capture";

if (Node->isImmediateEscalating())
OS << " immediate-escalating";
}
Expand Down Expand Up @@ -1359,6 +1365,8 @@ void TextNodeDumper::VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *Node) {
void TextNodeDumper::VisitCXXThisExpr(const CXXThisExpr *Node) {
if (Node->isImplicit())
OS << " implicit";
if (Node->isCapturedByCopyInLambdaWithExplicitObjectParameter())
OS << " dependent_capture";
OS << " this";
}

Expand Down
9 changes: 6 additions & 3 deletions clang/lib/AST/TypePrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1213,10 +1213,13 @@ void TypePrinter::printDecltypeBefore(const DecltypeType *T, raw_ostream &OS) {

void TypePrinter::printPackIndexingBefore(const PackIndexingType *T,
raw_ostream &OS) {
if (T->hasSelectedType())
if (T->hasSelectedType()) {
OS << T->getSelectedType();
else
OS << T->getPattern() << "...[" << T->getIndexExpr() << "]";
} else {
OS << T->getPattern() << "...[";
T->getIndexExpr()->printPretty(OS, nullptr, Policy);
OS << "]";
}
spaceBeforePlaceHolder(OS);
}

Expand Down
427 changes: 307 additions & 120 deletions clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp

Large diffs are not rendered by default.

176 changes: 78 additions & 98 deletions clang/lib/Analysis/FlowSensitive/Transfer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -460,25 +460,41 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
// So make sure we have a value if we didn't propagate one above.
if (S->isPRValue() && S->getType()->isRecordType()) {
if (Env.getValue(*S) == nullptr) {
Value *Val = Env.createValue(S->getType());
// We're guaranteed to always be able to create a value for record
// types.
assert(Val != nullptr);
Env.setValue(*S, *Val);
auto &Loc = Env.getResultObjectLocation(*S);
Env.initializeFieldsWithValues(Loc);
refreshRecordValue(Loc, Env);
}
}
}

void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *S) {
const Expr *InitExpr = S->getExpr();
assert(InitExpr != nullptr);

// If this is a prvalue of record type, the handler for `*InitExpr` (if one
// exists) will initialize the result object; there is no value to propgate
// here.
if (S->getType()->isRecordType() && S->isPRValue())
return;

propagateValueOrStorageLocation(*InitExpr, *S, Env);
}

void VisitCXXConstructExpr(const CXXConstructExpr *S) {
const CXXConstructorDecl *ConstructorDecl = S->getConstructor();
assert(ConstructorDecl != nullptr);

// `CXXConstructExpr` can have array type if default-initializing an array
// of records. We don't handle this specifically beyond potentially inlining
// the call.
if (!S->getType()->isRecordType()) {
transferInlineCall(S, ConstructorDecl);
return;
}

RecordStorageLocation &Loc = Env.getResultObjectLocation(*S);
Env.setValue(*S, refreshRecordValue(Loc, Env));

if (ConstructorDecl->isCopyOrMoveConstructor()) {
// It is permissible for a copy/move constructor to have additional
// parameters as long as they have default arguments defined for them.
Expand All @@ -491,24 +507,14 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
if (ArgLoc == nullptr)
return;

if (S->isElidable()) {
if (Value *Val = Env.getValue(*ArgLoc))
Env.setValue(*S, *Val);
} else {
auto &Val = *cast<RecordValue>(Env.createValue(S->getType()));
Env.setValue(*S, Val);
copyRecord(*ArgLoc, Val.getLoc(), Env);
}
// Even if the copy/move constructor call is elidable, we choose to copy
// the record in all cases (which isn't wrong, just potentially not
// optimal).
copyRecord(*ArgLoc, Loc, Env);
return;
}

// `CXXConstructExpr` can have array type if default-initializing an array
// of records, and we currently can't create values for arrays. So check if
// we've got a record type.
if (S->getType()->isRecordType()) {
auto &InitialVal = *cast<RecordValue>(Env.createValue(S->getType()));
Env.setValue(*S, InitialVal);
}
Env.initializeFieldsWithValues(Loc, S->getType());

transferInlineCall(S, ConstructorDecl);
}
Expand Down Expand Up @@ -551,19 +557,15 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
if (S->isGLValue()) {
Env.setStorageLocation(*S, *LocDst);
} else if (S->getType()->isRecordType()) {
// Make sure that we have a `RecordValue` for this expression so that
// `Environment::getResultObjectLocation()` is able to return a location
// for it.
if (Env.getValue(*S) == nullptr)
refreshRecordValue(*S, Env);
// Assume that the assignment returns the assigned value.
copyRecord(*LocDst, Env.getResultObjectLocation(*S), Env);
}

return;
}

// CXXOperatorCallExpr can be prvalues. Call `VisitCallExpr`() to create
// a `RecordValue` for them so that `Environment::getResultObjectLocation()`
// can return a value.
// `CXXOperatorCallExpr` can be a prvalue. Call `VisitCallExpr`() to
// initialize the prvalue's fields with values.
VisitCallExpr(S);
}

Expand All @@ -580,11 +582,6 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
}
}

void VisitCXXTemporaryObjectExpr(const CXXTemporaryObjectExpr *S) {
if (Value *Val = Env.createValue(S->getType()))
Env.setValue(*S, *Val);
}

void VisitCallExpr(const CallExpr *S) {
// Of clang's builtins, only `__builtin_expect` is handled explicitly, since
// others (like trap, debugtrap, and unreachable) are handled by CFG
Expand Down Expand Up @@ -612,13 +609,14 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
} else if (const FunctionDecl *F = S->getDirectCallee()) {
transferInlineCall(S, F);

// If this call produces a prvalue of record type, make sure that we have
// a `RecordValue` for it. This is required so that
// `Environment::getResultObjectLocation()` is able to return a location
// for this `CallExpr`.
// If this call produces a prvalue of record type, initialize its fields
// with values.
if (S->getType()->isRecordType() && S->isPRValue())
if (Env.getValue(*S) == nullptr)
refreshRecordValue(*S, Env);
if (Env.getValue(*S) == nullptr) {
RecordStorageLocation &Loc = Env.getResultObjectLocation(*S);
Env.initializeFieldsWithValues(Loc);
Env.setValue(*S, refreshRecordValue(Loc, Env));
}
}
}

Expand Down Expand Up @@ -666,8 +664,10 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
// `getLogicOperatorSubExprValue()`.
if (S->isGLValue())
Env.setStorageLocation(*S, Env.createObject(S->getType()));
else if (Value *Val = Env.createValue(S->getType()))
Env.setValue(*S, *Val);
else if (!S->getType()->isRecordType()) {
if (Value *Val = Env.createValue(S->getType()))
Env.setValue(*S, *Val);
}
}

void VisitInitListExpr(const InitListExpr *S) {
Expand All @@ -688,71 +688,51 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
return;
}

llvm::DenseMap<const ValueDecl *, StorageLocation *> FieldLocs;
RecordInitListHelper InitListHelper(S);
RecordStorageLocation &Loc = Env.getResultObjectLocation(*S);
Env.setValue(*S, refreshRecordValue(Loc, Env));

for (auto [Base, Init] : InitListHelper.base_inits()) {
assert(Base->getType().getCanonicalType() ==
Init->getType().getCanonicalType());
auto *BaseVal = Env.get<RecordValue>(*Init);
if (!BaseVal)
BaseVal = cast<RecordValue>(Env.createValue(Init->getType()));
// Take ownership of the fields of the `RecordValue` for the base class
// and incorporate them into the "flattened" set of fields for the
// derived class.
auto Children = BaseVal->getLoc().children();
FieldLocs.insert(Children.begin(), Children.end());
}
// Initialization of base classes and fields of record type happens when we
// visit the nested `CXXConstructExpr` or `InitListExpr` for that base class
// or field. We therefore only need to deal with fields of non-record type
// here.

for (auto [Field, Init] : InitListHelper.field_inits()) {
assert(
// The types are same, or
Field->getType().getCanonicalType().getUnqualifiedType() ==
Init->getType().getCanonicalType().getUnqualifiedType() ||
// The field's type is T&, and initializer is T
(Field->getType()->isReferenceType() &&
Field->getType().getCanonicalType()->getPointeeType() ==
Init->getType().getCanonicalType()));
auto& Loc = Env.createObject(Field->getType(), Init);
FieldLocs.insert({Field, &Loc});
}
RecordInitListHelper InitListHelper(S);

// In the case of a union, we don't in general have initializers for all
// of the fields. Create storage locations for the remaining fields (but
// don't associate them with values).
if (Type->isUnionType()) {
for (const FieldDecl *Field :
Env.getDataflowAnalysisContext().getModeledFields(Type)) {
if (auto [it, inserted] = FieldLocs.insert({Field, nullptr}); inserted)
it->second = &Env.createStorageLocation(Field->getType());
for (auto [Field, Init] : InitListHelper.field_inits()) {
if (Field->getType()->isRecordType())
continue;
if (Field->getType()->isReferenceType()) {
assert(Field->getType().getCanonicalType()->getPointeeType() ==
Init->getType().getCanonicalType());
Loc.setChild(*Field, &Env.createObject(Field->getType(), Init));
continue;
}
assert(Field->getType().getCanonicalType().getUnqualifiedType() ==
Init->getType().getCanonicalType().getUnqualifiedType());
StorageLocation *FieldLoc = Loc.getChild(*Field);
// Locations for non-reference fields must always be non-null.
assert(FieldLoc != nullptr);
Value *Val = Env.getValue(*Init);
if (Val == nullptr && isa<ImplicitValueInitExpr>(Init) &&
Init->getType()->isPointerType())
Val =
&Env.getOrCreateNullPointerValue(Init->getType()->getPointeeType());
if (Val == nullptr)
Val = Env.createValue(Field->getType());
if (Val != nullptr)
Env.setValue(*FieldLoc, *Val);
}

// Check that we satisfy the invariant that a `RecordStorageLoation`
// contains exactly the set of modeled fields for that type.
// `ModeledFields` includes fields from all the bases, but only the
// modeled ones. However, if a class type is initialized with an
// `InitListExpr`, all fields in the class, including those from base
// classes, are included in the set of modeled fields. The code above
// should therefore populate exactly the modeled fields.
assert(containsSameFields(
Env.getDataflowAnalysisContext().getModeledFields(Type), FieldLocs));

RecordStorageLocation::SyntheticFieldMap SyntheticFieldLocs;
for (const auto &Entry :
Env.getDataflowAnalysisContext().getSyntheticFields(Type)) {
SyntheticFieldLocs.insert(
{Entry.getKey(), &Env.createObject(Entry.getValue())});
for (const auto &[FieldName, FieldLoc] : Loc.synthetic_fields()) {
QualType FieldType = FieldLoc->getType();
if (FieldType->isRecordType()) {
Env.initializeFieldsWithValues(*cast<RecordStorageLocation>(FieldLoc));
} else {
if (Value *Val = Env.createValue(FieldType))
Env.setValue(*FieldLoc, *Val);
}
}

auto &Loc = Env.getDataflowAnalysisContext().createRecordStorageLocation(
Type, std::move(FieldLocs), std::move(SyntheticFieldLocs));
RecordValue &RecordVal = Env.create<RecordValue>(Loc);

Env.setValue(Loc, RecordVal);

Env.setValue(*S, RecordVal);

// FIXME: Implement array initialization.
}

Expand Down
13 changes: 3 additions & 10 deletions clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -369,17 +369,10 @@ builtinTransferInitializer(const CFGInitializer &Elt,
ParentLoc->setChild(*Member, InitExprLoc);
} else if (auto *InitExprVal = Env.getValue(*InitExpr)) {
assert(MemberLoc != nullptr);
if (Member->getType()->isRecordType()) {
auto *InitValStruct = cast<RecordValue>(InitExprVal);
// FIXME: Rather than performing a copy here, we should really be
// initializing the field in place. This would require us to propagate the
// storage location of the field to the AST node that creates the
// `RecordValue`.
copyRecord(InitValStruct->getLoc(),
*cast<RecordStorageLocation>(MemberLoc), Env);
} else {
// Record-type initializers construct themselves directly into the result
// object, so there is no need to handle them here.
if (!Member->getType()->isRecordType())
Env.setValue(*MemberLoc, *InitExprVal);
}
}
}

Expand Down
5 changes: 3 additions & 2 deletions clang/lib/Analysis/ObjCNoReturn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@

using namespace clang;

static bool isSubclass(const ObjCInterfaceDecl *Class, IdentifierInfo *II) {
static bool isSubclass(const ObjCInterfaceDecl *Class,
const IdentifierInfo *II) {
if (!Class)
return false;
if (Class->getIdentifier() == II)
Expand All @@ -30,7 +31,7 @@ ObjCNoReturn::ObjCNoReturn(ASTContext &C)
NSExceptionII(&C.Idents.get("NSException"))
{
// Generate selectors.
SmallVector<IdentifierInfo*, 3> II;
SmallVector<const IdentifierInfo *, 3> II;

// raise:format:
II.push_back(&C.Idents.get("raise"));
Expand Down
16 changes: 9 additions & 7 deletions clang/lib/Basic/IdentifierTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,8 @@ unsigned Selector::getNumArgs() const {
return SI->getNumArgs();
}

IdentifierInfo *Selector::getIdentifierInfoForSlot(unsigned argIndex) const {
const IdentifierInfo *
Selector::getIdentifierInfoForSlot(unsigned argIndex) const {
if (getIdentifierInfoFlag() < MultiArg) {
assert(argIndex == 0 && "illegal keyword index");
return getAsIdentifierInfo();
Expand All @@ -553,7 +554,7 @@ IdentifierInfo *Selector::getIdentifierInfoForSlot(unsigned argIndex) const {
}

StringRef Selector::getNameForSlot(unsigned int argIndex) const {
IdentifierInfo *II = getIdentifierInfoForSlot(argIndex);
const IdentifierInfo *II = getIdentifierInfoForSlot(argIndex);
return II ? II->getName() : StringRef();
}

Expand All @@ -574,7 +575,7 @@ std::string Selector::getAsString() const {
return "<null selector>";

if (getIdentifierInfoFlag() < MultiArg) {
IdentifierInfo *II = getAsIdentifierInfo();
const IdentifierInfo *II = getAsIdentifierInfo();

if (getNumArgs() == 0) {
assert(II && "If the number of arguments is 0 then II is guaranteed to "
Expand Down Expand Up @@ -608,7 +609,7 @@ static bool startsWithWord(StringRef name, StringRef word) {
}

ObjCMethodFamily Selector::getMethodFamilyImpl(Selector sel) {
IdentifierInfo *first = sel.getIdentifierInfoForSlot(0);
const IdentifierInfo *first = sel.getIdentifierInfoForSlot(0);
if (!first) return OMF_None;

StringRef name = first->getName();
Expand Down Expand Up @@ -655,7 +656,7 @@ ObjCMethodFamily Selector::getMethodFamilyImpl(Selector sel) {
}

ObjCInstanceTypeFamily Selector::getInstTypeMethodFamily(Selector sel) {
IdentifierInfo *first = sel.getIdentifierInfoForSlot(0);
const IdentifierInfo *first = sel.getIdentifierInfoForSlot(0);
if (!first) return OIT_None;

StringRef name = first->getName();
Expand Down Expand Up @@ -683,7 +684,7 @@ ObjCInstanceTypeFamily Selector::getInstTypeMethodFamily(Selector sel) {
}

ObjCStringFormatFamily Selector::getStringFormatFamilyImpl(Selector sel) {
IdentifierInfo *first = sel.getIdentifierInfoForSlot(0);
const IdentifierInfo *first = sel.getIdentifierInfoForSlot(0);
if (!first) return SFF_None;

StringRef name = first->getName();
Expand Down Expand Up @@ -750,7 +751,8 @@ size_t SelectorTable::getTotalMemory() const {
return SelTabImpl.Allocator.getTotalMemory();
}

Selector SelectorTable::getSelector(unsigned nKeys, IdentifierInfo **IIV) {
Selector SelectorTable::getSelector(unsigned nKeys,
const IdentifierInfo **IIV) {
if (nKeys < 2)
return Selector(IIV[0], nKeys);

Expand Down
5 changes: 4 additions & 1 deletion clang/lib/Basic/Targets/AArch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1543,10 +1543,13 @@ WindowsARM64TargetInfo::getBuiltinVaListKind() const {
TargetInfo::CallingConvCheckResult
WindowsARM64TargetInfo::checkCallingConvention(CallingConv CC) const {
switch (CC) {
case CC_X86VectorCall:
if (getTriple().isWindowsArm64EC())
return CCCR_OK;
return CCCR_Ignore;
case CC_X86StdCall:
case CC_X86ThisCall:
case CC_X86FastCall:
case CC_X86VectorCall:
return CCCR_Ignore;
case CC_C:
case CC_OpenCLKernel:
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/CodeGen/CGBlocks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1447,7 +1447,7 @@ llvm::Function *CodeGenFunction::GenerateBlockFunction(
selfTy = getContext().getPointerType(getContext().getAddrSpaceQualType(
getContext().VoidTy, LangAS::opencl_generic));

IdentifierInfo *II = &CGM.getContext().Idents.get(".block_descriptor");
const IdentifierInfo *II = &CGM.getContext().Idents.get(".block_descriptor");

ImplicitParamDecl SelfDecl(getContext(), const_cast<BlockDecl *>(blockDecl),
SourceLocation(), II, selfTy,
Expand Down Expand Up @@ -2791,7 +2791,7 @@ static void configureBlocksRuntimeObject(CodeGenModule &CGM,
auto *GV = cast<llvm::GlobalValue>(C->stripPointerCasts());

if (CGM.getTarget().getTriple().isOSBinFormatCOFF()) {
IdentifierInfo &II = CGM.getContext().Idents.get(C->getName());
const IdentifierInfo &II = CGM.getContext().Idents.get(C->getName());
TranslationUnitDecl *TUDecl = CGM.getContext().getTranslationUnitDecl();
DeclContext *DC = TranslationUnitDecl::castToDeclContext(TUDecl);

Expand Down
10 changes: 10 additions & 0 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17288,6 +17288,16 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
Value *Op1 = EmitScalarExpr(E->getArg(1));
Value *Op2 = EmitScalarExpr(E->getArg(2));
Value *Op3 = EmitScalarExpr(E->getArg(3));
// rldimi is 64-bit instruction, expand the intrinsic before isel to
// leverage peephole and avoid legalization efforts.
if (BuiltinID == PPC::BI__builtin_ppc_rldimi &&
!getTarget().getTriple().isPPC64()) {
Function *F = CGM.getIntrinsic(Intrinsic::fshl, Op0->getType());
Op2 = Builder.CreateZExt(Op2, Int64Ty);
Value *Shift = Builder.CreateCall(F, {Op0, Op0, Op2});
return Builder.CreateOr(Builder.CreateAnd(Shift, Op3),
Builder.CreateAnd(Op1, Builder.CreateNot(Op3)));
}
return Builder.CreateCall(
CGM.getIntrinsic(BuiltinID == PPC::BI__builtin_ppc_rldimi
? Intrinsic::ppc_rldimi
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/CodeGen/CGCUDANV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ void CGNVCUDARuntime::emitDeviceStubBodyNew(CodeGenFunction &CGF,
KernelLaunchAPI = KernelLaunchAPI + "_ptsz";
}
auto LaunchKernelName = addPrefixToName(KernelLaunchAPI);
IdentifierInfo &cudaLaunchKernelII =
const IdentifierInfo &cudaLaunchKernelII =
CGM.getContext().Idents.get(LaunchKernelName);
FunctionDecl *cudaLaunchKernelFD = nullptr;
for (auto *Result : DC->lookup(&cudaLaunchKernelII)) {
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5591,6 +5591,12 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
/*AttrOnCallSite=*/true,
/*IsThunk=*/false);

if (CallingConv == llvm::CallingConv::X86_VectorCall &&
getTarget().getTriple().isWindowsArm64EC()) {
CGM.Error(Loc, "__vectorcall calling convention is not currently "
"supported");
}

if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CurFuncDecl)) {
if (FD->hasAttr<StrictFPAttr>())
// All calls within a strictfp function are marked strictfp
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/CodeGen/CGClass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1404,7 +1404,7 @@ FieldHasTrivialDestructorBody(ASTContext &Context,

// The destructor for an implicit anonymous union member is never invoked.
if (FieldClassDecl->isUnion() && FieldClassDecl->isAnonymousStructOrUnion())
return false;
return true;

return HasTrivialDestructorBody(Context, FieldClassDecl, FieldClassDecl);
}
Expand Down
12 changes: 10 additions & 2 deletions clang/lib/CodeGen/CGCleanup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -667,7 +667,8 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {

// - whether there's a fallthrough
llvm::BasicBlock *FallthroughSource = Builder.GetInsertBlock();
bool HasFallthrough = (FallthroughSource != nullptr && IsActive);
bool HasFallthrough =
FallthroughSource != nullptr && (IsActive || HasExistingBranches);

// Branch-through fall-throughs leave the insertion point set to the
// end of the last cleanup, which points to the current scope. The
Expand All @@ -692,7 +693,11 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {

// If we have a prebranched fallthrough into an inactive normal
// cleanup, rewrite it so that it leads to the appropriate place.
if (Scope.isNormalCleanup() && HasPrebranchedFallthrough && !IsActive) {
if (Scope.isNormalCleanup() && HasPrebranchedFallthrough &&
!RequiresNormalCleanup) {
// FIXME: Come up with a program which would need forwarding prebranched
// fallthrough and add tests. Otherwise delete this and assert against it.
assert(!IsActive);
llvm::BasicBlock *prebranchDest;

// If the prebranch is semantically branching through the next
Expand Down Expand Up @@ -765,6 +770,7 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
EmitSehCppScopeEnd();
}
destroyOptimisticNormalEntry(*this, Scope);
Scope.MarkEmitted();
EHStack.popCleanup();
} else {
// If we have a fallthrough and no other need for the cleanup,
Expand All @@ -781,6 +787,7 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
}

destroyOptimisticNormalEntry(*this, Scope);
Scope.MarkEmitted();
EHStack.popCleanup();

EmitCleanup(*this, Fn, cleanupFlags, NormalActiveFlag);
Expand Down Expand Up @@ -916,6 +923,7 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
}

// IV. Pop the cleanup and emit it.
Scope.MarkEmitted();
EHStack.popCleanup();
assert(EHStack.hasNormalCleanups() == HasEnclosingCleanups);

Expand Down
57 changes: 56 additions & 1 deletion clang/lib/CodeGen/CGCleanup.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@
#include "EHScopeStack.h"

#include "Address.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/IR/Instruction.h"

namespace llvm {
class BasicBlock;
Expand Down Expand Up @@ -266,6 +269,51 @@ class alignas(8) EHCleanupScope : public EHScope {
};
mutable struct ExtInfo *ExtInfo;

/// Erases auxillary allocas and their usages for an unused cleanup.
/// Cleanups should mark these allocas as 'used' if the cleanup is
/// emitted, otherwise these instructions would be erased.
struct AuxillaryAllocas {
SmallVector<llvm::Instruction *, 1> AuxAllocas;
bool used = false;

// Records a potentially unused instruction to be erased later.
void Add(llvm::AllocaInst *Alloca) { AuxAllocas.push_back(Alloca); }

// Mark all recorded instructions as used. These will not be erased later.
void MarkUsed() {
used = true;
AuxAllocas.clear();
}

~AuxillaryAllocas() {
if (used)
return;
llvm::SetVector<llvm::Instruction *> Uses;
for (auto *Inst : llvm::reverse(AuxAllocas))
CollectUses(Inst, Uses);
// Delete uses in the reverse order of insertion.
for (auto *I : llvm::reverse(Uses))
I->eraseFromParent();
}

private:
void CollectUses(llvm::Instruction *I,
llvm::SetVector<llvm::Instruction *> &Uses) {
if (!I || !Uses.insert(I))
return;
for (auto *User : I->users())
CollectUses(cast<llvm::Instruction>(User), Uses);
}
};
mutable struct AuxillaryAllocas *AuxAllocas;

AuxillaryAllocas &getAuxillaryAllocas() {
if (!AuxAllocas) {
AuxAllocas = new struct AuxillaryAllocas();
}
return *AuxAllocas;
}

/// The number of fixups required by enclosing scopes (not including
/// this one). If this is the top cleanup scope, all the fixups
/// from this index onwards belong to this scope.
Expand Down Expand Up @@ -298,7 +346,7 @@ class alignas(8) EHCleanupScope : public EHScope {
EHScopeStack::stable_iterator enclosingEH)
: EHScope(EHScope::Cleanup, enclosingEH),
EnclosingNormal(enclosingNormal), NormalBlock(nullptr),
ActiveFlag(Address::invalid()), ExtInfo(nullptr),
ActiveFlag(Address::invalid()), ExtInfo(nullptr), AuxAllocas(nullptr),
FixupDepth(fixupDepth) {
CleanupBits.IsNormalCleanup = isNormal;
CleanupBits.IsEHCleanup = isEH;
Expand All @@ -312,8 +360,15 @@ class alignas(8) EHCleanupScope : public EHScope {
}

void Destroy() {
if (AuxAllocas)
delete AuxAllocas;
delete ExtInfo;
}
void AddAuxAllocas(llvm::SmallVector<llvm::AllocaInst *> Allocas) {
for (auto *Alloca : Allocas)
getAuxillaryAllocas().Add(Alloca);
}
void MarkEmitted() { getAuxillaryAllocas().MarkUsed(); }
// Objects of EHCleanupScope are not destructed. Use Destroy().
~EHCleanupScope() = delete;

Expand Down
Loading