17 changes: 13 additions & 4 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -807,8 +807,12 @@ def gcc_install_dir_EQ : Joined<["--"], "gcc-install-dir=">,
"Note: executables (e.g. ld) used by the compiler are not overridden by the selected GCC installation">;
def gcc_toolchain : Joined<["--"], "gcc-toolchain=">, Flags<[NoXarchOption]>,
Visibility<[ClangOption, FlangOption]>,
HelpText<"Specify a directory where Clang can find 'include' and 'lib{,32,64}/gcc{,-cross}/$triple/$version'. "
"Clang will use the GCC installation with the largest version">;
HelpText<
"Specify a directory where Clang can find 'include' and 'lib{,32,64}/gcc{,-cross}/$triple/$version'. "
"Clang will use the GCC installation with the largest version">,
HelpTextForVariants<[FlangOption],
"Specify a directory where Flang can find 'lib{,32,64}/gcc{,-cross}/$triple/$version'. "
"Flang will use the GCC installation with the largest version">;
def gcc_triple_EQ : Joined<["--"], "gcc-triple=">,
HelpText<"Search for the GCC installation with the specified triple.">;
def CC : Flag<["-"], "CC">, Visibility<[ClangOption, CC1Option]>,
Expand Down Expand Up @@ -3100,6 +3104,11 @@ defm modules_skip_header_search_paths : BoolFOption<"modules-skip-header-search-
HeaderSearchOpts<"ModulesSkipHeaderSearchPaths">, DefaultFalse,
PosFlag<SetTrue, [], [], "Disable writing header search paths">,
NegFlag<SetFalse>, BothFlags<[], [CC1Option]>>;
def fno_modules_prune_non_affecting_module_map_files :
Flag<["-"], "fno-modules-prune-non-affecting-module-map-files">,
Group<f_Group>, Flags<[]>, Visibility<[CC1Option]>,
MarshallingInfoNegativeFlag<HeaderSearchOpts<"ModulesPruneNonAffectingModuleMaps">>,
HelpText<"Do not prune non-affecting module map files when writing module files">;

def fincremental_extensions :
Flag<["-"], "fincremental-extensions">,
Expand Down Expand Up @@ -4747,9 +4756,9 @@ def munaligned_symbols : Flag<["-"], "munaligned-symbols">, Group<m_Group>,
HelpText<"Expect external char-aligned symbols to be without ABI alignment (SystemZ only)">;
def mno_unaligned_symbols : Flag<["-"], "mno-unaligned-symbols">, Group<m_Group>,
HelpText<"Expect external char-aligned symbols to be without ABI alignment (SystemZ only)">;
def mstrict_align : Flag<["-"], "mstrict-align">,
def mstrict_align : Flag<["-"], "mstrict-align">, Group<m_Group>,
HelpText<"Force all memory accesses to be aligned (AArch64/LoongArch/RISC-V only)">;
def mno_strict_align : Flag<["-"], "mno-strict-align">,
def mno_strict_align : Flag<["-"], "mno-strict-align">, Group<m_Group>,
HelpText<"Allow memory accesses to be unaligned (AArch64/LoongArch/RISC-V only)">;
def mno_thumb : Flag<["-"], "mno-thumb">, Group<m_arm_Features_Group>;
def mrestrict_it: Flag<["-"], "mrestrict-it">, Group<m_arm_Features_Group>,
Expand Down
7 changes: 6 additions & 1 deletion clang/include/clang/Lex/HeaderSearchOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,10 @@ class HeaderSearchOptions {
LLVM_PREFERRED_TYPE(bool)
unsigned ModulesSkipPragmaDiagnosticMappings : 1;

/// Whether to prune non-affecting module map files from PCM files.
LLVM_PREFERRED_TYPE(bool)
unsigned ModulesPruneNonAffectingModuleMaps : 1;

LLVM_PREFERRED_TYPE(bool)
unsigned ModulesHashContent : 1;

Expand Down Expand Up @@ -280,7 +284,8 @@ class HeaderSearchOptions {
ModulesValidateDiagnosticOptions(true),
ModulesSkipDiagnosticOptions(false),
ModulesSkipHeaderSearchPaths(false),
ModulesSkipPragmaDiagnosticMappings(false), ModulesHashContent(false),
ModulesSkipPragmaDiagnosticMappings(false),
ModulesPruneNonAffectingModuleMaps(true), ModulesHashContent(false),
ModulesStrictContextHash(false), ModulesIncludeVFSUsage(false) {}

/// AddPath - Add the \p Path path to the specified \p Group list.
Expand Down
13 changes: 10 additions & 3 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -6527,7 +6527,10 @@ class Sema final : public SemaBase {
SourceLocation RParenLoc);

//// ActOnCXXThis - Parse 'this' pointer.
ExprResult ActOnCXXThis(SourceLocation loc);
ExprResult ActOnCXXThis(SourceLocation Loc);

/// Check whether the type of 'this' is valid in the current context.
bool CheckCXXThisType(SourceLocation Loc, QualType Type);

/// Build a CXXThisExpr and mark it referenced in the current context.
Expr *BuildCXXThisExpr(SourceLocation Loc, QualType Type, bool IsImplicit);
Expand Down Expand Up @@ -6949,10 +6952,14 @@ class Sema final : public SemaBase {
///@{

public:
/// Check whether an expression might be an implicit class member access.
bool isPotentialImplicitMemberAccess(const CXXScopeSpec &SS, LookupResult &R,
bool IsAddressOfOperand);

ExprResult BuildPossibleImplicitMemberExpr(
const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R,
const TemplateArgumentListInfo *TemplateArgs, const Scope *S,
UnresolvedLookupExpr *AsULE = nullptr);
const TemplateArgumentListInfo *TemplateArgs, const Scope *S);

ExprResult
BuildImplicitMemberExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
LookupResult &R,
Expand Down
27 changes: 20 additions & 7 deletions clang/lib/AST/ASTImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -695,7 +695,7 @@ namespace clang {
// Returns true if the given function has a placeholder return type and
// that type is declared inside the body of the function.
// E.g. auto f() { struct X{}; return X(); }
bool hasAutoReturnTypeDeclaredInside(FunctionDecl *D);
bool hasReturnTypeDeclaredInside(FunctionDecl *D);
};

template <typename InContainerTy>
Expand Down Expand Up @@ -3647,15 +3647,28 @@ class IsTypeDeclaredInsideVisitor
};
} // namespace

/// This function checks if the function has 'auto' return type that contains
/// This function checks if the given function has a return type that contains
/// a reference (in any way) to a declaration inside the same function.
bool ASTNodeImporter::hasAutoReturnTypeDeclaredInside(FunctionDecl *D) {
bool ASTNodeImporter::hasReturnTypeDeclaredInside(FunctionDecl *D) {
QualType FromTy = D->getType();
const auto *FromFPT = FromTy->getAs<FunctionProtoType>();
assert(FromFPT && "Must be called on FunctionProtoType");

auto IsCXX11LambdaWithouTrailingReturn = [&]() {
if (Importer.FromContext.getLangOpts().CPlusPlus14) // C++14 or later
return false;

if (FromFPT->hasTrailingReturn())
return false;

if (const auto *MD = dyn_cast<CXXMethodDecl>(D))
return cast<CXXRecordDecl>(MD->getDeclContext())->isLambda();

return false;
};

QualType RetT = FromFPT->getReturnType();
if (isa<AutoType>(RetT.getTypePtr())) {
if (isa<AutoType>(RetT.getTypePtr()) || IsCXX11LambdaWithouTrailingReturn()) {
FunctionDecl *Def = D->getDefinition();
IsTypeDeclaredInsideVisitor Visitor(Def ? Def : D);
return Visitor.CheckType(RetT);
Expand Down Expand Up @@ -3811,7 +3824,7 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
// E.g.: auto foo() { struct X{}; return X(); }
// To avoid an infinite recursion when importing, create the FunctionDecl
// with a simplified return type.
if (hasAutoReturnTypeDeclaredInside(D)) {
if (hasReturnTypeDeclaredInside(D)) {
FromReturnTy = Importer.getFromContext().VoidTy;
UsedDifferentProtoType = true;
}
Expand Down Expand Up @@ -8561,8 +8574,8 @@ ASTNodeImporter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) {

return UnresolvedLookupExpr::Create(
Importer.getToContext(), *ToNamingClassOrErr, *ToQualifierLocOrErr,
ToNameInfo, E->requiresADL(), E->isOverloaded(), ToDecls.begin(),
ToDecls.end());
ToNameInfo, E->requiresADL(), ToDecls.begin(), ToDecls.end(),
/*KnownDependent=*/E->isTypeDependent());
}

ExpectedStmt
Expand Down
28 changes: 14 additions & 14 deletions clang/lib/AST/ExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -353,15 +353,14 @@ SourceLocation CXXPseudoDestructorExpr::getEndLoc() const {
UnresolvedLookupExpr::UnresolvedLookupExpr(
const ASTContext &Context, CXXRecordDecl *NamingClass,
NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo, bool RequiresADL, bool Overloaded,
const DeclarationNameInfo &NameInfo, bool RequiresADL,
const TemplateArgumentListInfo *TemplateArgs, UnresolvedSetIterator Begin,
UnresolvedSetIterator End, bool KnownDependent)
: OverloadExpr(UnresolvedLookupExprClass, Context, QualifierLoc,
TemplateKWLoc, NameInfo, TemplateArgs, Begin, End,
KnownDependent, false, false),
NamingClass(NamingClass) {
UnresolvedLookupExprBits.RequiresADL = RequiresADL;
UnresolvedLookupExprBits.Overloaded = Overloaded;
}

UnresolvedLookupExpr::UnresolvedLookupExpr(EmptyShell Empty,
Expand All @@ -373,15 +372,16 @@ UnresolvedLookupExpr::UnresolvedLookupExpr(EmptyShell Empty,
UnresolvedLookupExpr *UnresolvedLookupExpr::Create(
const ASTContext &Context, CXXRecordDecl *NamingClass,
NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo &NameInfo,
bool RequiresADL, bool Overloaded, UnresolvedSetIterator Begin,
UnresolvedSetIterator End) {
bool RequiresADL, UnresolvedSetIterator Begin, UnresolvedSetIterator End,
bool KnownDependent) {
unsigned NumResults = End - Begin;
unsigned Size = totalSizeToAlloc<DeclAccessPair, ASTTemplateKWAndArgsInfo,
TemplateArgumentLoc>(NumResults, 0, 0);
void *Mem = Context.Allocate(Size, alignof(UnresolvedLookupExpr));
return new (Mem) UnresolvedLookupExpr(Context, NamingClass, QualifierLoc,
SourceLocation(), NameInfo, RequiresADL,
Overloaded, nullptr, Begin, End, false);
return new (Mem) UnresolvedLookupExpr(
Context, NamingClass, QualifierLoc,
/*TemplateKWLoc=*/SourceLocation(), NameInfo, RequiresADL,
/*TemplateArgs=*/nullptr, Begin, End, KnownDependent);
}

UnresolvedLookupExpr *UnresolvedLookupExpr::Create(
Expand All @@ -390,16 +390,16 @@ UnresolvedLookupExpr *UnresolvedLookupExpr::Create(
const DeclarationNameInfo &NameInfo, bool RequiresADL,
const TemplateArgumentListInfo *Args, UnresolvedSetIterator Begin,
UnresolvedSetIterator End, bool KnownDependent) {
assert(Args || TemplateKWLoc.isValid());
unsigned NumResults = End - Begin;
bool HasTemplateKWAndArgsInfo = Args || TemplateKWLoc.isValid();
unsigned NumTemplateArgs = Args ? Args->size() : 0;
unsigned Size =
totalSizeToAlloc<DeclAccessPair, ASTTemplateKWAndArgsInfo,
TemplateArgumentLoc>(NumResults, 1, NumTemplateArgs);
unsigned Size = totalSizeToAlloc<DeclAccessPair, ASTTemplateKWAndArgsInfo,
TemplateArgumentLoc>(
NumResults, HasTemplateKWAndArgsInfo, NumTemplateArgs);
void *Mem = Context.Allocate(Size, alignof(UnresolvedLookupExpr));
return new (Mem) UnresolvedLookupExpr(
Context, NamingClass, QualifierLoc, TemplateKWLoc, NameInfo, RequiresADL,
/*Overloaded=*/true, Args, Begin, End, KnownDependent);
return new (Mem) UnresolvedLookupExpr(Context, NamingClass, QualifierLoc,
TemplateKWLoc, NameInfo, RequiresADL,
Args, Begin, End, KnownDependent);
}

UnresolvedLookupExpr *UnresolvedLookupExpr::CreateEmpty(
Expand Down
30 changes: 26 additions & 4 deletions clang/lib/AST/Interp/ByteCodeExprGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,12 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
return false;

PrimType T = classifyPrim(CE->getType());
if (T == PT_IntAP)
return this->emitCastPointerIntegralAP(Ctx.getBitWidth(CE->getType()),
CE);
if (T == PT_IntAPS)
return this->emitCastPointerIntegralAPS(Ctx.getBitWidth(CE->getType()),
CE);
return this->emitCastPointerIntegral(T, CE);
}

Expand Down Expand Up @@ -922,9 +928,9 @@ bool ByteCodeExprGen<Emitter>::VisitImplicitValueInitExpr(const ImplicitValueIni
return true;
}

if (QT->isAnyComplexType()) {
if (const auto *ComplexTy = E->getType()->getAs<ComplexType>()) {
assert(Initializing);
QualType ElemQT = QT->getAs<ComplexType>()->getElementType();
QualType ElemQT = ComplexTy->getElementType();
PrimType ElemT = classifyPrim(ElemQT);
for (unsigned I = 0; I < 2; ++I) {
if (!this->visitZeroInitializer(ElemT, ElemQT, E))
Expand All @@ -935,6 +941,20 @@ bool ByteCodeExprGen<Emitter>::VisitImplicitValueInitExpr(const ImplicitValueIni
return true;
}

if (const auto *VecT = E->getType()->getAs<VectorType>()) {
unsigned NumVecElements = VecT->getNumElements();
QualType ElemQT = VecT->getElementType();
PrimType ElemT = classifyPrim(ElemQT);

for (unsigned I = 0; I < NumVecElements; ++I) {
if (!this->visitZeroInitializer(ElemT, ElemQT, E))
return false;
if (!this->emitInitElem(ElemT, I, E))
return false;
}
return true;
}

return false;
}

Expand Down Expand Up @@ -1098,13 +1118,13 @@ bool ByteCodeExprGen<Emitter>::VisitInitListExpr(const InitListExpr *E) {
return true;
}

if (T->isAnyComplexType()) {
if (const auto *ComplexTy = E->getType()->getAs<ComplexType>()) {
unsigned NumInits = E->getNumInits();

if (NumInits == 1)
return this->delegate(E->inits()[0]);

QualType ElemQT = E->getType()->getAs<ComplexType>()->getElementType();
QualType ElemQT = ComplexTy->getElementType();
PrimType ElemT = classifyPrim(ElemQT);
if (NumInits == 0) {
// Zero-initialize both elements.
Expand Down Expand Up @@ -1337,6 +1357,8 @@ bool ByteCodeExprGen<Emitter>::VisitMemberExpr(const MemberExpr *E) {
if (const auto *FD = dyn_cast<FieldDecl>(Member)) {
const RecordDecl *RD = FD->getParent();
const Record *R = getRecord(RD);
if (!R)
return false;
const Record::Field *F = R->getField(FD);
// Leave a pointer to the field on the stack.
if (F->Decl->getType()->isReferenceType())
Expand Down
25 changes: 24 additions & 1 deletion clang/lib/AST/Interp/ByteCodeStmtGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -675,7 +675,30 @@ bool ByteCodeStmtGen<Emitter>::visitDefaultStmt(const DefaultStmt *S) {

template <class Emitter>
bool ByteCodeStmtGen<Emitter>::visitAttributedStmt(const AttributedStmt *S) {
// Ignore all attributes.

for (const Attr *A : S->getAttrs()) {
auto *AA = dyn_cast<CXXAssumeAttr>(A);
if (!AA)
continue;

assert(isa<NullStmt>(S->getSubStmt()));

const Expr *Assumption = AA->getAssumption();
if (Assumption->isValueDependent())
return false;

if (Assumption->HasSideEffects(this->Ctx.getASTContext()))
continue;

// Evaluate assumption.
if (!this->visitBool(Assumption))
return false;

if (!this->emitAssume(Assumption))
return false;
}

// Ignore other attributes.
return this->visitStmt(S->getSubStmt());
}

Expand Down
63 changes: 51 additions & 12 deletions clang/lib/AST/Interp/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -1548,17 +1548,16 @@ bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset,
if (!CheckArray(S, OpPC, Ptr))
return false;

// Get a version of the index comparable to the type.
T Index = T::from(Ptr.getIndex(), Offset.bitWidth());
// Compute the largest index into the array.
T MaxIndex = T::from(Ptr.getNumElems(), Offset.bitWidth());
uint64_t Index = Ptr.getIndex();
uint64_t MaxIndex = static_cast<uint64_t>(Ptr.getNumElems());

bool Invalid = false;
// Helper to report an invalid offset, computed as APSInt.
auto DiagInvalidOffset = [&]() -> void {
const unsigned Bits = Offset.bitWidth();
APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), false);
APSInt APIndex(Index.toAPSInt().extend(Bits + 2), false);
APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), /*IsUnsigend=*/false);
APSInt APIndex(APInt(Bits + 2, Index, /*IsSigned=*/true),
/*IsUnsigned=*/false);
APSInt NewIndex =
(Op == ArithOp::Add) ? (APIndex + APOffset) : (APIndex - APOffset);
S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
Expand All @@ -1569,22 +1568,24 @@ bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset,
};

if (Ptr.isBlockPointer()) {
T MaxOffset = T::from(MaxIndex - Index, Offset.bitWidth());
uint64_t IOffset = static_cast<uint64_t>(Offset);
uint64_t MaxOffset = MaxIndex - Index;

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

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

// If the new offset would be out of bounds, bail out.
if (Offset.isNegative() && (Offset.isMin() || -Offset > MaxOffset))
if (Offset.isNegative() && (Offset.isMin() || -IOffset > MaxOffset))
DiagInvalidOffset();
}
}
Expand All @@ -1601,7 +1602,7 @@ bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset,
else
Result = WideIndex - WideOffset;

S.Stk.push<Pointer>(Ptr.atIndex(static_cast<unsigned>(Result)));
S.Stk.push<Pointer>(Ptr.atIndex(static_cast<uint64_t>(Result)));
return true;
}

Expand Down Expand Up @@ -1832,6 +1833,32 @@ bool CastPointerIntegral(InterpState &S, CodePtr OpPC) {
return true;
}

static inline bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC,
uint32_t BitWidth) {
const Pointer &Ptr = S.Stk.pop<Pointer>();

const SourceInfo &E = S.Current->getSource(OpPC);
S.CCEDiag(E, diag::note_constexpr_invalid_cast)
<< 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);

S.Stk.push<IntegralAP<false>>(
IntegralAP<false>::from(Ptr.getIntegerRepresentation(), BitWidth));
return true;
}

static inline bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC,
uint32_t BitWidth) {
const Pointer &Ptr = S.Stk.pop<Pointer>();

const SourceInfo &E = S.Current->getSource(OpPC);
S.CCEDiag(E, diag::note_constexpr_invalid_cast)
<< 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);

S.Stk.push<IntegralAP<true>>(
IntegralAP<true>::from(Ptr.getIntegerRepresentation(), BitWidth));
return true;
}

//===----------------------------------------------------------------------===//
// Zero, Nullptr
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -2300,6 +2327,18 @@ inline bool InvalidDeclRef(InterpState &S, CodePtr OpPC,
return CheckDeclRef(S, OpPC, DR);
}

inline bool Assume(InterpState &S, CodePtr OpPC) {
const auto Val = S.Stk.pop<Boolean>();

if (Val)
return true;

// Else, diagnose.
const SourceLocation &Loc = S.Current->getLocation(OpPC);
S.CCEDiag(Loc, diag::note_constexpr_assumption_failed);
return false;
}

template <PrimType Name, class T = typename PrimConv<Name>::T>
inline bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E) {
llvm::SmallVector<int64_t> ArrayIndices;
Expand Down
17 changes: 17 additions & 0 deletions clang/lib/AST/Interp/InterpBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "Boolean.h"
#include "Interp.h"
#include "PrimType.h"
#include "clang/AST/OSLog.h"
#include "clang/AST/RecordLayout.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/TargetInfo.h"
Expand Down Expand Up @@ -1088,6 +1089,17 @@ static bool interp__builtin_is_aligned_up_down(InterpState &S, CodePtr OpPC,
return false;
}

static bool interp__builtin_os_log_format_buffer_size(InterpState &S,
CodePtr OpPC,
const InterpFrame *Frame,
const Function *Func,
const CallExpr *Call) {
analyze_os_log::OSLogBufferLayout Layout;
analyze_os_log::computeOSLogBufferLayout(S.getCtx(), Call, Layout);
pushInteger(S, Layout.size().getQuantity(), Call->getType());
return true;
}

bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
const CallExpr *Call) {
const InterpFrame *Frame = S.Current;
Expand Down Expand Up @@ -1409,6 +1421,11 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
return false;
break;

case Builtin::BI__builtin_os_log_format_buffer_size:
if (!interp__builtin_os_log_format_buffer_size(S, OpPC, Frame, F, Call))
return false;
break;

default:
S.FFDiag(S.Current->getLocation(OpPC),
diag::note_invalid_subexpr_in_const_expr)
Expand Down
15 changes: 13 additions & 2 deletions clang/lib/AST/Interp/Opcodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -664,10 +664,19 @@ def CastFloatingIntegralAPS : Opcode {
}

def CastPointerIntegral : Opcode {
let Types = [AluTypeClass];
let Args = [];
let Types = [FixedSizeIntegralTypeClass];
let HasGroup = 1;
}
def CastPointerIntegralAP : Opcode {
let Types = [];
let HasGroup = 0;
let Args = [ArgUint32];
}
def CastPointerIntegralAPS : Opcode {
let Types = [];
let HasGroup = 0;
let Args = [ArgUint32];
}

def DecayPtr : Opcode {
let Types = [PtrTypeClass, PtrTypeClass];
Expand Down Expand Up @@ -727,6 +736,8 @@ def InvalidDeclRef : Opcode {
let Args = [ArgDeclRef];
}

def Assume : Opcode;

def ArrayDecay : Opcode;

def CheckNonNullArg : Opcode {
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/AST/Interp/Pointer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Pointer::Pointer(Block *Pointee)
: Pointer(Pointee, Pointee->getDescriptor()->getMetadataSize(),
Pointee->getDescriptor()->getMetadataSize()) {}

Pointer::Pointer(Block *Pointee, unsigned BaseAndOffset)
Pointer::Pointer(Block *Pointee, uint64_t BaseAndOffset)
: Pointer(Pointee, BaseAndOffset, BaseAndOffset) {}

Pointer::Pointer(const Pointer &P)
Expand All @@ -34,7 +34,7 @@ Pointer::Pointer(const Pointer &P)
PointeeStorage.BS.Pointee->addPointer(this);
}

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

Expand Down
12 changes: 6 additions & 6 deletions clang/lib/AST/Interp/Pointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,10 @@ class Pointer {
PointeeStorage.Int.Desc = nullptr;
}
Pointer(Block *B);
Pointer(Block *B, unsigned BaseAndOffset);
Pointer(Block *B, uint64_t BaseAndOffset);
Pointer(const Pointer &P);
Pointer(Pointer &&P);
Pointer(uint64_t Address, const Descriptor *Desc, unsigned Offset = 0)
Pointer(uint64_t Address, const Descriptor *Desc, uint64_t Offset = 0)
: Offset(Offset), StorageKind(Storage::Int) {
PointeeStorage.Int.Value = Address;
PointeeStorage.Int.Desc = Desc;
Expand Down Expand Up @@ -134,14 +134,14 @@ class Pointer {
std::optional<APValue> toRValue(const Context &Ctx) const;

/// Offsets a pointer inside an array.
[[nodiscard]] Pointer atIndex(unsigned Idx) const {
[[nodiscard]] Pointer atIndex(uint64_t Idx) const {
if (isIntegralPointer())
return Pointer(asIntPointer().Value, asIntPointer().Desc, Idx);

if (asBlockPointer().Base == RootPtrMark)
return Pointer(asBlockPointer().Pointee, RootPtrMark,
getDeclDesc()->getSize());
unsigned Off = Idx * elemSize();
uint64_t Off = Idx * elemSize();
if (getFieldDesc()->ElemDesc)
Off += sizeof(InlineDescriptor);
else
Expand Down Expand Up @@ -630,7 +630,7 @@ class Pointer {
friend class DeadBlock;
friend struct InitMap;

Pointer(Block *Pointee, unsigned Base, unsigned Offset);
Pointer(Block *Pointee, unsigned Base, uint64_t Offset);

/// Returns the embedded descriptor preceding a field.
InlineDescriptor *getInlineDesc() const {
Expand All @@ -656,7 +656,7 @@ class Pointer {
}

/// Offset into the storage.
unsigned Offset = 0;
uint64_t Offset = 0;

/// Previous link in the pointer chain.
Pointer *Prev = nullptr;
Expand Down
15 changes: 5 additions & 10 deletions clang/lib/AST/Interp/Program.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,27 +108,23 @@ Pointer Program::getPtrGlobal(unsigned Idx) const {
}

std::optional<unsigned> Program::getGlobal(const ValueDecl *VD) {
auto It = GlobalIndices.find(VD);
if (It != GlobalIndices.end())
if (auto It = GlobalIndices.find(VD); It != GlobalIndices.end())
return It->second;

// Find any previous declarations which were already evaluated.
std::optional<unsigned> Index;
for (const Decl *P = VD; P; P = P->getPreviousDecl()) {
auto It = GlobalIndices.find(P);
if (It != GlobalIndices.end()) {
for (const Decl *P = VD->getPreviousDecl(); P; P = P->getPreviousDecl()) {
if (auto It = GlobalIndices.find(P); It != GlobalIndices.end()) {
Index = It->second;
break;
}
}

// Map the decl to the existing index.
if (Index) {
if (Index)
GlobalIndices[VD] = *Index;
return std::nullopt;
}

return Index;
return std::nullopt;
}

std::optional<unsigned> Program::getOrCreateGlobal(const ValueDecl *VD,
Expand Down Expand Up @@ -173,7 +169,6 @@ std::optional<unsigned> Program::getOrCreateDummy(const ValueDecl *VD) {

std::optional<unsigned> Program::createGlobal(const ValueDecl *VD,
const Expr *Init) {
assert(!getGlobal(VD));
bool IsStatic, IsExtern;
if (const auto *Var = dyn_cast<VarDecl>(VD)) {
IsStatic = Context::shouldBeGloballyIndexed(VD);
Expand Down
18 changes: 9 additions & 9 deletions clang/lib/AST/ItaniumMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1062,33 +1062,35 @@ void CXXNameMangler::mangleNameWithAbiTags(GlobalDecl GD,
// ::= <local-name>
//
const DeclContext *DC = Context.getEffectiveDeclContext(ND);
bool IsLambda = isLambda(ND);

// If this is an extern variable declared locally, the relevant DeclContext
// is that of the containing namespace, or the translation unit.
// FIXME: This is a hack; extern variables declared locally should have
// a proper semantic declaration context!
if (isLocalContainerContext(DC) && ND->hasLinkage() && !isLambda(ND))
if (isLocalContainerContext(DC) && ND->hasLinkage() && !IsLambda)
while (!DC->isNamespace() && !DC->isTranslationUnit())
DC = Context.getEffectiveParentContext(DC);
else if (GetLocalClassDecl(ND)) {
else if (GetLocalClassDecl(ND) &&
(!IsLambda || isCompatibleWith(LangOptions::ClangABI::Ver18))) {
mangleLocalName(GD, AdditionalAbiTags);
return;
}

assert(!isa<LinkageSpecDecl>(DC) && "context cannot be LinkageSpecDecl");

if (isLocalContainerContext(DC)) {
mangleLocalName(GD, AdditionalAbiTags);
return;
}

// Closures can require a nested-name mangling even if they're semantically
// in the global namespace.
if (const NamedDecl *PrefixND = getClosurePrefix(ND)) {
mangleNestedNameWithClosurePrefix(GD, PrefixND, AdditionalAbiTags);
return;
}

if (isLocalContainerContext(DC)) {
mangleLocalName(GD, AdditionalAbiTags);
return;
}

if (DC->isTranslationUnit() || isStdNamespace(DC)) {
// Check if we have a template.
const TemplateArgumentList *TemplateArgs = nullptr;
Expand Down Expand Up @@ -2201,8 +2203,6 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) {
if (NoFunction && isLocalContainerContext(DC))
return;

assert(!isLocalContainerContext(DC));

const NamedDecl *ND = cast<NamedDecl>(DC);
if (mangleSubstitution(ND))
return;
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/ASTMatchers/Dynamic/Marshallers.h
Original file line number Diff line number Diff line change
Expand Up @@ -937,7 +937,7 @@ class MapAnyOfMatcherDescriptor : public MatcherDescriptor {
public:
MapAnyOfMatcherDescriptor(ASTNodeKind CladeNodeKind,
std::vector<ASTNodeKind> NodeKinds)
: CladeNodeKind(CladeNodeKind), NodeKinds(NodeKinds) {}
: CladeNodeKind(CladeNodeKind), NodeKinds(std::move(NodeKinds)) {}

VariantMatcher create(SourceRange NameRange, ArrayRef<ParserValue> Args,
Diagnostics *Error) const override {
Expand Down Expand Up @@ -1026,7 +1026,7 @@ class MapAnyOfBuilderDescriptor : public MatcherDescriptor {
}

return std::make_unique<MapAnyOfMatcherDescriptor>(CladeNodeKind,
NodeKinds);
std::move(NodeKinds));
}

bool isVariadic() const override { return true; }
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Analysis/FlowSensitive/ASTOps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -261,4 +261,10 @@ ReferencedDecls getReferencedDecls(const FunctionDecl &FD) {
return Result;
}

ReferencedDecls getReferencedDecls(const Stmt &S) {
ReferencedDecls Result;
getReferencedDecls(S, Result);
return Result;
}

} // namespace clang::dataflow
57 changes: 35 additions & 22 deletions clang/lib/CodeGen/BackendUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,21 @@ static cl::opt<bool> ClSanitizeOnOptimizerEarlyEP(
"sanitizer-early-opt-ep", cl::Optional,
cl::desc("Insert sanitizers on OptimizerEarlyEP."));

// Experiment to mark cold functions as optsize/minsize/optnone.
// TODO: remove once this is exposed as a proper driver flag.
static cl::opt<PGOOptions::ColdFuncOpt> ClPGOColdFuncAttr(
"pgo-cold-func-opt", cl::init(PGOOptions::ColdFuncOpt::Default), cl::Hidden,
cl::desc(
"Function attribute to apply to cold functions as determined by PGO"),
cl::values(clEnumValN(PGOOptions::ColdFuncOpt::Default, "default",
"Default (no attribute)"),
clEnumValN(PGOOptions::ColdFuncOpt::OptSize, "optsize",
"Mark cold functions with optsize."),
clEnumValN(PGOOptions::ColdFuncOpt::MinSize, "minsize",
"Mark cold functions with minsize."),
clEnumValN(PGOOptions::ColdFuncOpt::OptNone, "optnone",
"Mark cold functions with optnone.")));

extern cl::opt<InstrProfCorrelator::ProfCorrelatorKind> ProfileCorrelate;

// Re-link builtin bitcodes after optimization
Expand Down Expand Up @@ -768,42 +783,41 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
CodeGenOpts.InstrProfileOutput.empty() ? getDefaultProfileGenName()
: CodeGenOpts.InstrProfileOutput,
"", "", CodeGenOpts.MemoryProfileUsePath, nullptr, PGOOptions::IRInstr,
PGOOptions::NoCSAction, PGOOptions::ColdFuncOpt::Default,
PGOOptions::NoCSAction, ClPGOColdFuncAttr,
CodeGenOpts.DebugInfoForProfiling,
/*PseudoProbeForProfiling=*/false, CodeGenOpts.AtomicProfileUpdate);
else if (CodeGenOpts.hasProfileIRUse()) {
// -fprofile-use.
auto CSAction = CodeGenOpts.hasProfileCSIRUse() ? PGOOptions::CSIRUse
: PGOOptions::NoCSAction;
PGOOpt = PGOOptions(
CodeGenOpts.ProfileInstrumentUsePath, "",
CodeGenOpts.ProfileRemappingFile, CodeGenOpts.MemoryProfileUsePath, VFS,
PGOOptions::IRUse, CSAction, PGOOptions::ColdFuncOpt::Default,
CodeGenOpts.DebugInfoForProfiling);
PGOOpt = PGOOptions(CodeGenOpts.ProfileInstrumentUsePath, "",
CodeGenOpts.ProfileRemappingFile,
CodeGenOpts.MemoryProfileUsePath, VFS,
PGOOptions::IRUse, CSAction, ClPGOColdFuncAttr,
CodeGenOpts.DebugInfoForProfiling);
} else if (!CodeGenOpts.SampleProfileFile.empty())
// -fprofile-sample-use
PGOOpt = PGOOptions(
CodeGenOpts.SampleProfileFile, "", CodeGenOpts.ProfileRemappingFile,
CodeGenOpts.MemoryProfileUsePath, VFS, PGOOptions::SampleUse,
PGOOptions::NoCSAction, PGOOptions::ColdFuncOpt::Default,
PGOOptions::NoCSAction, ClPGOColdFuncAttr,
CodeGenOpts.DebugInfoForProfiling, CodeGenOpts.PseudoProbeForProfiling);
else if (!CodeGenOpts.MemoryProfileUsePath.empty())
// -fmemory-profile-use (without any of the above options)
PGOOpt = PGOOptions("", "", "", CodeGenOpts.MemoryProfileUsePath, VFS,
PGOOptions::NoAction, PGOOptions::NoCSAction,
PGOOptions::ColdFuncOpt::Default,
CodeGenOpts.DebugInfoForProfiling);
ClPGOColdFuncAttr, CodeGenOpts.DebugInfoForProfiling);
else if (CodeGenOpts.PseudoProbeForProfiling)
// -fpseudo-probe-for-profiling
PGOOpt = PGOOptions("", "", "", /*MemoryProfile=*/"", nullptr,
PGOOptions::NoAction, PGOOptions::NoCSAction,
PGOOptions::ColdFuncOpt::Default,
CodeGenOpts.DebugInfoForProfiling, true);
PGOOpt =
PGOOptions("", "", "", /*MemoryProfile=*/"", nullptr,
PGOOptions::NoAction, PGOOptions::NoCSAction,
ClPGOColdFuncAttr, CodeGenOpts.DebugInfoForProfiling, true);
else if (CodeGenOpts.DebugInfoForProfiling)
// -fdebug-info-for-profiling
PGOOpt = PGOOptions("", "", "", /*MemoryProfile=*/"", nullptr,
PGOOptions::NoAction, PGOOptions::NoCSAction,
PGOOptions::ColdFuncOpt::Default, true);
ClPGOColdFuncAttr, true);

// Check to see if we want to generate a CS profile.
if (CodeGenOpts.hasProfileCSIRInstr()) {
Expand All @@ -820,14 +834,13 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
: CodeGenOpts.InstrProfileOutput;
PGOOpt->CSAction = PGOOptions::CSIRInstr;
} else
PGOOpt =
PGOOptions("",
CodeGenOpts.InstrProfileOutput.empty()
? getDefaultProfileGenName()
: CodeGenOpts.InstrProfileOutput,
"", /*MemoryProfile=*/"", nullptr, PGOOptions::NoAction,
PGOOptions::CSIRInstr, PGOOptions::ColdFuncOpt::Default,
CodeGenOpts.DebugInfoForProfiling);
PGOOpt = PGOOptions("",
CodeGenOpts.InstrProfileOutput.empty()
? getDefaultProfileGenName()
: CodeGenOpts.InstrProfileOutput,
"", /*MemoryProfile=*/"", nullptr,
PGOOptions::NoAction, PGOOptions::CSIRInstr,
ClPGOColdFuncAttr, CodeGenOpts.DebugInfoForProfiling);
}
if (TM)
TM->setPGOOption(PGOOpt);
Expand Down
62 changes: 36 additions & 26 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -826,29 +826,32 @@ const FieldDecl *CodeGenFunction::FindFlexibleArrayMemberField(
ASTContext &Ctx, const RecordDecl *RD, StringRef Name, uint64_t &Offset) {
const LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel =
getLangOpts().getStrictFlexArraysLevel();
unsigned FieldNo = 0;
bool IsUnion = RD->isUnion();
uint32_t FieldNo = 0;

for (const Decl *D : RD->decls()) {
if (const auto *Field = dyn_cast<FieldDecl>(D);
Field && (Name.empty() || Field->getNameAsString() == Name) &&
if (RD->isImplicit())
return nullptr;

for (const FieldDecl *FD : RD->fields()) {
if ((Name.empty() || FD->getNameAsString() == Name) &&
Decl::isFlexibleArrayMemberLike(
Ctx, Field, Field->getType(), StrictFlexArraysLevel,
Ctx, FD, FD->getType(), StrictFlexArraysLevel,
/*IgnoreTemplateOrMacroSubstitution=*/true)) {
const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
Offset += Layout.getFieldOffset(FieldNo);
return Field;
return FD;
}

if (const auto *Record = dyn_cast<RecordDecl>(D))
if (const FieldDecl *Field =
FindFlexibleArrayMemberField(Ctx, Record, Name, Offset)) {
QualType Ty = FD->getType();
if (Ty->isRecordType()) {
if (const FieldDecl *Field = FindFlexibleArrayMemberField(
Ctx, Ty->getAsRecordDecl(), Name, Offset)) {
const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
Offset += Layout.getFieldOffset(FieldNo);
return Field;
}
}

if (!IsUnion && isa<FieldDecl>(D))
if (!RD->isUnion())
++FieldNo;
}

Expand All @@ -858,14 +861,13 @@ const FieldDecl *CodeGenFunction::FindFlexibleArrayMemberField(
static unsigned CountCountedByAttrs(const RecordDecl *RD) {
unsigned Num = 0;

for (const Decl *D : RD->decls()) {
if (const auto *FD = dyn_cast<FieldDecl>(D);
FD && FD->getType()->isCountAttributedType()) {
for (const FieldDecl *FD : RD->fields()) {
if (FD->getType()->isCountAttributedType())
return ++Num;
}

if (const auto *Rec = dyn_cast<RecordDecl>(D))
Num += CountCountedByAttrs(Rec);
QualType Ty = FD->getType();
if (Ty->isRecordType())
Num += CountCountedByAttrs(Ty->getAsRecordDecl());
}

return Num;
Expand Down Expand Up @@ -18294,20 +18296,28 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
Value *M = EmitScalarExpr(E->getArg(0));
Value *A = EmitScalarExpr(E->getArg(1));
Value *B = EmitScalarExpr(E->getArg(2));
if (E->getArg(0)->getType()->hasFloatingRepresentation()) {
if (E->getArg(0)->getType()->hasFloatingRepresentation())
return Builder.CreateIntrinsic(
/*ReturnType*/ M->getType(), Intrinsic::fmuladd,
ArrayRef<Value *>{M, A, B}, nullptr, "dx.fmad");
}
ArrayRef<Value *>{M, A, B}, nullptr, "hlsl.fmad");

if (E->getArg(0)->getType()->hasSignedIntegerRepresentation()) {
return Builder.CreateIntrinsic(
/*ReturnType*/ M->getType(), Intrinsic::dx_imad,
ArrayRef<Value *>{M, A, B}, nullptr, "dx.imad");
if (CGM.getTarget().getTriple().getArch() == llvm::Triple::dxil)
return Builder.CreateIntrinsic(
/*ReturnType*/ M->getType(), Intrinsic::dx_imad,
ArrayRef<Value *>{M, A, B}, nullptr, "dx.imad");

Value *Mul = Builder.CreateNSWMul(M, A);
return Builder.CreateNSWAdd(Mul, B);
}
assert(E->getArg(0)->getType()->hasUnsignedIntegerRepresentation());
return Builder.CreateIntrinsic(
/*ReturnType=*/M->getType(), Intrinsic::dx_umad,
ArrayRef<Value *>{M, A, B}, nullptr, "dx.umad");
if (CGM.getTarget().getTriple().getArch() == llvm::Triple::dxil)
return Builder.CreateIntrinsic(
/*ReturnType=*/M->getType(), Intrinsic::dx_umad,
ArrayRef<Value *>{M, A, B}, nullptr, "dx.umad");

Value *Mul = Builder.CreateNUWMul(M, A);
return Builder.CreateNUWAdd(Mul, B);
}
case Builtin::BI__builtin_hlsl_elementwise_rcp: {
Value *Op0 = EmitScalarExpr(E->getArg(0));
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/CodeGen/CGExprScalar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1540,7 +1540,7 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
if (auto DstPT = dyn_cast<llvm::PointerType>(DstTy)) {
// The source value may be an integer, or a pointer.
if (isa<llvm::PointerType>(SrcTy))
return Builder.CreateBitCast(Src, DstTy, "conv");
return Src;

assert(SrcType->isIntegerType() && "Not ptr->ptr or int->ptr conversion?");
// First, convert to the correct width so that we control the kind of
Expand Down
54 changes: 38 additions & 16 deletions clang/lib/Driver/OffloadBundler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1010,13 +1010,19 @@ CompressedOffloadBundle::compress(llvm::compression::Params P,

uint16_t CompressionMethod = static_cast<uint16_t>(P.format);
uint32_t UncompressedSize = Input.getBuffer().size();
uint32_t TotalFileSize = MagicNumber.size() + sizeof(TotalFileSize) +
sizeof(Version) + sizeof(CompressionMethod) +
sizeof(UncompressedSize) + sizeof(TruncatedHash) +
CompressedBuffer.size();

SmallVector<char, 0> FinalBuffer;
llvm::raw_svector_ostream OS(FinalBuffer);
OS << MagicNumber;
OS.write(reinterpret_cast<const char *>(&Version), sizeof(Version));
OS.write(reinterpret_cast<const char *>(&CompressionMethod),
sizeof(CompressionMethod));
OS.write(reinterpret_cast<const char *>(&TotalFileSize),
sizeof(TotalFileSize));
OS.write(reinterpret_cast<const char *>(&UncompressedSize),
sizeof(UncompressedSize));
OS.write(reinterpret_cast<const char *>(&TruncatedHash),
Expand All @@ -1034,6 +1040,8 @@ CompressedOffloadBundle::compress(llvm::compression::Params P,
(UncompressedSize / (1024.0 * 1024.0)) / CompressionTimeSeconds;

llvm::errs() << "Compressed bundle format version: " << Version << "\n"
<< "Total file size (including headers): "
<< formatWithCommas(TotalFileSize) << " bytes\n"
<< "Compression method used: " << MethodUsed << "\n"
<< "Compression level: " << P.level << "\n"
<< "Binary size before compression: "
Expand All @@ -1059,31 +1067,42 @@ CompressedOffloadBundle::decompress(const llvm::MemoryBuffer &Input,

StringRef Blob = Input.getBuffer();

if (Blob.size() < HeaderSize) {
if (Blob.size() < V1HeaderSize)
return llvm::MemoryBuffer::getMemBufferCopy(Blob);
}

if (llvm::identify_magic(Blob) !=
llvm::file_magic::offload_bundle_compressed) {
if (Verbose)
llvm::errs() << "Uncompressed bundle.\n";
return llvm::MemoryBuffer::getMemBufferCopy(Blob);
}

size_t CurrentOffset = MagicSize;

uint16_t ThisVersion;
memcpy(&ThisVersion, Blob.data() + CurrentOffset, sizeof(uint16_t));
CurrentOffset += VersionFieldSize;

uint16_t CompressionMethod;
memcpy(&CompressionMethod, Blob.data() + CurrentOffset, sizeof(uint16_t));
CurrentOffset += MethodFieldSize;

uint32_t TotalFileSize;
if (ThisVersion >= 2) {
if (Blob.size() < V2HeaderSize)
return createStringError(inconvertibleErrorCode(),
"Compressed bundle header size too small");
memcpy(&TotalFileSize, Blob.data() + CurrentOffset, sizeof(uint32_t));
CurrentOffset += FileSizeFieldSize;
}

uint32_t UncompressedSize;
memcpy(&UncompressedSize, Blob.data() + CurrentOffset, sizeof(uint32_t));
CurrentOffset += UncompressedSizeFieldSize;

uint64_t StoredHash;
memcpy(&ThisVersion, Input.getBuffer().data() + MagicNumber.size(),
sizeof(uint16_t));
memcpy(&CompressionMethod, Blob.data() + MagicSize + VersionFieldSize,
sizeof(uint16_t));
memcpy(&UncompressedSize,
Blob.data() + MagicSize + VersionFieldSize + MethodFieldSize,
sizeof(uint32_t));
memcpy(&StoredHash,
Blob.data() + MagicSize + VersionFieldSize + MethodFieldSize +
SizeFieldSize,
sizeof(uint64_t));
memcpy(&StoredHash, Blob.data() + CurrentOffset, sizeof(uint64_t));
CurrentOffset += HashFieldSize;

llvm::compression::Format CompressionFormat;
if (CompressionMethod ==
Expand All @@ -1102,7 +1121,7 @@ CompressedOffloadBundle::decompress(const llvm::MemoryBuffer &Input,
DecompressTimer.startTimer();

SmallVector<uint8_t, 0> DecompressedData;
StringRef CompressedData = Blob.substr(HeaderSize);
StringRef CompressedData = Blob.substr(CurrentOffset);
if (llvm::Error DecompressionError = llvm::compression::decompress(
CompressionFormat, llvm::arrayRefFromStringRef(CompressedData),
DecompressedData, UncompressedSize))
Expand Down Expand Up @@ -1135,8 +1154,11 @@ CompressedOffloadBundle::decompress(const llvm::MemoryBuffer &Input,
double DecompressionSpeedMBs =
(UncompressedSize / (1024.0 * 1024.0)) / DecompressionTimeSeconds;

llvm::errs() << "Compressed bundle format version: " << ThisVersion << "\n"
<< "Decompression method: "
llvm::errs() << "Compressed bundle format version: " << ThisVersion << "\n";
if (ThisVersion >= 2)
llvm::errs() << "Total file size (from header): "
<< formatWithCommas(TotalFileSize) << " bytes\n";
llvm::errs() << "Decompression method: "
<< (CompressionFormat == llvm::compression::Format::Zlib
? "zlib"
: "zstd")
Expand Down
14 changes: 10 additions & 4 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4634,7 +4634,7 @@ renderDebugOptions(const ToolChain &TC, const Driver &D, const llvm::Triple &T,

// Emit DW_TAG_template_alias for template aliases? True by default for SCE.
bool UseDebugTemplateAlias =
DebuggerTuning == llvm::DebuggerKind::SCE && RequestedDWARFVersion >= 5;
DebuggerTuning == llvm::DebuggerKind::SCE && RequestedDWARFVersion >= 4;
if (const auto *DebugTemplateAlias = Args.getLastArg(
options::OPT_gtemplate_alias, options::OPT_gno_template_alias)) {
// DW_TAG_template_alias is only supported from DWARFv5 but if a user
Expand Down Expand Up @@ -4733,7 +4733,7 @@ renderDebugOptions(const ToolChain &TC, const Driver &D, const llvm::Triple &T,
Output.getFilename());
}

static void ProcessVSRuntimeLibrary(const ArgList &Args,
static void ProcessVSRuntimeLibrary(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs) {
unsigned RTOptionID = options::OPT__SLASH_MT;

Expand Down Expand Up @@ -4796,6 +4796,12 @@ static void ProcessVSRuntimeLibrary(const ArgList &Args,
// implemented in clang.
CmdArgs.push_back("--dependent-lib=oldnames");
}

// All Arm64EC object files implicitly add softintrin.lib. This is necessary
// even if the file doesn't actually refer to any of the routines because
// the CRT itself has incomplete dependency markings.
if (TC.getTriple().isWindowsArm64EC())
CmdArgs.push_back("--dependent-lib=softintrin");
}

void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Expand Down Expand Up @@ -7051,7 +7057,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,

if (Triple.isWindowsMSVCEnvironment() && !D.IsCLMode() &&
Args.hasArg(options::OPT_fms_runtime_lib_EQ))
ProcessVSRuntimeLibrary(Args, CmdArgs);
ProcessVSRuntimeLibrary(getToolChain(), Args, CmdArgs);

// Handle -fgcc-version, if present.
VersionTuple GNUCVer;
Expand Down Expand Up @@ -8178,7 +8184,7 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType,
ArgStringList &CmdArgs) const {
bool isNVPTX = getToolChain().getTriple().isNVPTX();

ProcessVSRuntimeLibrary(Args, CmdArgs);
ProcessVSRuntimeLibrary(getToolChain(), Args, CmdArgs);

if (Arg *ShowIncludes =
Args.getLastArg(options::OPT__SLASH_showIncludes,
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Driver/ToolChains/Flang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ void Flang::addOtherOptions(const ArgList &Args, ArgStringList &CmdArgs) const {
Arg *gNArg = Args.getLastArg(options::OPT_gN_Group);
DebugInfoKind = debugLevelToInfoKind(*gNArg);
} else if (Args.hasArg(options::OPT_g_Flag)) {
DebugInfoKind = llvm::codegenoptions::DebugLineTablesOnly;
DebugInfoKind = llvm::codegenoptions::FullDebugInfo;
} else {
DebugInfoKind = llvm::codegenoptions::NoDebugInfo;
}
Expand Down
5 changes: 4 additions & 1 deletion clang/lib/Format/TokenAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1543,6 +1543,7 @@ class AnnotatingParser {
return false;
if (Line.MustBeDeclaration && Contexts.size() == 1 &&
!Contexts.back().IsExpression && !Line.startsWith(TT_ObjCProperty) &&
!Line.startsWith(tok::l_paren) &&
!Tok->isOneOf(TT_TypeDeclarationParen, TT_RequiresExpressionLParen)) {
if (const auto *Previous = Tok->Previous;
!Previous ||
Expand Down Expand Up @@ -2726,8 +2727,10 @@ class AnnotatingParser {
}
}

if (Tok.Next->isOneOf(tok::question, tok::ampamp))
if (Tok.Next->is(tok::question) ||
(Tok.Next->is(tok::ampamp) && !Tok.Previous->isTypeName(IsCpp))) {
return false;
}

// `foreach((A a, B b) in someList)` should not be seen as a cast.
if (Tok.Next->is(Keywords.kw_in) && Style.isCSharp())
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3660,6 +3660,9 @@ void CompilerInvocationBase::GenerateLangArgs(const LangOptions &Opts,
case LangOptions::ClangABI::Ver17:
GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "17.0");
break;
case LangOptions::ClangABI::Ver18:
GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "18.0");
break;
case LangOptions::ClangABI::Latest:
break;
}
Expand Down Expand Up @@ -4167,6 +4170,8 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
Opts.setClangABICompat(LangOptions::ClangABI::Ver15);
else if (Major <= 17)
Opts.setClangABICompat(LangOptions::ClangABI::Ver17);
else if (Major <= 18)
Opts.setClangABICompat(LangOptions::ClangABI::Ver18);
} else if (Ver != "latest") {
Diags.Report(diag::err_drv_invalid_value)
<< A->getAsString(Args) << A->getValue();
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Headers/avxintrin.h
Original file line number Diff line number Diff line change
Expand Up @@ -840,6 +840,7 @@ _mm256_permutevar_pd(__m256d __a, __m256i __c)

/// Copies the values stored in a 128-bit vector of [4 x float] as
/// specified by the 128-bit integer vector operand.
///
/// \headerfile <x86intrin.h>
///
/// This intrinsic corresponds to the <c> VPERMILPS </c> instruction.
Expand Down
24 changes: 19 additions & 5 deletions clang/lib/Interpreter/IncrementalParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,10 @@ IncrementalParser::IncrementalParser(Interpreter &Interp,
if (Err)
return;
CI->ExecuteAction(*Act);

if (getCodeGen())
CachedInCodeGenModule = GenModule();

std::unique_ptr<ASTConsumer> IncrConsumer =
std::make_unique<IncrementalASTConsumer>(Interp, CI->takeASTConsumer());
CI->setASTConsumer(std::move(IncrConsumer));
Expand All @@ -224,11 +228,8 @@ IncrementalParser::IncrementalParser(Interpreter &Interp,
return; // PTU.takeError();
}

if (CodeGenerator *CG = getCodeGen()) {
std::unique_ptr<llvm::Module> M(CG->ReleaseModule());
CG->StartModule("incr_module_" + std::to_string(PTUs.size()),
M->getContext());
PTU->TheModule = std::move(M);
if (getCodeGen()) {
PTU->TheModule = GenModule();
assert(PTU->TheModule && "Failed to create initial PTU");
}
}
Expand Down Expand Up @@ -364,6 +365,19 @@ IncrementalParser::Parse(llvm::StringRef input) {
std::unique_ptr<llvm::Module> IncrementalParser::GenModule() {
static unsigned ID = 0;
if (CodeGenerator *CG = getCodeGen()) {
// Clang's CodeGen is designed to work with a single llvm::Module. In many
// cases for convenience various CodeGen parts have a reference to the
// llvm::Module (TheModule or Module) which does not change when a new
// module is pushed. However, the execution engine wants to take ownership
// of the module which does not map well to CodeGen's design. To work this
// around we created an empty module to make CodeGen happy. We should make
// sure it always stays empty.
assert((!CachedInCodeGenModule ||
(CachedInCodeGenModule->empty() &&
CachedInCodeGenModule->global_empty() &&
CachedInCodeGenModule->alias_empty() &&
CachedInCodeGenModule->ifunc_empty())) &&
"CodeGen wrote to a readonly module");
std::unique_ptr<llvm::Module> M(CG->ReleaseModule());
CG->StartModule("incr_module_" + std::to_string(ID++), M->getContext());
return M;
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/Interpreter/IncrementalParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <memory>
namespace llvm {
class LLVMContext;
class Module;
} // namespace llvm

namespace clang {
Expand Down Expand Up @@ -57,6 +58,10 @@ class IncrementalParser {
/// of code.
std::list<PartialTranslationUnit> PTUs;

/// When CodeGen is created the first llvm::Module gets cached in many places
/// and we must keep it alive.
std::unique_ptr<llvm::Module> CachedInCodeGenModule;

IncrementalParser();

public:
Expand Down
36 changes: 30 additions & 6 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3507,11 +3507,15 @@ bool Sema::ParseSVEImmChecks(
static ArmStreamingType getArmStreamingFnType(const FunctionDecl *FD) {
if (FD->hasAttr<ArmLocallyStreamingAttr>())
return ArmStreaming;
if (const auto *T = FD->getType()->getAs<FunctionProtoType>()) {
if (T->getAArch64SMEAttributes() & FunctionType::SME_PStateSMEnabledMask)
return ArmStreaming;
if (T->getAArch64SMEAttributes() & FunctionType::SME_PStateSMCompatibleMask)
return ArmStreamingCompatible;
if (const Type *Ty = FD->getType().getTypePtrOrNull()) {
if (const auto *FPT = Ty->getAs<FunctionProtoType>()) {
if (FPT->getAArch64SMEAttributes() &
FunctionType::SME_PStateSMEnabledMask)
return ArmStreaming;
if (FPT->getAArch64SMEAttributes() &
FunctionType::SME_PStateSMCompatibleMask)
return ArmStreamingCompatible;
}
}
return ArmNonStreaming;
}
Expand Down Expand Up @@ -7949,6 +7953,7 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
// For variadic functions, we may have more args than parameters.
// For some K&R functions, we may have less args than parameters.
const auto N = std::min<unsigned>(Proto->getNumParams(), Args.size());
bool AnyScalableArgsOrRet = Proto->getReturnType()->isSizelessVectorType();
for (unsigned ArgIdx = 0; ArgIdx < N; ++ArgIdx) {
// Args[ArgIdx] can be null in malformed code.
if (const Expr *Arg = Args[ArgIdx]) {
Expand All @@ -7962,6 +7967,8 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
checkAIXMemberAlignment((Arg->getExprLoc()), Arg);

QualType ParamTy = Proto->getParamType(ArgIdx);
if (ParamTy->isSizelessVectorType())
AnyScalableArgsOrRet = true;
QualType ArgTy = Arg->getType();
CheckArgAlignment(Arg->getExprLoc(), FDecl, std::to_string(ArgIdx + 1),
ArgTy, ParamTy);
Expand All @@ -7982,6 +7989,23 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
}
}

// If the call requires a streaming-mode change and has scalable vector
// arguments or return values, then warn the user that the streaming and
// non-streaming vector lengths may be different.
const auto *CallerFD = dyn_cast<FunctionDecl>(CurContext);
if (CallerFD && (!FD || !FD->getBuiltinID()) && AnyScalableArgsOrRet) {
bool IsCalleeStreaming =
ExtInfo.AArch64SMEAttributes & FunctionType::SME_PStateSMEnabledMask;
bool IsCalleeStreamingCompatible =
ExtInfo.AArch64SMEAttributes &
FunctionType::SME_PStateSMCompatibleMask;
ArmStreamingType CallerFnType = getArmStreamingFnType(CallerFD);
if (!IsCalleeStreamingCompatible &&
(CallerFnType == ArmStreamingCompatible ||
((CallerFnType == ArmStreaming) ^ IsCalleeStreaming)))
Diag(Loc, diag::warn_sme_streaming_pass_return_vl_to_non_streaming);
}

FunctionType::ArmStateValue CalleeArmZAState =
FunctionType::getArmZAState(ExtInfo.AArch64SMEAttributes);
FunctionType::ArmStateValue CalleeArmZT0State =
Expand All @@ -7990,7 +8014,7 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
CalleeArmZT0State != FunctionType::ARM_None) {
bool CallerHasZAState = false;
bool CallerHasZT0State = false;
if (const auto *CallerFD = dyn_cast<FunctionDecl>(CurContext)) {
if (CallerFD) {
auto *Attr = CallerFD->getAttr<ArmNewAttr>();
if (Attr && Attr->isNewZA())
CallerHasZAState = true;
Expand Down
7 changes: 2 additions & 5 deletions clang/lib/Sema/SemaCoroutine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -817,13 +817,10 @@ ExprResult Sema::BuildOperatorCoawaitLookupExpr(Scope *S, SourceLocation Loc) {

assert(!Operators.isAmbiguous() && "Operator lookup cannot be ambiguous");
const auto &Functions = Operators.asUnresolvedSet();
bool IsOverloaded =
Functions.size() > 1 ||
(Functions.size() == 1 && isa<FunctionTemplateDecl>(*Functions.begin()));
Expr *CoawaitOp = UnresolvedLookupExpr::Create(
Context, /*NamingClass*/ nullptr, NestedNameSpecifierLoc(),
DeclarationNameInfo(OpName, Loc), /*RequiresADL*/ true, IsOverloaded,
Functions.begin(), Functions.end());
DeclarationNameInfo(OpName, Loc), /*RequiresADL*/ true, Functions.begin(),
Functions.end(), /*KnownDependent=*/false);
assert(CoawaitOp);
return CoawaitOp;
}
Expand Down
16 changes: 13 additions & 3 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1240,8 +1240,8 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS,
Result.suppressDiagnostics();
return NameClassification::OverloadSet(UnresolvedLookupExpr::Create(
Context, Result.getNamingClass(), SS.getWithLocInContext(Context),
Result.getLookupNameInfo(), ADL, Result.isOverloadedResult(),
Result.begin(), Result.end()));
Result.getLookupNameInfo(), ADL, Result.begin(), Result.end(),
/*KnownDependent=*/false));
}

ExprResult
Expand Down Expand Up @@ -12408,12 +12408,22 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
}

// Check if the function definition uses any AArch64 SME features without
// having the '+sme' feature enabled.
// having the '+sme' feature enabled and warn user if sme locally streaming
// function returns or uses arguments with VL-based types.
if (DeclIsDefn) {
const auto *Attr = NewFD->getAttr<ArmNewAttr>();
bool UsesSM = NewFD->hasAttr<ArmLocallyStreamingAttr>();
bool UsesZA = Attr && Attr->isNewZA();
bool UsesZT0 = Attr && Attr->isNewZT0();

if (NewFD->hasAttr<ArmLocallyStreamingAttr>()) {
if (NewFD->getReturnType()->isSizelessVectorType() ||
llvm::any_of(NewFD->parameters(), [](ParmVarDecl *P) {
return P->getOriginalType()->isSizelessVectorType();
}))
Diag(NewFD->getLocation(),
diag::warn_sme_locally_streaming_has_vl_args_returns);
}
if (const auto *FPT = NewFD->getType()->getAs<FunctionProtoType>()) {
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
UsesSM |=
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1302,7 +1302,7 @@ static bool checkTupleLikeDecomposition(Sema &S,
// in the associated namespaces.
Expr *Get = UnresolvedLookupExpr::Create(
S.Context, nullptr, NestedNameSpecifierLoc(), SourceLocation(),
DeclarationNameInfo(GetDN, Loc), /*RequiresADL*/ true, &Args,
DeclarationNameInfo(GetDN, Loc), /*RequiresADL=*/true, &Args,
UnresolvedSetIterator(), UnresolvedSetIterator(),
/*KnownDependent=*/false);

Expand Down
33 changes: 7 additions & 26 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2918,26 +2918,9 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
// to get this right here so that we don't end up making a
// spuriously dependent expression if we're inside a dependent
// instance method.
if (getLangOpts().CPlusPlus && !R.empty() &&
(*R.begin())->isCXXClassMember()) {
bool MightBeImplicitMember;
if (!IsAddressOfOperand)
MightBeImplicitMember = true;
else if (!SS.isEmpty())
MightBeImplicitMember = false;
else if (R.isOverloadedResult())
MightBeImplicitMember = false;
else if (R.isUnresolvableResult())
MightBeImplicitMember = true;
else
MightBeImplicitMember = isa<FieldDecl>(R.getFoundDecl()) ||
isa<IndirectFieldDecl>(R.getFoundDecl()) ||
isa<MSPropertyDecl>(R.getFoundDecl());

if (MightBeImplicitMember)
return BuildPossibleImplicitMemberExpr(SS, TemplateKWLoc,
R, TemplateArgs, S);
}
if (isPotentialImplicitMemberAccess(SS, R, IsAddressOfOperand))
return BuildPossibleImplicitMemberExpr(SS, TemplateKWLoc, R, TemplateArgs,
S);

if (TemplateArgs || TemplateKWLoc.isValid()) {

Expand Down Expand Up @@ -3471,12 +3454,10 @@ ExprResult Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
// we've picked a target.
R.suppressDiagnostics();

UnresolvedLookupExpr *ULE
= UnresolvedLookupExpr::Create(Context, R.getNamingClass(),
SS.getWithLocInContext(Context),
R.getLookupNameInfo(),
NeedsADL, R.isOverloadedResult(),
R.begin(), R.end());
UnresolvedLookupExpr *ULE = UnresolvedLookupExpr::Create(
Context, R.getNamingClass(), SS.getWithLocInContext(Context),
R.getLookupNameInfo(), NeedsADL, R.begin(), R.end(),
/*KnownDependent=*/false);

return ULE;
}
Expand Down
61 changes: 32 additions & 29 deletions clang/lib/Sema/SemaExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1416,26 +1416,42 @@ bool Sema::CheckCXXThisCapture(SourceLocation Loc, const bool Explicit,
}

ExprResult Sema::ActOnCXXThis(SourceLocation Loc) {
/// C++ 9.3.2: In the body of a non-static member function, the keyword this
/// is a non-lvalue expression whose value is the address of the object for
/// which the function is called.
// C++20 [expr.prim.this]p1:
// The keyword this names a pointer to the object for which an
// implicit object member function is invoked or a non-static
// data member's initializer is evaluated.
QualType ThisTy = getCurrentThisType();

if (ThisTy.isNull()) {
DeclContext *DC = getFunctionLevelDeclContext();
if (CheckCXXThisType(Loc, ThisTy))
return ExprError();

if (const auto *Method = dyn_cast<CXXMethodDecl>(DC);
Method && Method->isExplicitObjectMemberFunction()) {
return Diag(Loc, diag::err_invalid_this_use) << 1;
}
return BuildCXXThisExpr(Loc, ThisTy, /*IsImplicit=*/false);
}

if (isLambdaCallWithExplicitObjectParameter(CurContext))
return Diag(Loc, diag::err_invalid_this_use) << 1;
bool Sema::CheckCXXThisType(SourceLocation Loc, QualType Type) {
if (!Type.isNull())
return false;

return Diag(Loc, diag::err_invalid_this_use) << 0;
// C++20 [expr.prim.this]p3:
// If a declaration declares a member function or member function template
// of a class X, the expression this is a prvalue of type
// "pointer to cv-qualifier-seq X" wherever X is the current class between
// the optional cv-qualifier-seq and the end of the function-definition,
// member-declarator, or declarator. It shall not appear within the
// declaration of either a static member function or an explicit object
// member function of the current class (although its type and value
// category are defined within such member functions as they are within
// an implicit object member function).
DeclContext *DC = getFunctionLevelDeclContext();
if (const auto *Method = dyn_cast<CXXMethodDecl>(DC);
Method && Method->isExplicitObjectMemberFunction()) {
Diag(Loc, diag::err_invalid_this_use) << 1;
} else if (isLambdaCallWithExplicitObjectParameter(CurContext)) {
Diag(Loc, diag::err_invalid_this_use) << 1;
} else {
Diag(Loc, diag::err_invalid_this_use) << 0;
}

return BuildCXXThisExpr(Loc, ThisTy, /*IsImplicit=*/false);
return true;
}

Expr *Sema::BuildCXXThisExpr(SourceLocation Loc, QualType Type,
Expand Down Expand Up @@ -8644,21 +8660,8 @@ static ExprResult attemptRecovery(Sema &SemaRef,

// Detect and handle the case where the decl might be an implicit
// member.
bool MightBeImplicitMember;
if (!Consumer.isAddressOfOperand())
MightBeImplicitMember = true;
else if (!NewSS.isEmpty())
MightBeImplicitMember = false;
else if (R.isOverloadedResult())
MightBeImplicitMember = false;
else if (R.isUnresolvableResult())
MightBeImplicitMember = true;
else
MightBeImplicitMember = isa<FieldDecl>(ND) ||
isa<IndirectFieldDecl>(ND) ||
isa<MSPropertyDecl>(ND);

if (MightBeImplicitMember)
if (SemaRef.isPotentialImplicitMemberAccess(
NewSS, R, Consumer.isAddressOfOperand()))
return SemaRef.BuildPossibleImplicitMemberExpr(
NewSS, /*TemplateKWLoc*/ SourceLocation(), R,
/*TemplateArgs*/ nullptr, /*S*/ nullptr);
Expand Down
72 changes: 57 additions & 15 deletions clang/lib/Sema/SemaExprMember.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ enum IMAKind {
/// The reference is a contextually-permitted abstract member reference.
IMA_Abstract,

/// Whether the context is static is dependent on the enclosing template (i.e.
/// in a dependent class scope explicit specialization).
IMA_Dependent,

/// The reference may be to an unresolved using declaration and the
/// context is not an instance method.
IMA_Unresolved_StaticOrExplicitContext,
Expand Down Expand Up @@ -92,14 +96,25 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,

DeclContext *DC = SemaRef.getFunctionLevelDeclContext();

bool isStaticOrExplicitContext =
SemaRef.CXXThisTypeOverride.isNull() &&
(!isa<CXXMethodDecl>(DC) || cast<CXXMethodDecl>(DC)->isStatic() ||
cast<CXXMethodDecl>(DC)->isExplicitObjectMemberFunction());
bool couldInstantiateToStatic = false;
bool isStaticOrExplicitContext = SemaRef.CXXThisTypeOverride.isNull();

if (R.isUnresolvableResult())
if (auto *MD = dyn_cast<CXXMethodDecl>(DC)) {
if (MD->isImplicitObjectMemberFunction()) {
isStaticOrExplicitContext = false;
// A dependent class scope function template explicit specialization
// that is neither declared 'static' nor with an explicit object
// parameter could instantiate to a static or non-static member function.
couldInstantiateToStatic = MD->getDependentSpecializationInfo();
}
}

if (R.isUnresolvableResult()) {
if (couldInstantiateToStatic)
return IMA_Dependent;
return isStaticOrExplicitContext ? IMA_Unresolved_StaticOrExplicitContext
: IMA_Unresolved;
}

// Collect all the declaring classes of instance members we find.
bool hasNonInstance = false;
Expand All @@ -124,6 +139,9 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
if (Classes.empty())
return IMA_Static;

if (couldInstantiateToStatic)
return IMA_Dependent;

// C++11 [expr.prim.general]p12:
// An id-expression that denotes a non-static data member or non-static
// member function of a class can only be used:
Expand Down Expand Up @@ -264,21 +282,37 @@ static void diagnoseInstanceReference(Sema &SemaRef,
}
}

bool Sema::isPotentialImplicitMemberAccess(const CXXScopeSpec &SS,
LookupResult &R,
bool IsAddressOfOperand) {
if (!getLangOpts().CPlusPlus)
return false;
else if (R.empty() || !R.begin()->isCXXClassMember())
return false;
else if (!IsAddressOfOperand)
return true;
else if (!SS.isEmpty())
return false;
else if (R.isOverloadedResult())
return false;
else if (R.isUnresolvableResult())
return true;
else
return isa<FieldDecl, IndirectFieldDecl, MSPropertyDecl>(R.getFoundDecl());
}

/// Builds an expression which might be an implicit member expression.
ExprResult Sema::BuildPossibleImplicitMemberExpr(
const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R,
const TemplateArgumentListInfo *TemplateArgs, const Scope *S,
UnresolvedLookupExpr *AsULE) {
switch (ClassifyImplicitMemberAccess(*this, R)) {
const TemplateArgumentListInfo *TemplateArgs, const Scope *S) {
switch (IMAKind Classification = ClassifyImplicitMemberAccess(*this, R)) {
case IMA_Instance:
return BuildImplicitMemberExpr(SS, TemplateKWLoc, R, TemplateArgs, true, S);

case IMA_Mixed:
case IMA_Mixed_Unrelated:
case IMA_Unresolved:
return BuildImplicitMemberExpr(SS, TemplateKWLoc, R, TemplateArgs, false,
S);

return BuildImplicitMemberExpr(
SS, TemplateKWLoc, R, TemplateArgs,
/*IsKnownInstance=*/Classification == IMA_Instance, S);
case IMA_Field_Uneval_Context:
Diag(R.getNameLoc(), diag::warn_cxx98_compat_non_static_member_use)
<< R.getLookupNameInfo().getName();
Expand All @@ -288,8 +322,16 @@ ExprResult Sema::BuildPossibleImplicitMemberExpr(
case IMA_Mixed_StaticOrExplicitContext:
case IMA_Unresolved_StaticOrExplicitContext:
if (TemplateArgs || TemplateKWLoc.isValid())
return BuildTemplateIdExpr(SS, TemplateKWLoc, R, false, TemplateArgs);
return AsULE ? AsULE : BuildDeclarationNameExpr(SS, R, false);
return BuildTemplateIdExpr(SS, TemplateKWLoc, R, /*RequiresADL=*/false,
TemplateArgs);
return BuildDeclarationNameExpr(SS, R, /*NeedsADL=*/false,
/*AcceptInvalidDecl=*/false);
case IMA_Dependent:
R.suppressDiagnostics();
return UnresolvedLookupExpr::Create(
Context, R.getNamingClass(), SS.getWithLocInContext(Context),
TemplateKWLoc, R.getLookupNameInfo(), /*RequiresADL=*/false,
TemplateArgs, R.begin(), R.end(), /*KnownDependent=*/true);

case IMA_Error_StaticOrExplicitContext:
case IMA_Error_Unrelated:
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Sema/SemaOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19354,7 +19354,7 @@ buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range,
return UnresolvedLookupExpr::Create(
SemaRef.Context, /*NamingClass=*/nullptr,
ReductionIdScopeSpec.getWithLocInContext(SemaRef.Context), ReductionId,
/*ADL=*/true, /*Overloaded=*/true, ResSet.begin(), ResSet.end());
/*ADL=*/true, ResSet.begin(), ResSet.end(), /*KnownDependent=*/false);
}
// Lookup inside the classes.
// C++ [over.match.oper]p3:
Expand Down Expand Up @@ -22220,7 +22220,7 @@ static ExprResult buildUserDefinedMapperRef(Sema &SemaRef, Scope *S,
return UnresolvedLookupExpr::Create(
SemaRef.Context, /*NamingClass=*/nullptr,
MapperIdScopeSpec.getWithLocInContext(SemaRef.Context), MapperId,
/*ADL=*/false, /*Overloaded=*/true, URS.begin(), URS.end());
/*ADL=*/false, URS.begin(), URS.end(), /*KnownDependent=*/false);
}
SourceLocation Loc = MapperId.getLoc();
// [OpenMP 5.0], 2.19.7.3 declare mapper Directive, Restrictions
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Sema/SemaOverload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14273,8 +14273,8 @@ ExprResult Sema::CreateUnresolvedLookupExpr(CXXRecordDecl *NamingClass,
const UnresolvedSetImpl &Fns,
bool PerformADL) {
return UnresolvedLookupExpr::Create(Context, NamingClass, NNSLoc, DNI,
PerformADL, IsOverloaded(Fns),
Fns.begin(), Fns.end());
PerformADL, Fns.begin(), Fns.end(),
/*KnownDependent=*/false);
}

ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl,
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Sema/SemaStmtAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const ParsedAttr &A,
SetHints(LoopHintAttr::Unroll, LoopHintAttr::Disable);
} else if (PragmaName == "unroll") {
// #pragma unroll N
if (ValueExpr) {
if (ValueExpr && !ValueExpr->isValueDependent()) {
llvm::APSInt ValueAPS;
ExprResult R = S.VerifyIntegerConstantExpression(ValueExpr, &ValueAPS);
assert(!R.isInvalid() && "unroll count value must be a valid value, it's "
Expand Down
27 changes: 14 additions & 13 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2962,19 +2962,6 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
Context.getCanonicalTemplateArgument(
Context.getInjectedTemplateArg(NewParam));
}
// Substitute new template parameters into requires-clause if present.
Expr *RequiresClause =
transformRequireClause(SemaRef, F, TemplateArgsForBuildingFPrime);
// FIXME: implement the is_deducible constraint per C++
// [over.match.class.deduct]p3.3:
// ... and a constraint that is satisfied if and only if the arguments
// of A are deducible (see below) from the return type.
auto *FPrimeTemplateParamList = TemplateParameterList::Create(
Context, AliasTemplate->getTemplateParameters()->getTemplateLoc(),
AliasTemplate->getTemplateParameters()->getLAngleLoc(),
FPrimeTemplateParams,
AliasTemplate->getTemplateParameters()->getRAngleLoc(),
/*RequiresClause=*/RequiresClause);

// To form a deduction guide f' from f, we leverage clang's instantiation
// mechanism, we construct a template argument list where the template
Expand Down Expand Up @@ -3020,6 +3007,20 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
F, TemplateArgListForBuildingFPrime, AliasTemplate->getLocation(),
Sema::CodeSynthesisContext::BuildingDeductionGuides)) {
auto *GG = cast<CXXDeductionGuideDecl>(FPrime);
// Substitute new template parameters into requires-clause if present.
Expr *RequiresClause =
transformRequireClause(SemaRef, F, TemplateArgsForBuildingFPrime);
// FIXME: implement the is_deducible constraint per C++
// [over.match.class.deduct]p3.3:
// ... and a constraint that is satisfied if and only if the arguments
// of A are deducible (see below) from the return type.
auto *FPrimeTemplateParamList = TemplateParameterList::Create(
Context, AliasTemplate->getTemplateParameters()->getTemplateLoc(),
AliasTemplate->getTemplateParameters()->getLAngleLoc(),
FPrimeTemplateParams,
AliasTemplate->getTemplateParameters()->getRAngleLoc(),
/*RequiresClause=*/RequiresClause);

buildDeductionGuide(SemaRef, AliasTemplate, FPrimeTemplateParamList,
GG->getCorrespondingConstructor(),
GG->getExplicitSpecifier(), GG->getTypeSourceInfo(),
Expand Down
5 changes: 1 addition & 4 deletions clang/lib/Sema/SemaTemplateInstantiate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2502,10 +2502,7 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB,
assert(Arg.getKind() == TemplateArgument::Type &&
"unexpected nontype template argument kind in template rewrite");
QualType NewT = Arg.getAsType();
assert(isa<TemplateTypeParmType>(NewT) &&
"type parm not rewritten to type parm");
auto NewTL = TLB.push<TemplateTypeParmTypeLoc>(NewT);
NewTL.setNameLoc(TL.getNameLoc());
TLB.pushTrivial(SemaRef.Context, NewT, TL.getNameLoc());
return NewT;
}

Expand Down
8 changes: 8 additions & 0 deletions clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5101,6 +5101,14 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
EnterExpressionEvaluationContext EvalContext(
*this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);

Qualifiers ThisTypeQuals;
CXXRecordDecl *ThisContext = nullptr;
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Function)) {
ThisContext = Method->getParent();
ThisTypeQuals = Method->getMethodQualifiers();
}
CXXThisScopeRAII ThisScope(*this, ThisContext, ThisTypeQuals);

// Introduce a new scope where local variable instantiations will be
// recorded, unless we're actually a member function within a local
// class, in which case we need to merge our results with the parent
Expand Down
8 changes: 5 additions & 3 deletions clang/lib/Sema/SemaTemplateVariadic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1085,9 +1085,11 @@ ExprResult Sema::ActOnPackIndexingExpr(Scope *S, Expr *PackExpression,
SourceLocation RSquareLoc) {
bool isParameterPack = ::isParameterPack(PackExpression);
if (!isParameterPack) {
CorrectDelayedTyposInExpr(IndexExpr);
Diag(PackExpression->getBeginLoc(), diag::err_expected_name_of_pack)
<< PackExpression;
if (!PackExpression->containsErrors()) {
CorrectDelayedTyposInExpr(IndexExpr);
Diag(PackExpression->getBeginLoc(), diag::err_expected_name_of_pack)
<< PackExpression;
}
return ExprError();
}
ExprResult Res =
Expand Down
86 changes: 49 additions & 37 deletions clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -796,6 +796,9 @@ class TreeTransform {
ParenExpr *PE, DependentScopeDeclRefExpr *DRE, bool IsAddressOfOperand,
TypeSourceInfo **RecoveryTSI);

ExprResult TransformUnresolvedLookupExpr(UnresolvedLookupExpr *E,
bool IsAddressOfOperand);

StmtResult TransformOMPExecutableDirective(OMPExecutableDirective *S);

// FIXME: We use LLVM_ATTRIBUTE_NOINLINE because inlining causes a ridiculous
Expand Down Expand Up @@ -3320,12 +3323,13 @@ class TreeTransform {

/// Build a new C++ "this" expression.
///
/// By default, builds a new "this" expression without performing any
/// semantic analysis. Subclasses may override this routine to provide
/// different behavior.
/// By default, performs semantic analysis to build a new "this" expression.
/// Subclasses may override this routine to provide different behavior.
ExprResult RebuildCXXThisExpr(SourceLocation ThisLoc,
QualType ThisType,
bool isImplicit) {
if (getSema().CheckCXXThisType(ThisLoc, ThisType))
return ExprError();
return getSema().BuildCXXThisExpr(ThisLoc, ThisType, isImplicit);
}

Expand Down Expand Up @@ -4759,8 +4763,6 @@ class TemplateArgumentLocInventIterator {
const TemplateArgumentLoc *operator->() const { return &Arg; }
};

TemplateArgumentLocInventIterator() { }

explicit TemplateArgumentLocInventIterator(TreeTransform<Derived> &Self,
InputIterator Iter)
: Self(Self), Iter(Iter) { }
Expand Down Expand Up @@ -10429,12 +10431,11 @@ TreeTransform<Derived>::TransformOMPReductionClause(OMPReductionClause *C) {
cast<NamedDecl>(getDerived().TransformDecl(E->getExprLoc(), D));
Decls.addDecl(InstD, InstD->getAccess());
}
UnresolvedReductions.push_back(
UnresolvedLookupExpr::Create(
UnresolvedReductions.push_back(UnresolvedLookupExpr::Create(
SemaRef.Context, /*NamingClass=*/nullptr,
ReductionIdScopeSpec.getWithLocInContext(SemaRef.Context),
NameInfo, /*ADL=*/true, ULE->isOverloaded(),
Decls.begin(), Decls.end()));
ReductionIdScopeSpec.getWithLocInContext(SemaRef.Context), NameInfo,
/*ADL=*/true, Decls.begin(), Decls.end(),
/*KnownDependent=*/false));
} else
UnresolvedReductions.push_back(nullptr);
}
Expand Down Expand Up @@ -10480,7 +10481,8 @@ OMPClause *TreeTransform<Derived>::TransformOMPTaskReductionClause(
UnresolvedReductions.push_back(UnresolvedLookupExpr::Create(
SemaRef.Context, /*NamingClass=*/nullptr,
ReductionIdScopeSpec.getWithLocInContext(SemaRef.Context), NameInfo,
/*ADL=*/true, ULE->isOverloaded(), Decls.begin(), Decls.end()));
/*ADL=*/true, Decls.begin(), Decls.end(),
/*KnownDependent=*/false));
} else
UnresolvedReductions.push_back(nullptr);
}
Expand Down Expand Up @@ -10525,7 +10527,8 @@ TreeTransform<Derived>::TransformOMPInReductionClause(OMPInReductionClause *C) {
UnresolvedReductions.push_back(UnresolvedLookupExpr::Create(
SemaRef.Context, /*NamingClass=*/nullptr,
ReductionIdScopeSpec.getWithLocInContext(SemaRef.Context), NameInfo,
/*ADL=*/true, ULE->isOverloaded(), Decls.begin(), Decls.end()));
/*ADL=*/true, Decls.begin(), Decls.end(),
/*KnownDependent=*/false));
} else
UnresolvedReductions.push_back(nullptr);
}
Expand Down Expand Up @@ -10706,8 +10709,8 @@ bool transformOMPMappableExprListClause(
UnresolvedMappers.push_back(UnresolvedLookupExpr::Create(
TT.getSema().Context, /*NamingClass=*/nullptr,
MapperIdScopeSpec.getWithLocInContext(TT.getSema().Context),
MapperIdInfo, /*ADL=*/true, ULE->isOverloaded(), Decls.begin(),
Decls.end()));
MapperIdInfo, /*ADL=*/true, Decls.begin(), Decls.end(),
/*KnownDependent=*/false));
} else {
UnresolvedMappers.push_back(nullptr);
}
Expand Down Expand Up @@ -11467,7 +11470,11 @@ template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformAddressOfOperand(Expr *E) {
if (DependentScopeDeclRefExpr *DRE = dyn_cast<DependentScopeDeclRefExpr>(E))
return getDerived().TransformDependentScopeDeclRefExpr(DRE, true, nullptr);
return getDerived().TransformDependentScopeDeclRefExpr(
DRE, /*IsAddressOfOperand=*/true, nullptr);
else if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(E))
return getDerived().TransformUnresolvedLookupExpr(
ULE, /*IsAddressOfOperand=*/true);
else
return getDerived().TransformExpr(E);
}
Expand Down Expand Up @@ -13174,10 +13181,16 @@ bool TreeTransform<Derived>::TransformOverloadExprDecls(OverloadExpr *Old,
return false;
}

template<typename Derived>
template <typename Derived>
ExprResult TreeTransform<Derived>::TransformUnresolvedLookupExpr(
UnresolvedLookupExpr *Old) {
return TransformUnresolvedLookupExpr(Old, /*IsAddressOfOperand=*/false);
}

template <typename Derived>
ExprResult
TreeTransform<Derived>::TransformUnresolvedLookupExpr(
UnresolvedLookupExpr *Old) {
TreeTransform<Derived>::TransformUnresolvedLookupExpr(UnresolvedLookupExpr *Old,
bool IsAddressOfOperand) {
LookupResult R(SemaRef, Old->getName(), Old->getNameLoc(),
Sema::LookupOrdinaryName);

Expand Down Expand Up @@ -13209,26 +13222,8 @@ TreeTransform<Derived>::TransformUnresolvedLookupExpr(
R.setNamingClass(NamingClass);
}

// Rebuild the template arguments, if any.
SourceLocation TemplateKWLoc = Old->getTemplateKeywordLoc();

// If we have neither explicit template arguments, nor the template keyword,
// it's a normal declaration name or member reference.
if (!Old->hasExplicitTemplateArgs() && !TemplateKWLoc.isValid()) {
NamedDecl *D = R.getAsSingle<NamedDecl>();
// In a C++11 unevaluated context, an UnresolvedLookupExpr might refer to an
// instance member. In other contexts, BuildPossibleImplicitMemberExpr will
// give a good diagnostic.
if (D && D->isCXXInstanceMember()) {
return SemaRef.BuildPossibleImplicitMemberExpr(SS, TemplateKWLoc, R,
/*TemplateArgs=*/nullptr,
/*Scope=*/nullptr);
}

return getDerived().RebuildDeclarationNameExpr(SS, R, Old->requiresADL());
}

// If we have template arguments, rebuild them, then rebuild the
// templateid expression.
TemplateArgumentListInfo TransArgs(Old->getLAngleLoc(), Old->getRAngleLoc());
if (Old->hasExplicitTemplateArgs() &&
getDerived().TransformTemplateArguments(Old->getTemplateArgs(),
Expand All @@ -13238,6 +13233,23 @@ TreeTransform<Derived>::TransformUnresolvedLookupExpr(
return ExprError();
}

// An UnresolvedLookupExpr can refer to a class member. This occurs e.g. when
// a non-static data member is named in an unevaluated operand, or when
// a member is named in a dependent class scope function template explicit
// specialization that is neither declared static nor with an explicit object
// parameter.
if (SemaRef.isPotentialImplicitMemberAccess(SS, R, IsAddressOfOperand))
return SemaRef.BuildPossibleImplicitMemberExpr(
SS, TemplateKWLoc, R,
Old->hasExplicitTemplateArgs() ? &TransArgs : nullptr,
/*S=*/nullptr);

// If we have neither explicit template arguments, nor the template keyword,
// it's a normal declaration name or member reference.
if (!Old->hasExplicitTemplateArgs() && !TemplateKWLoc.isValid())
return getDerived().RebuildDeclarationNameExpr(SS, R, Old->requiresADL());

// If we have template arguments, then rebuild the template-id expression.
return getDerived().RebuildTemplateIdExpr(SS, TemplateKWLoc, R,
Old->requiresADL(), &TransArgs);
}
Expand Down
1 change: 0 additions & 1 deletion clang/lib/Serialization/ASTReaderStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2096,7 +2096,6 @@ void ASTStmtReader::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E) {
void ASTStmtReader::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) {
VisitOverloadExpr(E);
E->UnresolvedLookupExprBits.RequiresADL = CurrentUnpackingBits->getNextBit();
E->UnresolvedLookupExprBits.Overloaded = CurrentUnpackingBits->getNextBit();
E->NamingClass = readDeclAs<CXXRecordDecl>();
}

Expand Down
6 changes: 3 additions & 3 deletions clang/lib/Serialization/ASTWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,9 @@ namespace {

std::optional<std::set<const FileEntry *>>
GetAffectingModuleMaps(const Preprocessor &PP, Module *RootModule) {
// Without implicit module map search, there's no good reason to know about
// any module maps that are not affecting.
if (!PP.getHeaderSearchInfo().getHeaderSearchOpts().ImplicitModuleMaps)
if (!PP.getHeaderSearchInfo()
.getHeaderSearchOpts()
.ModulesPruneNonAffectingModuleMaps)
return std::nullopt;

SmallVector<const Module *> ModulesToProcess{RootModule};
Expand Down
1 change: 0 additions & 1 deletion clang/lib/Serialization/ASTWriterStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2082,7 +2082,6 @@ void ASTStmtWriter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E) {
void ASTStmtWriter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) {
VisitOverloadExpr(E);
CurrentPackingBits.addBit(E->requiresADL());
CurrentPackingBits.addBit(E->isOverloaded());
Record.AddDeclRef(E->getNamingClass());
Code = serialization::EXPR_CXX_UNRESOLVED_LOOKUP;
}
Expand Down
18 changes: 9 additions & 9 deletions clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,23 +56,23 @@ class CastValueChecker : public Checker<check::DeadSymbols, eval::Call> {

private:
// These are known in the LLVM project. The pairs are in the following form:
// {{{namespace, call}, argument-count}, {callback, kind}}
// {{match-mode, {namespace, call}, argument-count}, {callback, kind}}
const CallDescriptionMap<std::pair<CastCheck, CallKind>> CDM = {
{{{"llvm", "cast"}, 1},
{{CDM::SimpleFunc, {"llvm", "cast"}, 1},
{&CastValueChecker::evalCast, CallKind::Function}},
{{{"llvm", "dyn_cast"}, 1},
{{CDM::SimpleFunc, {"llvm", "dyn_cast"}, 1},
{&CastValueChecker::evalDynCast, CallKind::Function}},
{{{"llvm", "cast_or_null"}, 1},
{{CDM::SimpleFunc, {"llvm", "cast_or_null"}, 1},
{&CastValueChecker::evalCastOrNull, CallKind::Function}},
{{{"llvm", "dyn_cast_or_null"}, 1},
{{CDM::SimpleFunc, {"llvm", "dyn_cast_or_null"}, 1},
{&CastValueChecker::evalDynCastOrNull, CallKind::Function}},
{{{"clang", "castAs"}, 0},
{{CDM::CXXMethod, {"clang", "castAs"}, 0},
{&CastValueChecker::evalCastAs, CallKind::Method}},
{{{"clang", "getAs"}, 0},
{{CDM::CXXMethod, {"clang", "getAs"}, 0},
{&CastValueChecker::evalGetAs, CallKind::Method}},
{{{"llvm", "isa"}, 1},
{{CDM::SimpleFunc, {"llvm", "isa"}, 1},
{&CastValueChecker::evalIsa, CallKind::InstanceOf}},
{{{"llvm", "isa_and_nonnull"}, 1},
{{CDM::SimpleFunc, {"llvm", "isa_and_nonnull"}, 1},
{&CastValueChecker::evalIsaAndNonNull, CallKind::InstanceOf}}};

void evalCast(const CallEvent &Call, DefinedOrUnknownSVal DV,
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ class ChrootChecker : public Checker<eval::Call, check::PreCall> {
// This bug refers to possibly break out of a chroot() jail.
const BugType BT_BreakJail{this, "Break out of jail"};

const CallDescription Chroot{{"chroot"}, 1}, Chdir{{"chdir"}, 1};
const CallDescription Chroot{CDM::CLibrary, {"chroot"}, 1},
Chdir{CDM::CLibrary, {"chdir"}, 1};

public:
ChrootChecker() {}
Expand Down
12 changes: 7 additions & 5 deletions clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,15 @@ class ErrnoTesterChecker : public Checker<eval::Call> {

using EvalFn = std::function<void(CheckerContext &, const CallEvent &)>;
const CallDescriptionMap<EvalFn> TestCalls{
{{{"ErrnoTesterChecker_setErrno"}, 1}, &ErrnoTesterChecker::evalSetErrno},
{{{"ErrnoTesterChecker_getErrno"}, 0}, &ErrnoTesterChecker::evalGetErrno},
{{{"ErrnoTesterChecker_setErrnoIfError"}, 0},
{{CDM::SimpleFunc, {"ErrnoTesterChecker_setErrno"}, 1},
&ErrnoTesterChecker::evalSetErrno},
{{CDM::SimpleFunc, {"ErrnoTesterChecker_getErrno"}, 0},
&ErrnoTesterChecker::evalGetErrno},
{{CDM::SimpleFunc, {"ErrnoTesterChecker_setErrnoIfError"}, 0},
&ErrnoTesterChecker::evalSetErrnoIfError},
{{{"ErrnoTesterChecker_setErrnoIfErrorRange"}, 0},
{{CDM::SimpleFunc, {"ErrnoTesterChecker_setErrnoIfErrorRange"}, 0},
&ErrnoTesterChecker::evalSetErrnoIfErrorRange},
{{{"ErrnoTesterChecker_setErrnoCheckState"}, 0},
{{CDM::SimpleFunc, {"ErrnoTesterChecker_setErrnoCheckState"}, 0},
&ErrnoTesterChecker::evalSetErrnoCheckState}};
};

Expand Down
5 changes: 2 additions & 3 deletions clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,15 @@ using namespace ento;

namespace {
class MmapWriteExecChecker : public Checker<check::PreCall> {
CallDescription MmapFn;
CallDescription MprotectFn;
CallDescription MmapFn{CDM::CLibrary, {"mmap"}, 6};
CallDescription MprotectFn{CDM::CLibrary, {"mprotect"}, 3};
static int ProtWrite;
static int ProtExec;
static int ProtRead;
const BugType BT{this, "W^X check fails, Write Exec prot flags set",
"Security"};

public:
MmapWriteExecChecker() : MmapFn({"mmap"}, 6), MprotectFn({"mprotect"}, 3) {}
void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
int ProtExecOv;
int ProtReadOv;
Expand Down
10 changes: 6 additions & 4 deletions clang/lib/StaticAnalyzer/Checkers/StdVariantChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,11 @@ static llvm::StringRef indefiniteArticleBasedOnVowel(char a) {

class StdVariantChecker : public Checker<eval::Call, check::RegionChanges> {
// Call descriptors to find relevant calls
CallDescription VariantConstructor{{"std", "variant", "variant"}};
CallDescription VariantAssignmentOperator{{"std", "variant", "operator="}};
CallDescription StdGet{{"std", "get"}, 1, 1};
CallDescription VariantConstructor{CDM::CXXMethod,
{"std", "variant", "variant"}};
CallDescription VariantAssignmentOperator{CDM::CXXMethod,
{"std", "variant", "operator="}};
CallDescription StdGet{CDM::SimpleFunc, {"std", "get"}, 1, 1};

BugType BadVariantType{this, "BadVariantType", "BadVariantType"};

Expand Down Expand Up @@ -295,4 +297,4 @@ bool clang::ento::shouldRegisterStdVariantChecker(

void clang::ento::registerStdVariantChecker(clang::ento::CheckerManager &mgr) {
mgr.registerChecker<StdVariantChecker>();
}
}
2 changes: 1 addition & 1 deletion clang/lib/StaticAnalyzer/Checkers/StringChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class StringChecker : public Checker<check::PreCall> {
mutable const FunctionDecl *StringConstCharPtrCtor = nullptr;
mutable CanQualType SizeTypeTy;
const CallDescription TwoParamStdStringCtor = {
{"std", "basic_string", "basic_string"}, 2, 2};
CDM::CXXMethod, {"std", "basic_string", "basic_string"}, 2, 2};

bool isCharToStringCtor(const CallEvent &Call, const ASTContext &ACtx) const;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class PutenvWithAutoChecker : public Checker<check::PostCall> {
private:
BugType BT{this, "'putenv' function should not be called with auto variables",
categories::SecurityError};
const CallDescription Putenv{{"putenv"}, 1};
const CallDescription Putenv{CDM::CLibrary, {"putenv"}, 1};

public:
void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
Expand Down
7 changes: 4 additions & 3 deletions clang/lib/StaticAnalyzer/Core/RegionStore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2358,11 +2358,12 @@ StoreRef RegionStoreManager::killBinding(Store ST, Loc L) {

RegionBindingsRef
RegionStoreManager::bind(RegionBindingsConstRef B, Loc L, SVal V) {
if (L.getAs<loc::ConcreteInt>())
// We only care about region locations.
auto MemRegVal = L.getAs<loc::MemRegionVal>();
if (!MemRegVal)
return B;

// If we get here, the location should be a region.
const MemRegion *R = L.castAs<loc::MemRegionVal>().getRegion();
const MemRegion *R = MemRegVal->getRegion();

// Check if the region is a struct region.
if (const TypedValueRegion* TR = dyn_cast<TypedValueRegion>(R)) {
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,11 @@ makeCommonInvocationForModuleBuild(CompilerInvocation CI) {
CI.resetNonModularOptions();
CI.clearImplicitModuleBuildOptions();

// The scanner takes care to avoid passing non-affecting module maps to the
// explicit compiles. No need to do extra work just to find out there are no
// module map files to prune.
CI.getHeaderSearchOpts().ModulesPruneNonAffectingModuleMaps = false;

// Remove options incompatible with explicit module build or are likely to
// differ between identical modules discovered from different translation
// units.
Expand Down
6 changes: 6 additions & 0 deletions clang/test/AST/Interp/builtin-functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -633,3 +633,9 @@ void test7(void) {
X = CFSTR("foo", "bar"); // both-error {{too many arguments to function call}}
#endif
}

/// The actual value on my machine is 22, but I have a feeling this will be different
/// on other targets, so just checking for != 0 here. Light testing is fine since
/// the actual implementation uses analyze_os_log::computeOSLogBufferLayout(), which
/// is tested elsewhere.
static_assert(__builtin_os_log_format_buffer_size("%{mask.xyz}s", "abc") != 0, "");
6 changes: 6 additions & 0 deletions clang/test/AST/Interp/c.c
Original file line number Diff line number Diff line change
Expand Up @@ -257,3 +257,9 @@ int Y __attribute__((annotate(
42,
(struct TestStruct) { .a = 1, .b = 2 }
)));

#ifdef __SIZEOF_INT128__
const int *p = &b;
const __int128 K = (__int128)(int*)0;
const unsigned __int128 KU = (unsigned __int128)(int*)0;
#endif
12 changes: 12 additions & 0 deletions clang/test/AST/Interp/literals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1209,4 +1209,16 @@ constexpr int externvar1() { // both-error {{never produces a constant expressio
namespace Extern {
constexpr extern char Oops = 1;
static_assert(Oops == 1, "");

#if __cplusplus >= 201402L
struct NonLiteral {
NonLiteral() {}
};
NonLiteral nl;
constexpr NonLiteral &ExternNonLiteralVarDecl() {
extern NonLiteral nl;
return nl;
}
static_assert(&ExternNonLiteralVarDecl() == &nl, "");
#endif
}
20 changes: 20 additions & 0 deletions clang/test/AST/Interp/vectors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ static_assert(A[1] == 2, ""); // ref-error {{not an integral constant expression
static_assert(A[2] == 3, ""); // ref-error {{not an integral constant expression}}
static_assert(A[3] == 4, ""); // ref-error {{not an integral constant expression}}


/// FIXME: It would be nice if the note said 'vector' instead of 'array'.
static_assert(A[12] == 4, ""); // ref-error {{not an integral constant expression}} \
// expected-error {{not an integral constant expression}} \
// expected-note {{cannot refer to element 12 of array of 4 elements in a constant expression}}


/// VectorSplat casts
typedef __attribute__(( ext_vector_type(4) )) float float4;
constexpr float4 vec4_0 = (float4)0.5f;
Expand All @@ -18,6 +25,19 @@ static_assert(vec4_0[3] == 0.5, ""); // ref-error {{not an integral constant exp
constexpr int vec4_0_discarded = ((float4)12.0f, 0);


/// ImplicitValueInitExpr of vector type
constexpr float4 arr4[2] = {
{1,2,3,4},
};
static_assert(arr4[0][0] == 1, ""); // ref-error {{not an integral constant expression}}
static_assert(arr4[0][1] == 2, ""); // ref-error {{not an integral constant expression}}
static_assert(arr4[0][2] == 3, ""); // ref-error {{not an integral constant expression}}
static_assert(arr4[0][3] == 4, ""); // ref-error {{not an integral constant expression}}
static_assert(arr4[1][0] == 0, ""); // ref-error {{not an integral constant expression}}
static_assert(arr4[1][0] == 0, ""); // ref-error {{not an integral constant expression}}
static_assert(arr4[1][0] == 0, ""); // ref-error {{not an integral constant expression}}
static_assert(arr4[1][0] == 0, ""); // ref-error {{not an integral constant expression}}


/// From constant-expression-cxx11.cpp
namespace Vector {
Expand Down
40 changes: 38 additions & 2 deletions clang/test/AST/ast-dump-template-json-win32-mangler-crash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2725,7 +2725,25 @@ int main()
// CHECK-NEXT: "type": {
// CHECK-NEXT: "qualType": "bool"
// CHECK-NEXT: },
// CHECK-NEXT: "valueCategory": "prvalue"
// CHECK-NEXT: "valueCategory": "prvalue",
// CHECK-NEXT: "inner": [
// CHECK-NEXT: {
// CHECK-NEXT: "id": "0x{{.*}}",
// CHECK-NEXT: "kind": "TemplateTypeParmType",
// CHECK-NEXT: "type": {
// CHECK-NEXT: "qualType": "_Ty"
// CHECK-NEXT: },
// CHECK-NEXT: "isDependent": true,
// CHECK-NEXT: "isInstantiationDependent": true,
// CHECK-NEXT: "depth": 0,
// CHECK-NEXT: "index": 0,
// CHECK-NEXT: "decl": {
// CHECK-NEXT: "id": "0x{{.*}}",
// CHECK-NEXT: "kind": "TemplateTypeParmDecl",
// CHECK-NEXT: "name": "_Ty"
// CHECK-NEXT: }
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK-NEXT: }
Expand Down Expand Up @@ -3003,7 +3021,25 @@ int main()
// CHECK-NEXT: "type": {
// CHECK-NEXT: "qualType": "bool"
// CHECK-NEXT: },
// CHECK-NEXT: "valueCategory": "prvalue"
// CHECK-NEXT: "valueCategory": "prvalue",
// CHECK-NEXT: "inner": [
// CHECK-NEXT: {
// CHECK-NEXT: "id": "0x{{.*}}",
// CHECK-NEXT: "kind": "TemplateTypeParmType",
// CHECK-NEXT: "type": {
// CHECK-NEXT: "qualType": "_Ty"
// CHECK-NEXT: },
// CHECK-NEXT: "isDependent": true,
// CHECK-NEXT: "isInstantiationDependent": true,
// CHECK-NEXT: "depth": 0,
// CHECK-NEXT: "index": 0,
// CHECK-NEXT: "decl": {
// CHECK-NEXT: "id": "0x{{.*}}",
// CHECK-NEXT: "kind": "TemplateTypeParmDecl",
// CHECK-NEXT: "name": "_Ty"
// CHECK-NEXT: }
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK-NEXT: }
Expand Down
9 changes: 9 additions & 0 deletions clang/test/AST/ast-dump-traits.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,19 @@ void test_unary_expr_or_type_trait() {
// CHECK-NEXT: | | `-EnumDecl {{.*}} <col:3, col:11> col:8{{( imported)?}} referenced E
// CHECK-NEXT: | |-CStyleCastExpr {{.*}} <line:13:3, col:21> 'void' <ToVoid>
// CHECK-NEXT: | | `-TypeTraitExpr {{.*}} <col:10, col:21> 'bool' __is_enum
// CHECK-NEXT: | | `-ElaboratedType {{.*}} 'E' sugar
// CHECK-NEXT: | | `-EnumType {{.*}} 'E'
// CHECK-NEXT: | | `-Enum {{.*}} 'E'
// CHECK-NEXT: | |-CStyleCastExpr {{.*}} <line:15:3, col:30> 'void' <ToVoid>
// CHECK-NEXT: | | `-TypeTraitExpr {{.*}} <col:10, col:30> 'bool' __is_same
// CHECK-NEXT: | | |-BuiltinType {{.*}} 'int'
// CHECK-NEXT: | | `-BuiltinType {{.*}} 'float'
// CHECK-NEXT: | `-CStyleCastExpr {{.*}} <line:17:3, col:47> 'void' <ToVoid>
// CHECK-NEXT: | `-TypeTraitExpr {{.*}} <col:10, col:47> 'bool' __is_constructible
// CHECK-NEXT: |-BuiltinType {{.*}} 'int'
// CHECK-NEXT: |-BuiltinType {{.*}} 'int'
// CHECK-NEXT: |-BuiltinType {{.*}} 'int'
// CHECK-NEXT: `-BuiltinType {{.*}} 'int'
// CHECK-NEXT: |-FunctionDecl {{.*}} <line:20:1, line:23:1> line:20:6{{( imported)?}} test_array_type_trait 'void ()'
// CHECK-NEXT: | `-CompoundStmt {{.*}} <col:30, line:23:1>
// CHECK-NEXT: | `-CStyleCastExpr {{.*}} <line:22:3, col:34> 'void' <ToVoid>
Expand Down
14 changes: 14 additions & 0 deletions clang/test/Analysis/gh-issue-89185.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify %s

void clang_analyzer_dump(char);
void clang_analyzer_dump_ptr(char*);

// https://github.com/llvm/llvm-project/issues/89185
void binding_to_label_loc() {
char *b = &&MyLabel;
MyLabel:
*b = 0; // no-crash
clang_analyzer_dump_ptr(b); // expected-warning {{&&MyLabel}}
clang_analyzer_dump(*b); // expected-warning {{Unknown}}
// FIXME: We should never reach here, as storing to a label is invalid.
}
3 changes: 3 additions & 0 deletions clang/test/ClangScanDeps/modules-full.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
// CHECK-NEXT: "command-line": [
// CHECK-NEXT: "-cc1"
// CHECK: "-emit-module"
// CHECK: "-fno-modules-prune-non-affecting-module-map-files"
// CHECK: "-fmodule-file={{.*}}[[PREFIX]]/module-cache{{(_clangcl)?}}/[[HASH_H2_DINCLUDE]]/header2-{{[A-Z0-9]+}}.pcm"
// CHECK-NOT: "-fimplicit-module-maps"
// CHECK: "-fmodule-name=header1"
Expand All @@ -51,6 +52,7 @@
// CHECK-NEXT: "command-line": [
// CHECK-NEXT: "-cc1",
// CHECK: "-emit-module",
// CHECK: "-fno-modules-prune-non-affecting-module-map-files"
// CHECK-NOT: "-fimplicit-module-maps",
// CHECK: "-fmodule-name=header1",
// CHECK: "-fno-implicit-modules",
Expand All @@ -68,6 +70,7 @@
// CHECK-NEXT: "command-line": [
// CHECK-NEXT: "-cc1",
// CHECK: "-emit-module",
// CHECK: "-fno-modules-prune-non-affecting-module-map-files"
// CHECK: "-fmodule-name=header2",
// CHECK-NOT: "-fimplicit-module-maps",
// CHECK: "-fno-implicit-modules",
Expand Down
2 changes: 1 addition & 1 deletion clang/test/CodeGen/PowerPC/builtins-ppc-htm.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// REQUIRES: powerpc-registered-target
// RUN: %clang_cc1 -target-feature +altivec -target-feature +htm -triple powerpc64-unknown-unknown -emit-llvm %s -o - | FileCheck %s
// RUN: not %clang_cc1 -target-feature +altivec -target-feature -htm -triple powerpc64-unknown-unknown -emit-llvm %s 2>&1 | FileCheck %s --check-prefix=ERROR
// RUN: not %clang_cc1 -target-feature +altivec -target-feature -htm -triple powerpc64-unknown-unknown -emit-llvm-only %s 2>&1 | FileCheck %s --check-prefix=ERROR

void test1(long int *r, int code, long int *a, long int *b) {
// CHECK-LABEL: define{{.*}} void @test1
Expand Down
12 changes: 6 additions & 6 deletions clang/test/CodeGen/PowerPC/builtins-ppc-vec-ins-error.c
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
// REQUIRES: powerpc-registered-target

// RUN: %clang_cc1 -flax-vector-conversions=none -target-feature +vsx -target-cpu pwr10 -fsyntax-only \
// RUN: -triple powerpc64le-unknown-unknown -emit-llvm -ferror-limit 10 %s -verify -D __TEST_ELT_SI
// RUN: -triple powerpc64le-unknown-unknown -emit-llvm-only -ferror-limit 10 %s -verify -D __TEST_ELT_SI
// RUN: %clang_cc1 -flax-vector-conversions=none -target-feature +vsx -target-cpu pwr10 -fsyntax-only \
// RUN: -triple powerpc64-unknown-unknown -emit-llvm -ferror-limit 10 %s -verify -D __TEST_ELT_F
// RUN: -triple powerpc64-unknown-unknown -emit-llvm-only -ferror-limit 10 %s -verify -D __TEST_ELT_F
// RUN: %clang_cc1 -flax-vector-conversions=none -target-feature +vsx -target-cpu pwr10 -fsyntax-only \
// RUN: -triple powerpc64le-unknown-unknown -emit-llvm -ferror-limit 10 %s -verify -D __TEST_ELT_SLL
// RUN: -triple powerpc64le-unknown-unknown -emit-llvm-only -ferror-limit 10 %s -verify -D __TEST_ELT_SLL
// RUN: %clang_cc1 -flax-vector-conversions=none -target-feature +vsx -target-cpu pwr10 -fsyntax-only \
// RUN: -triple powerpc64-unknown-unknown -emit-llvm -ferror-limit 10 %s -verify -D __TEST_ELT_D
// RUN: -triple powerpc64-unknown-unknown -emit-llvm-only -ferror-limit 10 %s -verify -D __TEST_ELT_D
// RUN: %clang_cc1 -flax-vector-conversions=none -target-feature +vsx -target-cpu pwr10 -fsyntax-only \
// RUN: -triple powerpc64le-unknown-unknown -emit-llvm -ferror-limit 10 %s -verify -D __TEST_UNALIGNED_UI
// RUN: -triple powerpc64le-unknown-unknown -emit-llvm-only -ferror-limit 10 %s -verify -D __TEST_UNALIGNED_UI
// RUN: %clang_cc1 -flax-vector-conversions=none -target-feature +vsx -target-cpu pwr10 -fsyntax-only \
// RUN: -triple powerpc64-unknown-unknown -emit-llvm -ferror-limit 10 %s -verify
// RUN: -triple powerpc64-unknown-unknown -emit-llvm-only -ferror-limit 10 %s -verify

#include <altivec.h>

Expand Down
2 changes: 1 addition & 1 deletion clang/test/CodeGen/RISCV/riscv-func-attr-target-err.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// REQUIRES: riscv-registered-target
// RUN: not %clang_cc1 -triple riscv64 -target-feature +zifencei -target-feature +m -target-feature +a \
// RUN: -emit-llvm %s 2>&1 | FileCheck %s
// RUN: -emit-llvm-only %s 2>&1 | FileCheck %s

#include <riscv_vector.h>

Expand Down
Loading