diff --git a/third_party/llvm/generated.patch b/third_party/llvm/generated.patch index 509398da9..12076086e 100644 --- a/third_party/llvm/generated.patch +++ b/third_party/llvm/generated.patch @@ -1 +1,608 @@ Auto generated patch. Do not edit or delete it, even if empty. +diff -ruN --strip-trailing-cr a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst +--- a/clang/docs/ReleaseNotes.rst ++++ b/clang/docs/ReleaseNotes.rst +@@ -81,6 +81,24 @@ + template + void f(); + ++- During constant evaluation, comparisons between different evaluations of the ++ same string literal are now correctly treated as non-constant, and comparisons ++ between string literals that cannot possibly overlap in memory are now treated ++ as constant. This updates Clang to match the anticipated direction of open core ++ issue `CWG2765 `, but is subject to change once that ++ issue is resolved. ++ ++ .. code-block:: c++ ++ ++ constexpr const char *f() { return "hello"; } ++ constexpr const char *g() { return "world"; } ++ // Used to evaluate to false, now error: non-constant comparison. ++ constexpr bool a = f() == f(); ++ // Might evaluate to true or false, as before. ++ bool at_runtime() { return f() == f(); } ++ // Was error, now evaluates to false. ++ constexpr bool b = f() == g(); ++ + ABI Changes in This Version + --------------------------- + +diff -ruN --strip-trailing-cr a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h +--- a/clang/include/clang/AST/ASTContext.h ++++ b/clang/include/clang/AST/ASTContext.h +@@ -324,6 +324,14 @@ + /// This is lazily created. This is intentionally not serialized. + mutable llvm::StringMap StringLiteralCache; + ++ /// The next string literal "version" to allocate during constant evaluation. ++ /// This is used to distinguish between repeated evaluations of the same ++ /// string literal. ++ /// ++ /// We don't need to serialize this because constants get re-evaluated in the ++ /// current file before they are compared locally. ++ unsigned NextStringLiteralVersion = 0; ++ + /// MD5 hash of CUID. It is calculated when first used and cached by this + /// data member. + mutable std::string CUIDHash; +@@ -3300,6 +3308,10 @@ + /// PredefinedExpr to cache evaluated results. + StringLiteral *getPredefinedStringLiteralFromCache(StringRef Key) const; + ++ /// Return the next version number to be used for a string literal evaluated ++ /// as part of constant evaluation. ++ unsigned getNextStringLiteralVersion() { return NextStringLiteralVersion++; } ++ + /// Return a declaration for the global GUID object representing the given + /// GUID value. + MSGuidDecl *getMSGuidDecl(MSGuidDeclParts Parts) const; +diff -ruN --strip-trailing-cr a/clang/include/clang/AST/DeclID.h b/clang/include/clang/AST/DeclID.h +--- a/clang/include/clang/AST/DeclID.h ++++ b/clang/include/clang/AST/DeclID.h +@@ -189,6 +189,7 @@ + // Every Decl ID is a local decl ID to the module being writing in ASTWriter. + friend class ASTWriter; + friend class GlobalDeclID; ++ friend struct llvm::DenseMapInfo; + + public: + LocalDeclID() : Base() {} +@@ -266,6 +267,27 @@ + return L == R; + } + }; ++ ++template <> struct DenseMapInfo { ++ using LocalDeclID = clang::LocalDeclID; ++ using DeclID = LocalDeclID::DeclID; ++ ++ static LocalDeclID getEmptyKey() { ++ return LocalDeclID(DenseMapInfo::getEmptyKey()); ++ } ++ ++ static LocalDeclID getTombstoneKey() { ++ return LocalDeclID(DenseMapInfo::getTombstoneKey()); ++ } ++ ++ static unsigned getHashValue(const LocalDeclID &Key) { ++ return DenseMapInfo::getHashValue(Key.getRawValue()); ++ } ++ ++ static bool isEqual(const LocalDeclID &L, const LocalDeclID &R) { ++ return L == R; ++ } ++}; + + } // namespace llvm + +diff -ruN --strip-trailing-cr a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td +--- a/clang/include/clang/Basic/DiagnosticASTKinds.td ++++ b/clang/include/clang/Basic/DiagnosticASTKinds.td +@@ -96,6 +96,9 @@ + "at runtime">; + def note_constexpr_literal_comparison : Note< + "comparison of addresses of literals has unspecified value">; ++def note_constexpr_opaque_call_comparison : Note< ++ "comparison against opaque constant address '%0' can only be performed at " ++ "runtime">; + def note_constexpr_pointer_weak_comparison : Note< + "comparison against address of weak declaration '%0' can only be performed " + "at runtime">; +diff -ruN --strip-trailing-cr a/clang/include/clang/Serialization/ASTWriter.h b/clang/include/clang/Serialization/ASTWriter.h +--- a/clang/include/clang/Serialization/ASTWriter.h ++++ b/clang/include/clang/Serialization/ASTWriter.h +@@ -233,13 +233,13 @@ + /// instead of comparing the result of `getDeclID()` or `GetDeclRef()`. + llvm::SmallPtrSet PredefinedDecls; + +- /// Mapping from FunctionDecl to the list of lambda IDs inside the function. ++ /// Mapping from FunctionDecl ID to the list of lambda IDs inside the ++ /// function. + /// + /// These lambdas have to be loaded right after the function they belong to. + /// In order to have canonical declaration for lambda class from the same + /// module as enclosing function during deserialization. +- llvm::DenseMap> +- FunctionToLambdasMap; ++ llvm::DenseMap> FunctionToLambdasMap; + + /// Offset of each declaration in the bitstream, indexed by + /// the declaration's ID. +diff -ruN --strip-trailing-cr a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp +--- a/clang/lib/AST/ExprConstant.cpp ++++ b/clang/lib/AST/ExprConstant.cpp +@@ -54,8 +54,10 @@ + #include "clang/Basic/DiagnosticSema.h" + #include "clang/Basic/TargetInfo.h" + #include "llvm/ADT/APFixedPoint.h" ++#include "llvm/ADT/Sequence.h" + #include "llvm/ADT/SmallBitVector.h" + #include "llvm/ADT/StringExtras.h" ++#include "llvm/Support/Casting.h" + #include "llvm/Support/Debug.h" + #include "llvm/Support/SaveAndRestore.h" + #include "llvm/Support/SipHash.h" +@@ -2061,8 +2063,8 @@ + return true; + } + +-/// Should this call expression be treated as a no-op? +-static bool IsNoOpCall(const CallExpr *E) { ++/// Should this call expression be treated as forming an opaque constant? ++static bool IsOpaqueConstantCall(const CallExpr *E) { + unsigned Builtin = E->getBuiltinCallee(); + return (Builtin == Builtin::BI__builtin___CFStringMakeConstantString || + Builtin == Builtin::BI__builtin___NSStringMakeConstantString || +@@ -2070,6 +2072,12 @@ + Builtin == Builtin::BI__builtin_function_start); + } + ++static bool IsOpaqueConstantCall(const LValue &LVal) { ++ const auto *BaseExpr = ++ llvm::dyn_cast_if_present(LVal.Base.dyn_cast()); ++ return BaseExpr && IsOpaqueConstantCall(BaseExpr); ++} ++ + static bool IsGlobalLValue(APValue::LValueBase B) { + // C++11 [expr.const]p3 An address constant expression is a prvalue core + // constant expression of pointer type that evaluates to... +@@ -2115,7 +2123,7 @@ + case Expr::ObjCBoxedExprClass: + return cast(E)->isExpressibleAsConstantInitializer(); + case Expr::CallExprClass: +- return IsNoOpCall(cast(E)); ++ return IsOpaqueConstantCall(cast(E)); + // For GCC compatibility, &&label has static storage duration. + case Expr::AddrLabelExprClass: + return true; +@@ -2142,11 +2150,91 @@ + return LVal.Base.dyn_cast(); + } + +-static bool IsLiteralLValue(const LValue &Value) { +- if (Value.getLValueCallIndex()) ++// Information about an LValueBase that is some kind of string. ++struct LValueBaseString { ++ std::string ObjCEncodeStorage; ++ StringRef Bytes; ++ int CharWidth; ++}; ++ ++// Gets the lvalue base of LVal as a string. ++static bool GetLValueBaseAsString(const EvalInfo &Info, const LValue &LVal, ++ LValueBaseString &AsString) { ++ const auto *BaseExpr = LVal.Base.dyn_cast(); ++ if (!BaseExpr) ++ return false; ++ ++ // For ObjCEncodeExpr, we need to compute and store the string. ++ if (const auto *EE = dyn_cast(BaseExpr)) { ++ Info.Ctx.getObjCEncodingForType(EE->getEncodedType(), ++ AsString.ObjCEncodeStorage); ++ AsString.Bytes = AsString.ObjCEncodeStorage; ++ AsString.CharWidth = 1; ++ return true; ++ } ++ ++ // Otherwise, we have a StringLiteral. ++ const auto *Lit = dyn_cast(BaseExpr); ++ if (const auto *PE = dyn_cast(BaseExpr)) ++ Lit = PE->getFunctionName(); ++ ++ if (!Lit) ++ return false; ++ ++ AsString.Bytes = Lit->getBytes(); ++ AsString.CharWidth = Lit->getCharByteWidth(); ++ return true; ++} ++ ++// Determine whether two string literals potentially overlap. This will be the ++// case if they agree on the values of all the bytes on the overlapping region ++// between them. ++// ++// The overlapping region is the portion of the two string literals that must ++// overlap in memory if the pointers actually point to the same address at ++// runtime. For example, if LHS is "abcdef" + 3 and RHS is "cdef\0gh" + 1 then ++// the overlapping region is "cdef\0", which in this case does agree, so the ++// strings are potentially overlapping. Conversely, for "foobar" + 3 versus ++// "bazbar" + 3, the overlapping region contains all of both strings, so they ++// are not potentially overlapping, even though they agree from the given ++// addresses onwards. ++// ++// See open core issue CWG2765 which is discussing the desired rule here. ++static bool ArePotentiallyOverlappingStringLiterals(const EvalInfo &Info, ++ const LValue &LHS, ++ const LValue &RHS) { ++ LValueBaseString LHSString, RHSString; ++ if (!GetLValueBaseAsString(Info, LHS, LHSString) || ++ !GetLValueBaseAsString(Info, RHS, RHSString)) + return false; +- const Expr *E = Value.Base.dyn_cast(); +- return E && !isa(E); ++ ++ // This is the byte offset to the location of the first character of LHS ++ // within RHS. We don't need to look at the characters of one string that ++ // would appear before the start of the other string if they were merged. ++ CharUnits Offset = RHS.Offset - LHS.Offset; ++ if (Offset.isNegative()) ++ LHSString.Bytes = LHSString.Bytes.drop_front(-Offset.getQuantity()); ++ else ++ RHSString.Bytes = RHSString.Bytes.drop_front(Offset.getQuantity()); ++ ++ bool LHSIsLonger = LHSString.Bytes.size() > RHSString.Bytes.size(); ++ StringRef Longer = LHSIsLonger ? LHSString.Bytes : RHSString.Bytes; ++ StringRef Shorter = LHSIsLonger ? RHSString.Bytes : LHSString.Bytes; ++ int ShorterCharWidth = (LHSIsLonger ? RHSString : LHSString).CharWidth; ++ ++ // The null terminator isn't included in the string data, so check for it ++ // manually. If the longer string doesn't have a null terminator where the ++ // shorter string ends, they aren't potentially overlapping. ++ for (int NullByte : llvm::seq(ShorterCharWidth)) { ++ if (Shorter.size() + NullByte >= Longer.size()) ++ break; ++ if (Longer[Shorter.size() + NullByte]) ++ return false; ++ } ++ ++ // Otherwise, they're potentially overlapping if and only if the overlapping ++ // region is the same. ++ return Shorter == Longer.take_front(Shorter.size()); + } + + static bool IsWeakLValue(const LValue &Value) { +@@ -8573,7 +8661,10 @@ + bool VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E); + bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E); + bool VisitMemberExpr(const MemberExpr *E); +- bool VisitStringLiteral(const StringLiteral *E) { return Success(E); } ++ bool VisitStringLiteral(const StringLiteral *E) { ++ return Success(APValue::LValueBase( ++ E, 0, Info.getASTContext().getNextStringLiteralVersion())); ++ } + bool VisitObjCEncodeExpr(const ObjCEncodeExpr *E) { return Success(E); } + bool VisitCXXTypeidExpr(const CXXTypeidExpr *E); + bool VisitCXXUuidofExpr(const CXXUuidofExpr *E); +@@ -9639,7 +9730,7 @@ + + bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, + unsigned BuiltinOp) { +- if (IsNoOpCall(E)) ++ if (IsOpaqueConstantCall(E)) + return Success(E); + + switch (BuiltinOp) { +@@ -13889,13 +13980,22 @@ + (!RHSValue.Base && !RHSValue.Offset.isZero())) + return DiagComparison(diag::note_constexpr_pointer_constant_comparison, + !RHSValue.Base); +- // It's implementation-defined whether distinct literals will have +- // distinct addresses. In clang, the result of such a comparison is +- // unspecified, so it is not a constant expression. However, we do know +- // that the address of a literal will be non-null. +- if ((IsLiteralLValue(LHSValue) || IsLiteralLValue(RHSValue)) && +- LHSValue.Base && RHSValue.Base) ++ // C++2c [intro.object]/10: ++ // Two objects [...] may have the same address if [...] they are both ++ // potentially non-unique objects. ++ // C++2c [intro.object]/9: ++ // An object is potentially non-unique if it is a string literal object, ++ // the backing array of an initializer list, or a subobject thereof. ++ // ++ // This makes the comparison result unspecified, so it's not a constant ++ // expression. ++ // ++ // TODO: Do we need to handle the initializer list case here? ++ if (ArePotentiallyOverlappingStringLiterals(Info, LHSValue, RHSValue)) + return DiagComparison(diag::note_constexpr_literal_comparison); ++ if (IsOpaqueConstantCall(LHSValue) || IsOpaqueConstantCall(RHSValue)) ++ return DiagComparison(diag::note_constexpr_opaque_call_comparison, ++ !IsOpaqueConstantCall(LHSValue)); + // We can't tell whether weak symbols will end up pointing to the same + // object. + if (IsWeakLValue(LHSValue) || IsWeakLValue(RHSValue)) +diff -ruN --strip-trailing-cr a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp +--- a/clang/lib/Serialization/ASTWriter.cpp ++++ b/clang/lib/Serialization/ASTWriter.cpp +@@ -5713,8 +5713,7 @@ + // efficent becuase it allows lazy deserialization. + RecordData FunctionToLambdasMapRecord; + for (const auto &Pair : FunctionToLambdasMap) { +- FunctionToLambdasMapRecord.push_back( +- GetDeclRef(Pair.first).getRawValue()); ++ FunctionToLambdasMapRecord.push_back(Pair.first.getRawValue()); + FunctionToLambdasMapRecord.push_back(Pair.second.size()); + for (const auto &Lambda : Pair.second) + FunctionToLambdasMapRecord.push_back(Lambda.getRawValue()); +diff -ruN --strip-trailing-cr a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp +--- a/clang/lib/Serialization/ASTWriterDecl.cpp ++++ b/clang/lib/Serialization/ASTWriterDecl.cpp +@@ -1524,7 +1524,8 @@ + // For lambdas inside canonical FunctionDecl remember the mapping. + if (auto FD = llvm::dyn_cast_or_null(D->getDeclContext()); + FD && FD->isCanonicalDecl()) { +- Writer.FunctionToLambdasMap[FD].push_back(Writer.GetDeclRef(D)); ++ Writer.FunctionToLambdasMap[Writer.GetDeclRef(FD)].push_back( ++ Writer.GetDeclRef(D)); + } + } else { + Record.push_back(CXXRecNotTemplate); +diff -ruN --strip-trailing-cr a/clang/test/AST/ByteCode/builtin-functions.cpp b/clang/test/AST/ByteCode/builtin-functions.cpp +--- a/clang/test/AST/ByteCode/builtin-functions.cpp ++++ b/clang/test/AST/ByteCode/builtin-functions.cpp +@@ -966,7 +966,8 @@ + 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}} ++ // ref-note {{comparison against opaque constant address '&__builtin_function_start(a)'}} \ ++ // expected-note {{comparison of addresses of literals has unspecified value}} + } + + namespace BuiltinInImplicitCtor { +diff -ruN --strip-trailing-cr a/clang/test/AST/ByteCode/cxx20.cpp b/clang/test/AST/ByteCode/cxx20.cpp +--- a/clang/test/AST/ByteCode/cxx20.cpp ++++ b/clang/test/AST/ByteCode/cxx20.cpp +@@ -99,7 +99,7 @@ + static_assert(f()); + #endif + +-/// Distinct literals have disctinct addresses. ++/// Distinct literals have distinct addresses. + /// see https://github.com/llvm/llvm-project/issues/58754 + constexpr auto foo(const char *p) { return p; } + constexpr auto p1 = "test1"; +@@ -108,22 +108,16 @@ + constexpr bool b1 = foo(p1) == foo(p1); + static_assert(b1); + +-constexpr bool b2 = foo(p1) == foo(p2); // ref-error {{must be initialized by a constant expression}} \ +- // ref-note {{comparison of addresses of literals}} \ +- // ref-note {{declared here}} +-static_assert(!b2); // ref-error {{not an integral constant expression}} \ +- // ref-note {{not a constant expression}} ++constexpr bool b2 = foo(p1) == foo(p2); ++static_assert(!b2); + + constexpr auto name1() { return "name1"; } + constexpr auto name2() { return "name2"; } + +-constexpr auto b3 = name1() == name1(); +-static_assert(b3); +-constexpr auto b4 = name1() == name2(); // ref-error {{must be initialized by a constant expression}} \ +- // ref-note {{has unspecified value}} \ +- // ref-note {{declared here}} +-static_assert(!b4); // ref-error {{not an integral constant expression}} \ +- // ref-note {{not a constant expression}} ++constexpr auto b3 = name1() == name1(); // ref-error {{must be initialized by a constant expression}} \ ++ // ref-note {{comparison of addresses of literals}} ++constexpr auto b4 = name1() == name2(); ++static_assert(!b4); + + namespace UninitializedFields { + class A { +diff -ruN --strip-trailing-cr a/clang/test/Modules/string-literal-uniqueness.cpp b/clang/test/Modules/string-literal-uniqueness.cpp +--- a/clang/test/Modules/string-literal-uniqueness.cpp ++++ b/clang/test/Modules/string-literal-uniqueness.cpp +@@ -0,0 +1,60 @@ ++// RUN: rm -rf %t ++// RUN: mkdir -p %t ++// RUN: split-file %s %t ++ ++// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/a.cpp \ ++// RUN: -o %t/A.pcm ++ ++// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/b.cpp \ ++// RUN: -fmodule-file=A=%t/A.pcm -o %t/B.pcm ++ ++// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/c.cpp \ ++// RUN: -fmodule-file=A=%t/A.pcm -o %t/C.pcm ++ ++// RUN: %clang_cc1 -std=c++20 -verify %t/main.cpp \ ++// RUN: -fmodule-file=A=%t/A.pcm \ ++// RUN: -fmodule-file=B=%t/B.pcm \ ++// RUN: -fmodule-file=C=%t/C.pcm ++ ++// expected-no-diagnostics ++ ++//--- a.cpp ++ ++export module A; ++export consteval const char *hello() { return "hello"; } ++export constexpr const char *helloA0 = hello(); ++export constexpr const char *helloA1 = helloA0; ++export constexpr const char *helloA2 = hello(); ++ ++//--- b.cpp ++ ++export module B; ++import A; ++export constexpr const char *helloB1 = helloA0; ++export constexpr const char *helloB2 = hello(); ++ ++//--- c.cpp ++ ++export module C; ++import A; ++export constexpr const char *helloC1 = helloA1; ++export constexpr const char *helloC2 = hello(); ++ ++//--- main.cpp ++ ++import A; ++import B; ++import C; ++ ++// These are valid: they refer to the same evaluation of the same constant. ++static_assert(helloA0 == helloA1); ++static_assert(helloA0 == helloB1); ++static_assert(helloA0 == helloC1); ++ ++// These refer to distinct evaluations, and so may or may not be equal. ++static_assert(helloA1 == helloA2); // expected-error {{}} expected-note {{unspecified value}} ++static_assert(helloA1 == helloB2); // expected-error {{}} expected-note {{unspecified value}} ++static_assert(helloA1 == helloC2); // expected-error {{}} expected-note {{unspecified value}} ++static_assert(helloA2 == helloB2); // expected-error {{}} expected-note {{unspecified value}} ++static_assert(helloA2 == helloC2); // expected-error {{}} expected-note {{unspecified value}} ++static_assert(helloB2 == helloC2); // expected-error {{}} expected-note {{unspecified value}} +diff -ruN --strip-trailing-cr a/clang/test/SemaCXX/builtins.cpp b/clang/test/SemaCXX/builtins.cpp +--- a/clang/test/SemaCXX/builtins.cpp ++++ b/clang/test/SemaCXX/builtins.cpp +@@ -1,13 +1,21 @@ +-// RUN: %clang_cc1 %s -fsyntax-only -verify -std=c++11 -fcxx-exceptions +-// RUN: %clang_cc1 %s -fsyntax-only -verify -std=c++1z -fcxx-exceptions ++// RUN: %clang_cc1 %s -fsyntax-only -verify -std=c++11 -fcxx-exceptions -fptrauth-intrinsics ++// RUN: %clang_cc1 %s -fsyntax-only -verify -std=c++1z -fcxx-exceptions -fptrauth-intrinsics + typedef const struct __CFString * CFStringRef; + #define CFSTR __builtin___CFStringMakeConstantString ++#define NSSTR __builtin___NSStringMakeConstantString + + void f() { + #if !defined(__MVS__) && !defined(_AIX) + // Builtin function __builtin___CFStringMakeConstantString is currently + // unsupported on z/OS and AIX. + (void)CFStringRef(CFSTR("Hello")); ++ ++ constexpr bool a = CFSTR("Hello") == CFSTR("Hello"); ++ // expected-error@-1 {{constant expression}} ++ // expected-note@-2 {{comparison against opaque constant address '&__builtin___CFStringMakeConstantString("Hello")'}} ++ constexpr bool b = NSSTR("Hello") == NSSTR("Hello"); ++ // expected-error@-1 {{constant expression}} ++ // expected-note@-2 {{comparison against opaque constant address '&__builtin___NSStringMakeConstantString("Hello")'}} + #endif + } + +@@ -47,7 +55,7 @@ + int n; + void *p = __builtin_function_start(n); // expected-error {{argument must be a function}} + static_assert(__builtin_function_start(a) == a, ""); // expected-error {{static assertion expression is not an integral constant expression}} +-// expected-note@-1 {{comparison of addresses of literals has unspecified value}} ++// expected-note@-1 {{comparison against opaque constant address '&__builtin_function_start(a)'}} + } // namespace function_start + + void no_ms_builtins() { +diff -ruN --strip-trailing-cr a/clang/test/SemaCXX/constant-expression-cxx11.cpp b/clang/test/SemaCXX/constant-expression-cxx11.cpp +--- a/clang/test/SemaCXX/constant-expression-cxx11.cpp ++++ b/clang/test/SemaCXX/constant-expression-cxx11.cpp +@@ -2,6 +2,10 @@ + // RUN: %clang_cc1 -std=c++20 -isystem %S/Inputs -fsyntax-only -verify=expected,cxx11_20,cxx20_23,pre-cxx23 -triple x86_64-linux -Wno-string-plus-int -Wno-pointer-arith -Wno-zero-length-array -Wno-c99-designator -fcxx-exceptions -pedantic %s -Wno-comment -Wno-tautological-pointer-compare -Wno-bool-conversion + // RUN: %clang_cc1 -std=c++11 -isystem %S/Inputs -fsyntax-only -verify=expected,cxx11_20,cxx11,pre-cxx23 -triple x86_64-linux -Wno-string-plus-int -Wno-pointer-arith -Wno-zero-length-array -Wno-c99-designator -fcxx-exceptions -pedantic %s -Wno-comment -Wno-tautological-pointer-compare -Wno-bool-conversion + ++// This macro forces its argument to be constant-folded, even if it's not ++// otherwise a constant expression. ++#define fold(x) (__builtin_constant_p(x) ? (x) : (x)) ++ + namespace StaticAssertFoldTest { + + int x; +@@ -358,11 +362,36 @@ + + extern char externalvar[]; + constexpr bool constaddress = (void *)externalvar == (void *)0x4000UL; // expected-error {{must be initialized by a constant expression}} expected-note {{reinterpret_cast}} +-constexpr bool litaddress = "foo" == "foo"; // expected-error {{must be initialized by a constant expression}} +-// expected-note@-1 {{comparison of addresses of literals has unspecified value}} +-// cxx20_23-warning@-2 {{comparison between two arrays is deprecated}} + static_assert(0 != "foo", ""); + ++// OK: These string literals cannot possibly overlap. ++static_assert(+"foo" != +"bar", ""); ++static_assert("xfoo" + 1 != "yfoo" + 1, ""); ++static_assert(+"foot" != +"foo", ""); ++static_assert(+"foo\0bar" != +"foo\0baz", ""); ++ ++// These can't overlap because the null terminator for UTF-16 is two bytes wide. ++static_assert(fold((const char*)u"A" != (const char*)"\0A\0x"), ""); ++static_assert(fold((const char*)u"A" != (const char*)"A\0\0x"), ""); ++ ++constexpr const char *string = "hello"; ++constexpr const char *also_string = string; ++static_assert(string == string, ""); ++static_assert(string == also_string, ""); ++ ++// These strings may overlap, and so the result of the comparison is unknown. ++constexpr bool may_overlap_1 = +"foo" == +"foo"; // expected-error {{}} expected-note {{addresses of literals}} ++constexpr bool may_overlap_2 = +"foo" == +"foo\0bar"; // expected-error {{}} expected-note {{addresses of literals}} ++constexpr bool may_overlap_3 = +"foo" == "bar\0foo" + 4; // expected-error {{}} expected-note {{addresses of literals}} ++constexpr bool may_overlap_4 = "xfoo" + 1 == "xfoo" + 1; // expected-error {{}} expected-note {{addresses of literals}} ++ ++// These may overlap even though they have different encodings. ++// One of these two comparisons is non-constant, but due to endianness we don't ++// know which one. ++constexpr bool may_overlap_different_encoding[] = ++ {fold((const char*)u"A" != (const char*)"xA\0\0\0x" + 1), fold((const char*)u"A" != (const char*)"x\0A\0\0x" + 1)}; ++ // expected-error@-2 {{}} expected-note@-1 {{addresses of literals}} ++ + } + + namespace MaterializeTemporary { +@@ -1543,16 +1572,10 @@ + + namespace Fold { + +- // This macro forces its argument to be constant-folded, even if it's not +- // otherwise a constant expression. +- #define fold(x) (__builtin_constant_p(x) ? (x) : (x)) +- + constexpr int n = (long)(char*)123; // expected-error {{constant expression}} expected-note {{reinterpret_cast}} + constexpr int m = fold((long)(char*)123); // ok + static_assert(m == 123, ""); + +- #undef fold +- + } + + namespace DR1454 { +diff -ruN --strip-trailing-cr a/clang/test/SemaCXX/constant-expression-cxx14.cpp b/clang/test/SemaCXX/constant-expression-cxx14.cpp +--- a/clang/test/SemaCXX/constant-expression-cxx14.cpp ++++ b/clang/test/SemaCXX/constant-expression-cxx14.cpp +@@ -1306,3 +1306,18 @@ + static_assert(field(3), ""); // expected-error {{constant expression}} \ + // expected-note {{in call to 'field(3)'}} + } ++ ++namespace literal_comparison { ++ ++constexpr bool different_in_loop(bool b = false) { ++ if (b) return false; ++ ++ const char *p[2] = {}; ++ for (const char *&r : p) ++ r = "hello"; ++ return p[0] == p[1]; // expected-note {{addresses of literals}} ++} ++constexpr bool check = different_in_loop(); ++ // expected-error@-1 {{}} expected-note@-1 {{in call}} ++ ++} +diff -ruN --strip-trailing-cr a/clang/test/SemaCXX/ptrauth-sign-constant.cpp b/clang/test/SemaCXX/ptrauth-sign-constant.cpp +--- a/clang/test/SemaCXX/ptrauth-sign-constant.cpp ++++ b/clang/test/SemaCXX/ptrauth-sign-constant.cpp +@@ -0,0 +1,7 @@ ++// RUN: %clang_cc1 -triple arm64-apple-ios -std=c++17 -Wno-vla -fsyntax-only -verify -fptrauth-intrinsics %s ++// RUN: %clang_cc1 -triple aarch64-linux-gnu -std=c++17 -Wno-vla -fsyntax-only -verify -fptrauth-intrinsics %s ++ ++int n; ++constexpr bool compare_result = __builtin_ptrauth_sign_constant(&n, 2, 0) == &n; ++// expected-error@-1 {{constant expression}} ++// expected-note@-2 {{comparison against opaque constant address '&__builtin_ptrauth_sign_constant(&n, 2, 0)'}} +\ No newline at end of file diff --git a/third_party/llvm/workspace.bzl b/third_party/llvm/workspace.bzl index 7b1108678..106f3665c 100644 --- a/third_party/llvm/workspace.bzl +++ b/third_party/llvm/workspace.bzl @@ -4,8 +4,8 @@ load("//third_party:repo.bzl", "tf_http_archive") def repo(name): """Imports LLVM.""" - LLVM_COMMIT = "29b92d07746fac26cd64c914bc9c5c3833974f6d" - LLVM_SHA256 = "3e8e93e3749454af4b64f7f34b792a4748b62fc533bca1703d33b2b04e34eb70" + LLVM_COMMIT = "23487be4903630a4c06160562fb939f6389aa99d" + LLVM_SHA256 = "7c4c8c99df91e9e9859006b0435f83b5ed1260289a649befacfb529dc0a5f68f" tf_http_archive( name = name,