184 changes: 68 additions & 116 deletions clang/include/clang/Sema/Sema.h

Large diffs are not rendered by default.

37 changes: 37 additions & 0 deletions clang/include/clang/Sema/SemaHLSL.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//===----- SemaHLSL.h ----- Semantic Analysis for HLSL constructs ---------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
/// This file declares semantic analysis for HLSL constructs.
///
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_SEMA_SEMAHLSL_H
#define LLVM_CLANG_SEMA_SEMAHLSL_H

#include "clang/AST/DeclBase.h"
#include "clang/AST/Expr.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/SemaBase.h"

namespace clang {

class SemaHLSL : public SemaBase {
public:
SemaHLSL(Sema &S);

Decl *ActOnStartHLSLBuffer(Scope *BufferScope, bool CBuffer,
SourceLocation KwLoc, IdentifierInfo *Ident,
SourceLocation IdentLoc, SourceLocation LBrace);
void ActOnFinishHLSLBuffer(Decl *Dcl, SourceLocation RBrace);
};

} // namespace clang

#endif // LLVM_CLANG_SEMA_SEMAHLSL_H
57 changes: 55 additions & 2 deletions clang/include/clang/Sema/SemaOpenACC.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,65 @@
#include "clang/Basic/SourceLocation.h"
#include "clang/Sema/Ownership.h"
#include "clang/Sema/SemaBase.h"
#include <variant>

namespace clang {
class OpenACCClause;

class SemaOpenACC : public SemaBase {
public:
/// A type to represent all the data for an OpenACC Clause that has been
/// parsed, but not yet created/semantically analyzed. This is effectively a
/// discriminated union on the 'Clause Kind', with all of the individual
/// clause details stored in a std::variant.
class OpenACCParsedClause {
OpenACCDirectiveKind DirKind;
OpenACCClauseKind ClauseKind;
SourceRange ClauseRange;
SourceLocation LParenLoc;

struct DefaultDetails {
OpenACCDefaultClauseKind DefaultClauseKind;
};

std::variant<DefaultDetails> Details;

public:
OpenACCParsedClause(OpenACCDirectiveKind DirKind,
OpenACCClauseKind ClauseKind, SourceLocation BeginLoc)
: DirKind(DirKind), ClauseKind(ClauseKind), ClauseRange(BeginLoc, {}) {}

OpenACCDirectiveKind getDirectiveKind() const { return DirKind; }

OpenACCClauseKind getClauseKind() const { return ClauseKind; }

SourceLocation getBeginLoc() const { return ClauseRange.getBegin(); }

SourceLocation getLParenLoc() const { return LParenLoc; }

SourceLocation getEndLoc() const { return ClauseRange.getEnd(); }

OpenACCDefaultClauseKind getDefaultClauseKind() const {
assert(ClauseKind == OpenACCClauseKind::Default &&
"Parsed clause is not a default clause");
return std::get<DefaultDetails>(Details).DefaultClauseKind;
}

void setLParenLoc(SourceLocation EndLoc) { LParenLoc = EndLoc; }
void setEndLoc(SourceLocation EndLoc) { ClauseRange.setEnd(EndLoc); }

void setDefaultDetails(OpenACCDefaultClauseKind DefKind) {
assert(ClauseKind == OpenACCClauseKind::Default &&
"Parsed clause is not a default clause");
Details = DefaultDetails{DefKind};
}
};

SemaOpenACC(Sema &S);

/// Called after parsing an OpenACC Clause so that it can be checked.
bool ActOnClause(OpenACCClauseKind ClauseKind, SourceLocation StartLoc);
OpenACCClause *ActOnClause(ArrayRef<const OpenACCClause *> ExistingClauses,
OpenACCParsedClause &Clause);

/// Called after the construct has been parsed, but clauses haven't been
/// parsed. This allows us to diagnose not-implemented, as well as set up any
Expand All @@ -53,7 +103,10 @@ class SemaOpenACC : public SemaBase {
/// declaration group or associated statement.
StmtResult ActOnEndStmtDirective(OpenACCDirectiveKind K,
SourceLocation StartLoc,
SourceLocation EndLoc, StmtResult AssocStmt);
SourceLocation EndLoc,
ArrayRef<OpenACCClause *> Clauses,
StmtResult AssocStmt);

/// Called after the directive has been completely parsed, including the
/// declaration group or associated statement.
DeclGroupRef ActOnEndDeclDirective();
Expand Down
65 changes: 65 additions & 0 deletions clang/include/clang/Sema/SemaSYCL.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
//===----- SemaSYCL.h ------- Semantic Analysis for SYCL constructs -------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
/// This file declares semantic analysis for SYCL constructs.
///
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_SEMA_SEMASYCL_H
#define LLVM_CLANG_SEMA_SEMASYCL_H

#include "clang/AST/Decl.h"
#include "clang/AST/Type.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Sema/Ownership.h"
#include "clang/Sema/SemaBase.h"
#include "llvm/ADT/DenseSet.h"

namespace clang {

class SemaSYCL : public SemaBase {
public:
SemaSYCL(Sema &S);

/// Creates a SemaDiagnosticBuilder that emits the diagnostic if the current
/// context is "used as device code".
///
/// - If CurLexicalContext is a kernel function or it is known that the
/// function will be emitted for the device, emits the diagnostics
/// immediately.
/// - If CurLexicalContext is a function and we are compiling
/// for the device, but we don't know yet that this function will be
/// codegen'ed for the devive, creates a diagnostic which is emitted if and
/// when we realize that the function will be codegen'ed.
///
/// Example usage:
///
/// Diagnose __float128 type usage only from SYCL device code if the current
/// target doesn't support it
/// if (!S.Context.getTargetInfo().hasFloat128Type() &&
/// S.getLangOpts().SYCLIsDevice)
/// DiagIfDeviceCode(Loc, diag::err_type_unsupported) << "__float128";
SemaDiagnosticBuilder DiagIfDeviceCode(SourceLocation Loc, unsigned DiagID);

void deepTypeCheckForDevice(SourceLocation UsedAt,
llvm::DenseSet<QualType> Visited,
ValueDecl *DeclToCheck);

ExprResult BuildUniqueStableNameExpr(SourceLocation OpLoc,
SourceLocation LParen,
SourceLocation RParen,
TypeSourceInfo *TSI);
ExprResult ActOnUniqueStableNameExpr(SourceLocation OpLoc,
SourceLocation LParen,
SourceLocation RParen,
ParsedType ParsedTy);
};

} // namespace clang

#endif // LLVM_CLANG_SEMA_SEMASYCL_H
27 changes: 7 additions & 20 deletions clang/include/clang/Serialization/ASTReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -1082,34 +1082,20 @@ class ASTReader

/// The set of lookup results that we have faked in order to support
/// merging of partially deserialized decls but that we have not yet removed.
llvm::SmallMapVector<IdentifierInfo *, SmallVector<NamedDecl*, 2>, 16>
PendingFakeLookupResults;
llvm::SmallMapVector<const IdentifierInfo *, SmallVector<NamedDecl *, 2>, 16>
PendingFakeLookupResults;

/// The generation number of each identifier, which keeps track of
/// the last time we loaded information about this identifier.
llvm::DenseMap<IdentifierInfo *, unsigned> IdentifierGeneration;

class InterestingDecl {
Decl *D;
bool DeclHasPendingBody;

public:
InterestingDecl(Decl *D, bool HasBody)
: D(D), DeclHasPendingBody(HasBody) {}

Decl *getDecl() { return D; }

/// Whether the declaration has a pending body.
bool hasPendingBody() { return DeclHasPendingBody; }
};
llvm::DenseMap<const IdentifierInfo *, unsigned> IdentifierGeneration;

/// Contains declarations and definitions that could be
/// "interesting" to the ASTConsumer, when we get that AST consumer.
///
/// "Interesting" declarations are those that have data that may
/// need to be emitted, such as inline function definitions or
/// Objective-C protocols.
std::deque<InterestingDecl> PotentiallyInterestingDecls;
std::deque<Decl *> PotentiallyInterestingDecls;

/// The list of deduced function types that we have not yet read, because
/// they might contain a deduced return type that refers to a local type
Expand Down Expand Up @@ -1506,6 +1492,7 @@ class ASTReader
getModuleFileLevelDecls(ModuleFile &Mod);

private:
bool isConsumerInterestedIn(Decl *D);
void PassInterestingDeclsToConsumer();
void PassInterestingDeclToConsumer(Decl *D);

Expand Down Expand Up @@ -2344,10 +2331,10 @@ class ASTReader
void ReadDefinedMacros() override;

/// Update an out-of-date identifier.
void updateOutOfDateIdentifier(IdentifierInfo &II) override;
void updateOutOfDateIdentifier(const IdentifierInfo &II) override;

/// Note that this identifier is up-to-date.
void markIdentifierUpToDate(IdentifierInfo *II);
void markIdentifierUpToDate(const IdentifierInfo *II);

/// Load all external visible decls in the given DeclContext.
void completeVisibleDeclsMap(const DeclContext *DC) override;
Expand Down
9 changes: 9 additions & 0 deletions clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
Original file line number Diff line number Diff line change
Expand Up @@ -604,6 +604,15 @@ def PthreadLockChecker : Checker<"PthreadLock">,
def StreamChecker : Checker<"Stream">,
HelpText<"Check stream handling functions">,
WeakDependencies<[NonNullParamChecker]>,
CheckerOptions<[
CmdLineOption<Boolean,
"Pedantic",
"If false, assume that stream operations which are often not "
"checked for error do not fail."
"fail.",
"false",
InAlpha>
]>,
Documentation<HasDocumentation>;

def SimpleStreamChecker : Checker<"SimpleStream">,
Expand Down
7 changes: 4 additions & 3 deletions clang/lib/ARCMigrate/ObjCMT.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1144,7 +1144,7 @@ static bool IsValidIdentifier(ASTContext &Ctx,
return false;
std::string NameString = Name;
NameString[0] = toLowercase(NameString[0]);
IdentifierInfo *II = &Ctx.Idents.get(NameString);
const IdentifierInfo *II = &Ctx.Idents.get(NameString);
return II->getTokenID() == tok::identifier;
}

Expand All @@ -1166,7 +1166,7 @@ bool ObjCMigrateASTConsumer::migrateProperty(ASTContext &Ctx,
if (OIT_Family != OIT_None)
return false;

IdentifierInfo *getterName = GetterSelector.getIdentifierInfoForSlot(0);
const IdentifierInfo *getterName = GetterSelector.getIdentifierInfoForSlot(0);
Selector SetterSelector =
SelectorTable::constructSetterSelector(PP.getIdentifierTable(),
PP.getSelectorTable(),
Expand Down Expand Up @@ -1311,7 +1311,8 @@ void ObjCMigrateASTConsumer::migrateFactoryMethod(ASTContext &Ctx,
std::string StringLoweredClassName = LoweredClassName.lower();
LoweredClassName = StringLoweredClassName;

IdentifierInfo *MethodIdName = OM->getSelector().getIdentifierInfoForSlot(0);
const IdentifierInfo *MethodIdName =
OM->getSelector().getIdentifierInfoForSlot(0);
// Handle method with no name at its first selector slot; e.g. + (id):(int)x.
if (!MethodIdName)
return;
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/ARCMigrate/TransAPIUses.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class APIChecker : public RecursiveASTVisitor<APIChecker> {
getReturnValueSel = sels.getUnarySelector(&ids.get("getReturnValue"));
setReturnValueSel = sels.getUnarySelector(&ids.get("setReturnValue"));

IdentifierInfo *selIds[2];
const IdentifierInfo *selIds[2];
selIds[0] = &ids.get("getArgument");
selIds[1] = &ids.get("atIndex");
getArgumentSel = sels.getSelector(2, selIds);
Expand Down
11 changes: 4 additions & 7 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6929,16 +6929,13 @@ ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const {
// typedef typename T::type T1;
// typedef typename T1::type T2;
if (const auto *DNT = T->getAs<DependentNameType>())
return NestedNameSpecifier::Create(
*this, DNT->getQualifier(),
const_cast<IdentifierInfo *>(DNT->getIdentifier()));
return NestedNameSpecifier::Create(*this, DNT->getQualifier(),
DNT->getIdentifier());
if (const auto *DTST = T->getAs<DependentTemplateSpecializationType>())
return NestedNameSpecifier::Create(*this, DTST->getQualifier(), true,
const_cast<Type *>(T));
return NestedNameSpecifier::Create(*this, DTST->getQualifier(), true, T);

// TODO: Set 'Template' parameter to true for other template types.
return NestedNameSpecifier::Create(*this, nullptr, false,
const_cast<Type *>(T));
return NestedNameSpecifier::Create(*this, nullptr, false, T);
}

case NestedNameSpecifier::Global:
Expand Down
6 changes: 3 additions & 3 deletions clang/lib/AST/ASTImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8383,8 +8383,8 @@ ASTNodeImporter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) {
return std::move(Err);

PseudoDestructorTypeStorage Storage;
if (IdentifierInfo *FromII = E->getDestroyedTypeIdentifier()) {
IdentifierInfo *ToII = Importer.Import(FromII);
if (const IdentifierInfo *FromII = E->getDestroyedTypeIdentifier()) {
const IdentifierInfo *ToII = Importer.Import(FromII);
ExpectedSLoc ToDestroyedTypeLocOrErr = import(E->getDestroyedTypeLoc());
if (!ToDestroyedTypeLocOrErr)
return ToDestroyedTypeLocOrErr.takeError();
Expand Down Expand Up @@ -10194,7 +10194,7 @@ Expected<Selector> ASTImporter::Import(Selector FromSel) {
if (FromSel.isNull())
return Selector{};

SmallVector<IdentifierInfo *, 4> Idents;
SmallVector<const IdentifierInfo *, 4> Idents;
Idents.push_back(Import(FromSel.getIdentifierInfoForSlot(0)));
for (unsigned I = 1, N = FromSel.getNumArgs(); I < N; ++I)
Idents.push_back(Import(FromSel.getIdentifierInfoForSlot(I)));
Expand Down
10 changes: 10 additions & 0 deletions clang/lib/AST/ComputeDependence.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,16 @@ ExprDependence clang::computeDependence(CXXThisExpr *E) {
// 'this' is type-dependent if the class type of the enclosing
// member function is dependent (C++ [temp.dep.expr]p2)
auto D = toExprDependenceForImpliedType(E->getType()->getDependence());

// If a lambda with an explicit object parameter captures '*this', then
// 'this' now refers to the captured copy of lambda, and if the lambda
// is type-dependent, so is the object and thus 'this'.
//
// Note: The standard does not mention this case explicitly, but we need
// to do this so we can mark NSDM accesses as dependent.
if (E->isCapturedByCopyInLambdaWithExplicitObjectParameter())
D |= ExprDependence::Type;

assert(!(D & ExprDependence::UnexpandedPack));
return D;
}
Expand Down
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
Loading