Skip to content

Commit

Permalink
merge main into amd-staging
Browse files Browse the repository at this point in the history
Change-Id: I1d291f4898c65bb967a02a833f5f057ce394b696
  • Loading branch information
Jenkins committed Aug 31, 2024
2 parents 54334d7 + 0f7400c commit c74c21f
Show file tree
Hide file tree
Showing 31 changed files with 783 additions and 174 deletions.
2 changes: 2 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,8 @@ Bug Fixes to C++ Support
- Mangle placeholders for deduced types as a template-prefix, such that mangling
of template template parameters uses the correct production. (#GH106182)
- Fixed an assertion failure when converting vectors to int/float with invalid expressions. (#GH105486)
- Template parameter names are considered in the name lookup of out-of-line class template
specialization right before its declaration context. (#GH64082)

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
11 changes: 3 additions & 8 deletions clang/lib/AST/ByteCode/Compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -505,14 +505,9 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {
case CK_MemberPointerToBoolean: {
PrimType PtrT = classifyPrim(SubExpr->getType());

// Just emit p != nullptr for this.
if (!this->visit(SubExpr))
return false;

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

return this->emitNE(PtrT, CE);
return this->emitIsNonNull(PtrT, CE);
}

case CK_IntegralComplexToBoolean:
Expand Down Expand Up @@ -2323,8 +2318,8 @@ bool Compiler<Emitter>::VisitMaterializeTemporaryExpr(

// For everyhing else, use local variables.
if (SubExprT) {
unsigned LocalIndex = allocateLocalPrimitive(
SubExpr, *SubExprT, /*IsConst=*/true, /*IsExtended=*/true);
unsigned LocalIndex = allocateLocalPrimitive(E, *SubExprT, /*IsConst=*/true,
/*IsExtended=*/true);
if (!this->visit(SubExpr))
return false;
if (!this->emitSetLocal(*SubExprT, LocalIndex, E))
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/AST/ByteCode/Interp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,8 @@ void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC) {

// Some builtin functions require us to only look at the call site, since
// the classified parameter types do not match.
if (CurFunc->isBuiltin()) {
if (unsigned BID = CurFunc->getBuiltinID();
BID && S.getASTContext().BuiltinInfo.hasCustomTypechecking(BID)) {
const auto *CE =
cast<CallExpr>(S.Current->Caller->getExpr(S.Current->getRetPC()));
for (int32_t I = CE->getNumArgs() - 1; I >= 0; --I) {
Expand Down
64 changes: 43 additions & 21 deletions clang/lib/AST/ByteCode/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -986,24 +986,7 @@ inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
}
}

if (!Pointer::hasSameBase(LHS, RHS)) {
if (LHS.isOnePastEnd() && !RHS.isOnePastEnd() && !RHS.isZero() &&
RHS.getOffset() == 0) {
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)
<< LHS.toDiagnosticString(S.getASTContext());
return false;
} else if (RHS.isOnePastEnd() && !LHS.isOnePastEnd() && !LHS.isZero() &&
LHS.getOffset() == 0) {
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)
<< RHS.toDiagnosticString(S.getASTContext());
return false;
}

S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Unordered)));
return true;
} else {
if (Pointer::hasSameBase(LHS, RHS)) {
unsigned VL = LHS.getByteOffset();
unsigned VR = RHS.getByteOffset();

Expand All @@ -1019,6 +1002,35 @@ inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
return true;
}
// Otherwise we need to do a bunch of extra checks before returning Unordered.
if (LHS.isOnePastEnd() && !RHS.isOnePastEnd() && !RHS.isZero() &&
RHS.getOffset() == 0) {
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)
<< LHS.toDiagnosticString(S.getASTContext());
return false;
} else if (RHS.isOnePastEnd() && !LHS.isOnePastEnd() && !LHS.isZero() &&
LHS.getOffset() == 0) {
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)
<< RHS.toDiagnosticString(S.getASTContext());
return false;
}

bool BothNonNull = !LHS.isZero() && !RHS.isZero();
// Reject comparisons to literals.
for (const auto &P : {LHS, RHS}) {
if (P.isZero())
continue;
if (BothNonNull && P.pointsToLiteral()) {
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_literal_comparison);
return false;
}
}

S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Unordered)));
return true;
}

template <>
Expand All @@ -1030,9 +1042,10 @@ inline bool CmpHelperEQ<MemberPointer>(InterpState &S, CodePtr OpPC,
// If either operand is a pointer to a weak function, the comparison is not
// constant.
for (const auto &MP : {LHS, RHS}) {
if (const CXXMethodDecl *MD = MP.getMemberFunction(); MD && MD->isWeak()) {
if (MP.isWeak()) {
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_mem_pointer_weak_comparison) << MD;
S.FFDiag(Loc, diag::note_constexpr_mem_pointer_weak_comparison)
<< MP.getMemberFunction();
return false;
}
}
Expand Down Expand Up @@ -2291,6 +2304,15 @@ inline bool Null(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
return true;
}

template <PrimType Name, class T = typename PrimConv<Name>::T>
inline bool IsNonNull(InterpState &S, CodePtr OpPC) {
const auto &P = S.Stk.pop<T>();
if (P.isWeak())
return false;
S.Stk.push<Boolean>(Boolean::from(!P.isZero()));
return true;
}

//===----------------------------------------------------------------------===//
// This, ImplicitThis
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -2806,7 +2828,7 @@ inline bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
return true;
}

inline bool GetMemberPtr(InterpState &S, CodePtr OpPC, const Decl *D) {
inline bool GetMemberPtr(InterpState &S, CodePtr OpPC, const ValueDecl *D) {
S.Stk.push<MemberPointer>(D);
return true;
}
Expand Down
17 changes: 11 additions & 6 deletions clang/lib/AST/ByteCode/MemberPointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,21 @@ class FunctionPointer;
class MemberPointer final {
private:
Pointer Base;
const Decl *Dcl = nullptr;
const ValueDecl *Dcl = nullptr;
int32_t PtrOffset = 0;

MemberPointer(Pointer Base, const Decl *Dcl, int32_t PtrOffset)
MemberPointer(Pointer Base, const ValueDecl *Dcl, int32_t PtrOffset)
: Base(Base), Dcl(Dcl), PtrOffset(PtrOffset) {}

public:
MemberPointer() = default;
MemberPointer(Pointer Base, const Decl *Dcl) : Base(Base), Dcl(Dcl) {}
MemberPointer(Pointer Base, const ValueDecl *Dcl) : Base(Base), Dcl(Dcl) {}
MemberPointer(uint32_t Address, const Descriptor *D) {
// We only reach this for Address == 0, when creating a null member pointer.
assert(Address == 0);
}

MemberPointer(const Decl *D) : Dcl(D) {
MemberPointer(const ValueDecl *D) : Dcl(D) {
assert((isa<FieldDecl, IndirectFieldDecl, CXXMethodDecl>(D)));
}

Expand Down Expand Up @@ -67,7 +67,7 @@ class MemberPointer final {
}

bool hasDecl() const { return Dcl; }
const Decl *getDecl() const { return Dcl; }
const ValueDecl *getDecl() const { return Dcl; }

MemberPointer atInstanceBase(unsigned Offset) const {
if (Base.isZero())
Expand All @@ -84,14 +84,19 @@ class MemberPointer final {

bool isZero() const { return Base.isZero() && !Dcl; }
bool hasBase() const { return !Base.isZero(); }
bool isWeak() const {
if (const auto *MF = getMemberFunction())
return MF->isWeak();
return false;
}

void print(llvm::raw_ostream &OS) const {
OS << "MemberPtr(" << Base << " " << (const void *)Dcl << " + " << PtrOffset
<< ")";
}

std::string toDiagnosticString(const ASTContext &Ctx) const {
return "FIXME";
return toAPValue(Ctx).getAsString(Ctx, Dcl->getType());
}

ComparisonCategoryResult compare(const MemberPointer &RHS) const {
Expand Down
9 changes: 7 additions & 2 deletions clang/lib/AST/ByteCode/Opcodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def ArgExpr : ArgType { let Name = "const Expr *"; }
def ArgOffsetOfExpr : ArgType { let Name = "const OffsetOfExpr *"; }
def ArgDeclRef : ArgType { let Name = "const DeclRefExpr *"; }
def ArgCCI : ArgType { let Name = "const ComparisonCategoryInfo *"; }
def ArgDecl : ArgType { let Name = "const Decl*"; }
def ArgValueDecl : ArgType { let Name = "const ValueDecl*"; }
def ArgVarDecl : ArgType { let Name = "const VarDecl*"; }
def ArgDesc : ArgType { let Name = "const Descriptor *"; }
def ArgPrimType : ArgType { let Name = "PrimType"; }
Expand Down Expand Up @@ -597,6 +597,11 @@ def Comp: Opcode {
let HasGroup = 1;
}

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

//===----------------------------------------------------------------------===//
// Cast, CastFP.
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -751,7 +756,7 @@ def Memcpy : Opcode;
def ToMemberPtr : Opcode;
def CastMemberPtrPtr : Opcode;
def GetMemberPtr : Opcode {
let Args = [ArgDecl];
let Args = [ArgValueDecl];
}
def GetMemberPtrBase : Opcode;
def GetMemberPtrDecl : Opcode;
Expand Down
11 changes: 11 additions & 0 deletions clang/lib/AST/ByteCode/Pointer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,17 @@ bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) {
A.getFieldDesc()->IsArray;
}

bool Pointer::pointsToLiteral() const {
if (isZero() || !isBlockPointer())
return false;

const Expr *E = block()->getDescriptor()->asExpr();
if (block()->isDynamic())
return false;

return E && !isa<MaterializeTemporaryExpr, StringLiteral>(E);
}

std::optional<APValue> Pointer::toRValue(const Context &Ctx,
QualType ResultType) const {
const ASTContext &ASTCtx = Ctx.getASTContext();
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/AST/ByteCode/Pointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,10 @@ class Pointer {
/// Checks if both given pointers point to the same block.
static bool pointToSameBlock(const Pointer &A, const Pointer &B);

/// Whether this points to a block that's been created for a "literal lvalue",
/// i.e. a non-MaterializeTemporaryExpr Expr.
bool pointsToLiteral() const;

/// Prints the pointer.
void print(llvm::raw_ostream &OS) const;

Expand Down
24 changes: 24 additions & 0 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1873,6 +1873,27 @@ DeclResult Sema::CheckClassTemplate(
if (Previous.isAmbiguous())
return true;

// Let the template parameter scope enter the lookup chain of the current
// class template. For example, given
//
// namespace ns {
// template <class> bool Param = false;
// template <class T> struct N;
// }
//
// template <class Param> struct ns::N { void foo(Param); };
//
// When we reference Param inside the function parameter list, our name lookup
// chain for it should be like:
// FunctionScope foo
// -> RecordScope N
// -> TemplateParamScope (where we will find Param)
// -> NamespaceScope ns
//
// See also CppLookupName().
if (S->isTemplateParamScope())
EnterTemplatedContext(S, SemanticContext);

NamedDecl *PrevDecl = nullptr;
if (Previous.begin() != Previous.end())
PrevDecl = (*Previous.begin())->getUnderlyingDecl();
Expand Down Expand Up @@ -8090,6 +8111,9 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
return true;
}

if (S->isTemplateParamScope())
EnterTemplatedContext(S, ClassTemplate->getTemplatedDecl());

DeclContext *DC = ClassTemplate->getDeclContext();

bool isMemberSpecialization = false;
Expand Down
6 changes: 6 additions & 0 deletions clang/test/AST/ByteCode/builtin-functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -951,3 +951,9 @@ namespace shufflevector {
}

#endif

namespace FunctionStart {
void a(void) {}
static_assert(__builtin_function_start(a) == a, ""); // both-error {{not an integral constant expression}} \
// both-note {{comparison of addresses of literals has unspecified value}}
}
6 changes: 0 additions & 6 deletions clang/test/AST/ByteCode/weak.cpp
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
// RUN: %clang_cc1 -std=c++20 -fexperimental-new-constant-interpreter -verify=expected,both %s
// RUN: %clang_cc1 -std=c++20 -verify=ref,both %s




/// FIXME: The new interpreter also emits the "address of weak declaration" note in the pointer-to-bool case.

[[gnu::weak]] extern int a;
int ha[(bool)&a]; // both-warning {{variable length arrays in C++ are a Clang extension}} \
// expected-note {{comparison against address of weak declaration}} \
// both-error {{variable length array declaration not allowed at file scope}}
int ha2[&a == nullptr]; // both-warning {{variable length arrays in C++ are a Clang extension}} \
// both-note {{comparison against address of weak declaration '&a' can only be performed at runtime}} \
Expand Down
35 changes: 35 additions & 0 deletions clang/test/CXX/temp/temp.res/temp.local/p8.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s

namespace N {
enum { C };
Expand Down Expand Up @@ -151,4 +152,38 @@ namespace SearchClassBetweenTemplateParameterLists {
void A<T>::B<BB>::k(V) { // expected-error {{does not match}}
BB bb; // expected-error {{incomplete type}}
}

int CC;
template <typename> struct C;
template <template<typename> typename> struct D;
#if __cplusplus >= 202002L
template <bool CC> requires (CC) struct E;
template <typename> struct F;
template <typename> concept True = true;
#endif
}

template <typename CC>
struct SearchClassBetweenTemplateParameterLists::C {
void foo(CC); // This should find the template type parameter.
};

template <template<typename> typename CC>
struct SearchClassBetweenTemplateParameterLists::D {
template <typename AA>
CC<AA> foo(CC<AA>);
};

#if __cplusplus >= 202002L

template <bool CC> requires (CC)
struct SearchClassBetweenTemplateParameterLists::E {
void foo() requires (CC);
};

template <SearchClassBetweenTemplateParameterLists::True CC>
struct SearchClassBetweenTemplateParameterLists::F<CC> {
void foo(CC);
};

#endif
Loading

0 comments on commit c74c21f

Please sign in to comment.