Skip to content

Commit

Permalink
merge main into amd-staging
Browse files Browse the repository at this point in the history
Change-Id: Ic918fcacb94f64e5595487c5fa4243d523e43f63
  • Loading branch information
ronlieb committed Sep 5, 2024
2 parents b7a41f0 + 1892666 commit ed76de6
Show file tree
Hide file tree
Showing 418 changed files with 7,992 additions and 4,511 deletions.
7 changes: 7 additions & 0 deletions .github/workflows/libcxx-build-and-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ jobs:
- { config: mingw-dll, mingw: true }
- { config: mingw-static, mingw: true }
- { config: mingw-dll-i686, mingw: true }
- { config: mingw-incomplete-sysroot, mingw: true }
steps:
- uses: actions/checkout@v4
- name: Install dependencies
Expand All @@ -260,6 +261,12 @@ jobs:
del llvm-mingw*.zip
mv llvm-mingw* c:\llvm-mingw
echo "c:\llvm-mingw\bin" | Out-File -FilePath $Env:GITHUB_PATH -Encoding utf8 -Append
- name: Simulate a from-scratch build of llvm-mingw
if: ${{ matrix.config == 'mingw-incomplete-sysroot' }}
run: |
rm -r c:\llvm-mingw\include\c++
rm -r c:\llvm-mingw\*-w64-mingw32\lib\libc++*
rm -r c:\llvm-mingw\*-w64-mingw32\lib\libunwind*
- name: Add Git Bash to the path
run: |
echo "c:\Program Files\Git\usr\bin" | Out-File -FilePath $Env:GITHUB_PATH -Encoding utf8 -Append
Expand Down
2 changes: 2 additions & 0 deletions clang/docs/LanguageExtensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1483,6 +1483,7 @@ Generic lambda expressions __cpp_generic_lambdas C+
variable templates __cpp_variable_templates C++14 C++03
Binary literals __cpp_binary_literals C++14 C++03
Relaxed constexpr __cpp_constexpr C++14 C++11
Static assert with no message __cpp_static_assert >= 201411L C++17 C++11
Pack expansion in generalized lambda-capture __cpp_init_captures C++17 C++03
``if constexpr`` __cpp_if_constexpr C++17 C++11
fold expressions __cpp_fold_expressions C++17 C++03
Expand All @@ -1503,6 +1504,7 @@ Conditional ``explicit`` __cpp_conditional_explicit C+
``static operator()`` __cpp_static_call_operator C++23 C++03
Attributes on Lambda-Expressions C++23 C++11
Attributes on Structured Bindings __cpp_structured_bindings C++26 C++03
Static assert with user-generated message __cpp_static_assert >= 202306L C++26 C++11
Pack Indexing __cpp_pack_indexing C++26 C++03
``= delete ("should have a reason");`` __cpp_deleted_function C++26 C++03
Variadic Friends __cpp_variadic_friend C++26 C++03
Expand Down
11 changes: 11 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ C++ Language Changes
constant expression. Supports the `V.xyzw` syntax and other tidbits
as seen in OpenCL. Selecting multiple elements is left as a future work.

- Accept C++26 user-defined ``static_assert`` messages in C++11 as an extension.


C++2c Feature Support
^^^^^^^^^^^^^^^^^^^^^
- Compiler flags ``-std=c++2c`` and ``-std=gnu++2c`` have been added for experimental C++2c implementation work.
Expand All @@ -127,6 +130,9 @@ C++2c Feature Support

- Implemented `P2747R2 constexpr placement new <https://wg21.link/P2747R2>`_.

- Added the ``__builtin_is_within_lifetime`` builtin, which supports
`P2641R4 Checking if a union alternative is active <https://wg21.link/p2641r4>`_

C++23 Feature Support
^^^^^^^^^^^^^^^^^^^^^
- Removed the restriction to literal types in constexpr functions in C++23 mode.
Expand Down Expand Up @@ -159,6 +165,10 @@ Resolutions to C++ Defect Reports
- Allow ``void{}`` as a prvalue of type ``void``.
(`CWG2351: void{} <https://cplusplus.github.io/CWG/issues/2351.html>`_).

- Clang now allows comparing unequal object pointers that have been cast to ``void *``
in constant expressions. These comparisons always worked in non-constant expressions.
(`CWG2749: Treatment of "pointer to void" for relational comparisons <https://cplusplus.github.io/CWG/issues/2749.html>`_).

C Language Changes
------------------

Expand Down Expand Up @@ -364,6 +374,7 @@ Bug Fixes to C++ Support
- Clang no longer tries to capture non-odr used default arguments of template parameters of generic lambdas (#GH107048)
- Fixed a bug where defaulted comparison operators would remove ``const`` from base classes. (#GH102588)

- Fix a crash when using ``source_location`` in the trailing return type of a lambda expression. (#GH67134)

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/Builtins.td
Original file line number Diff line number Diff line change
Expand Up @@ -934,6 +934,12 @@ def IsConstantEvaluated : LangBuiltin<"CXX_LANG"> {
let Prototype = "bool()";
}

def IsWithinLifetime : LangBuiltin<"CXX_LANG"> {
let Spellings = ["__builtin_is_within_lifetime"];
let Attributes = [NoThrow, CustomTypeChecking, Consteval];
let Prototype = "bool(void*)";
}

// GCC exception builtins
def EHReturn : Builtin {
let Spellings = ["__builtin_eh_return"];
Expand Down
14 changes: 9 additions & 5 deletions clang/include/clang/Basic/DiagnosticASTKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,6 @@ def note_constexpr_var_init_weak : Note<
def note_constexpr_typeid_polymorphic : Note<
"typeid applied to expression of polymorphic type %0 is "
"not allowed in a constant expression in C++ standards before C++20">;
def note_constexpr_void_comparison : Note<
"comparison between unequal pointers to void has unspecified result">;
def note_constexpr_temporary_here : Note<"temporary created here">;
def note_constexpr_dynamic_alloc_here : Note<"heap allocation performed here">;
def note_constexpr_conditional_never_const : Note<
Expand All @@ -169,14 +167,14 @@ def note_constexpr_this : Note<
def access_kind : TextSubstitution<
"%select{read of|read of|assignment to|increment of|decrement of|"
"member call on|dynamic_cast of|typeid applied to|construction of|"
"destruction of}0">;
"destruction of|read of}0">;
def access_kind_subobject : TextSubstitution<
"%select{read of|read of|assignment to|increment of|decrement of|"
"member call on|dynamic_cast of|typeid applied to|"
"construction of subobject of|destruction of}0">;
"construction of subobject of|destruction of|read of}0">;
def access_kind_volatile : TextSubstitution<
"%select{read of|read of|assignment to|increment of|decrement of|"
"<ERROR>|<ERROR>|<ERROR>|<ERROR>|<ERROR>}0">;
"<ERROR>|<ERROR>|<ERROR>|<ERROR>|<ERROR>|<ERROR>}0">;
def note_constexpr_lifetime_ended : Note<
"%sub{access_kind}0 %select{temporary|variable}1 whose "
"%plural{8:storage duration|:lifetime}0 has ended">;
Expand Down Expand Up @@ -409,6 +407,12 @@ def warn_is_constant_evaluated_always_true_constexpr : Warning<
"'%0' will always evaluate to 'true' in a manifestly constant-evaluated expression">,
InGroup<DiagGroup<"constant-evaluated">>;

def err_invalid_is_within_lifetime : Note<
"'%0' cannot be called with "
"%select{a null pointer|a one-past-the-end pointer|"
"a pointer to an object whose lifetime has not yet begun}1"
>;

// inline asm related.
let CategoryName = "Inline Assembly Issue" in {
def err_asm_invalid_escape : Error<
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,12 @@ def warn_c17_compat_static_assert_no_message : Warning<
"'_Static_assert' with no message is incompatible with C standards before "
"C23">,
DefaultIgnore, InGroup<CPre23Compat>;
def ext_cxx_static_assert_user_generated_message : ExtWarn<
"'static_assert' with a user-generated message is a C++26 extension">,
InGroup<CXX26>;
def warn_cxx20_compat_static_assert_user_generated_message : Warning<
"'static_assert' with a user-generated message is incompatible with "
"C++ standards before C++26">, DefaultIgnore, InGroup<CXXPre26Compat>;
def err_function_definition_not_allowed : Error<
"function definition is not allowed here">;
def err_expected_end_of_enumerator : Error<
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -12187,6 +12187,10 @@ def err_builtin_launder_invalid_arg : Error<
"%select{non-pointer|function pointer|void pointer}0 argument to "
"'__builtin_launder' is not allowed">;

def err_builtin_is_within_lifetime_invalid_arg : Error<
"%select{non-|function }0pointer argument to '__builtin_is_within_lifetime' "
"is not allowed">;

def err_builtin_invalid_arg_type: Error <
"%ordinal0 argument must be "
"%select{a vector, integer or floating point type|a matrix|"
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/ByteCode/State.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ enum AccessKinds {
AK_TypeId,
AK_Construct,
AK_Destroy,
AK_IsWithinLifetime,
};

/// The order of this enum is important for diagnostics.
Expand Down
10 changes: 10 additions & 0 deletions clang/lib/AST/Expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/APValue.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTLambda.h"
#include "clang/AST/Attr.h"
#include "clang/AST/ComputeDependence.h"
#include "clang/AST/DeclCXX.h"
Expand Down Expand Up @@ -2287,6 +2288,15 @@ APValue SourceLocExpr::EvaluateInContext(const ASTContext &Ctx,
Context = getParentContext();
}

// If we are currently parsing a lambda declarator, we might not have a fully
// formed call operator declaration yet, and we could not form a function name
// for it. Because we do not have access to Sema/function scopes here, we
// detect this case by relying on the fact such method doesn't yet have a
// type.
if (const auto *D = dyn_cast<CXXMethodDecl>(Context);
D && D->getFunctionTypeLoc().isNull() && isLambdaCallOperator(D))
Context = D->getParent()->getParent();

PresumedLoc PLoc = Ctx.getSourceManager().getPresumedLoc(
Ctx.getSourceManager().getExpansionRange(Loc).getEnd());

Expand Down
119 changes: 106 additions & 13 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1522,7 +1522,8 @@ CallStackFrame::~CallStackFrame() {
}

static bool isRead(AccessKinds AK) {
return AK == AK_Read || AK == AK_ReadObjectRepresentation;
return AK == AK_Read || AK == AK_ReadObjectRepresentation ||
AK == AK_IsWithinLifetime;
}

static bool isModification(AccessKinds AK) {
Expand All @@ -1532,6 +1533,7 @@ static bool isModification(AccessKinds AK) {
case AK_MemberCall:
case AK_DynamicCast:
case AK_TypeId:
case AK_IsWithinLifetime:
return false;
case AK_Assign:
case AK_Increment:
Expand All @@ -1549,7 +1551,8 @@ static bool isAnyAccess(AccessKinds AK) {

/// Is this an access per the C++ definition?
static bool isFormalAccess(AccessKinds AK) {
return isAnyAccess(AK) && AK != AK_Construct && AK != AK_Destroy;
return isAnyAccess(AK) && AK != AK_Construct && AK != AK_Destroy &&
AK != AK_IsWithinLifetime;
}

/// Is this kind of axcess valid on an indeterminate object value?
Expand All @@ -1561,6 +1564,7 @@ static bool isValidIndeterminateAccess(AccessKinds AK) {
// These need the object's value.
return false;

case AK_IsWithinLifetime:
case AK_ReadObjectRepresentation:
case AK_Assign:
case AK_Construct:
Expand Down Expand Up @@ -3707,7 +3711,8 @@ struct CompleteObject {
// In C++14 onwards, it is permitted to read a mutable member whose
// lifetime began within the evaluation.
// FIXME: Should we also allow this in C++11?
if (!Info.getLangOpts().CPlusPlus14)
if (!Info.getLangOpts().CPlusPlus14 &&
AK != AccessKinds::AK_IsWithinLifetime)
return false;
return lifetimeStartedInEvaluation(Info, Base, /*MutableSubobject*/true);
}
Expand Down Expand Up @@ -3760,6 +3765,12 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
if ((O->isAbsent() && !(handler.AccessKind == AK_Construct && I == N)) ||
(O->isIndeterminate() &&
!isValidIndeterminateAccess(handler.AccessKind))) {
// Object has ended lifetime.
// If I is non-zero, some subobject (member or array element) of a
// complete object has ended its lifetime, so this is valid for
// IsWithinLifetime, resulting in false.
if (I != 0 && handler.AccessKind == AK_IsWithinLifetime)
return false;
if (!Info.checkingPotentialConstantExpression())
Info.FFDiag(E, diag::note_constexpr_access_uninit)
<< handler.AccessKind << O->isIndeterminate()
Expand Down Expand Up @@ -3927,6 +3938,9 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
// Placement new onto an inactive union member makes it active.
O->setUnion(Field, APValue());
} else {
// Pointer to/into inactive union member: Not within lifetime
if (handler.AccessKind == AK_IsWithinLifetime)
return false;
// FIXME: If O->getUnionValue() is absent, report that there's no
// active union member rather than reporting the prior active union
// member. We'll need to fix nullptr_t to not use APValue() as its
Expand Down Expand Up @@ -11684,6 +11698,9 @@ class IntExprEvaluator

bool ZeroInitialization(const Expr *E) { return Success(0, E); }

friend std::optional<bool> EvaluateBuiltinIsWithinLifetime(IntExprEvaluator &,
const CallExpr *);

//===--------------------------------------------------------------------===//
// Visitor Methods
//===--------------------------------------------------------------------===//
Expand Down Expand Up @@ -12743,6 +12760,11 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
return Success(Info.InConstantContext, E);
}

case Builtin::BI__builtin_is_within_lifetime:
if (auto result = EvaluateBuiltinIsWithinLifetime(*this, E))
return Success(*result, E);
return false;

case Builtin::BI__builtin_ctz:
case Builtin::BI__builtin_ctzl:
case Builtin::BI__builtin_ctzll:
Expand Down Expand Up @@ -13895,16 +13917,6 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
SubobjectDesignator &LHSDesignator = LHSValue.getLValueDesignator();
SubobjectDesignator &RHSDesignator = RHSValue.getLValueDesignator();

// C++11 [expr.rel]p3:
// Pointers to void (after pointer conversions) can be compared, with a
// result defined as follows: If both pointers represent the same
// address or are both the null pointer value, the result is true if the
// operator is <= or >= and false otherwise; otherwise the result is
// unspecified.
// We interpret this as applying to pointers to *cv* void.
if (LHSTy->isVoidPointerType() && LHSOffset != RHSOffset && IsRelational)
Info.CCEDiag(E, diag::note_constexpr_void_comparison);

// C++11 [expr.rel]p2:
// - If two pointers point to non-static data members of the same object,
// or to subobjects or array elements fo such members, recursively, the
Expand Down Expand Up @@ -17332,3 +17344,84 @@ bool Expr::tryEvaluateStrLen(uint64_t &Result, ASTContext &Ctx) const {
EvalInfo Info(Ctx, Status, EvalInfo::EM_ConstantFold);
return EvaluateBuiltinStrLen(this, Result, Info);
}

namespace {
struct IsWithinLifetimeHandler {
EvalInfo &Info;
static constexpr AccessKinds AccessKind = AccessKinds::AK_IsWithinLifetime;
using result_type = std::optional<bool>;
std::optional<bool> failed() { return std::nullopt; }
template <typename T>
std::optional<bool> found(T &Subobj, QualType SubobjType) {
return true;
}
};

std::optional<bool> EvaluateBuiltinIsWithinLifetime(IntExprEvaluator &IEE,
const CallExpr *E) {
EvalInfo &Info = IEE.Info;
// Sometimes this is called during some sorts of constant folding / early
// evaluation. These are meant for non-constant expressions and are not
// necessary since this consteval builtin will never be evaluated at runtime.
// Just fail to evaluate when not in a constant context.
if (!Info.InConstantContext)
return std::nullopt;
assert(E->getBuiltinCallee() == Builtin::BI__builtin_is_within_lifetime);
const Expr *Arg = E->getArg(0);
if (Arg->isValueDependent())
return std::nullopt;
LValue Val;
if (!EvaluatePointer(Arg, Val, Info))
return std::nullopt;

auto Error = [&](int Diag) {
bool CalledFromStd = false;
const auto *Callee = Info.CurrentCall->getCallee();
if (Callee && Callee->isInStdNamespace()) {
const IdentifierInfo *Identifier = Callee->getIdentifier();
CalledFromStd = Identifier && Identifier->isStr("is_within_lifetime");
}
Info.CCEDiag(CalledFromStd ? Info.CurrentCall->getCallRange().getBegin()
: E->getExprLoc(),
diag::err_invalid_is_within_lifetime)
<< (CalledFromStd ? "std::is_within_lifetime"
: "__builtin_is_within_lifetime")
<< Diag;
return std::nullopt;
};
// C++2c [meta.const.eval]p4:
// During the evaluation of an expression E as a core constant expression, a
// call to this function is ill-formed unless p points to an object that is
// usable in constant expressions or whose complete object's lifetime began
// within E.

// Make sure it points to an object
// nullptr does not point to an object
if (Val.isNullPointer() || Val.getLValueBase().isNull())
return Error(0);
QualType T = Val.getLValueBase().getType();
assert(!T->isFunctionType() &&
"Pointers to functions should have been typed as function pointers "
"which would have been rejected earlier");
assert(T->isObjectType());
// Hypothetical array element is not an object
if (Val.getLValueDesignator().isOnePastTheEnd())
return Error(1);
assert(Val.getLValueDesignator().isValidSubobject() &&
"Unchecked case for valid subobject");
// All other ill-formed values should have failed EvaluatePointer, so the
// object should be a pointer to an object that is usable in a constant
// expression or whose complete lifetime began within the expression
CompleteObject CO =
findCompleteObject(Info, E, AccessKinds::AK_IsWithinLifetime, Val, T);
// The lifetime hasn't begun yet if we are still evaluating the
// initializer ([basic.life]p(1.2))
if (Info.EvaluatingDeclValue && CO.Value == Info.EvaluatingDeclValue)
return Error(2);

if (!CO)
return false;
IsWithinLifetimeHandler handler{Info};
return findSubobject(Info, E, CO, Val.getLValueDesignator(), handler);
}
} // namespace
3 changes: 1 addition & 2 deletions clang/lib/Analysis/ThreadSafety.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1180,8 +1180,7 @@ void BeforeSet::checkBeforeAfter(const ValueDecl* StartVd,
}
// Transitively search other before sets, and warn on cycles.
if (traverse(Vdb)) {
if (!CycMap.contains(Vd)) {
CycMap.insert(std::make_pair(Vd, true));
if (CycMap.try_emplace(Vd, true).second) {
StringRef L1 = Vd->getName();
Analyzer.Handler.handleBeforeAfterCycle(L1, Vd->getLocation());
}
Expand Down
Loading

0 comments on commit ed76de6

Please sign in to comment.