Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// RUN: %check_clang_tidy %s readability-string-compare %t -- -config='{CheckOptions: {readability-string-compare.StringLikeClasses: "CustomStringTemplateBase;CustomStringNonTemplateBase"}}' -- -isystem %clang_tidy_headers
#include <string>

struct CustomStringNonTemplateBase {
int compare(const CustomStringNonTemplateBase& Other) const {
return 123; // value is not important for check
}
};

template <typename T>
struct CustomStringTemplateBase {
int compare(const CustomStringTemplateBase& Other) const {
return 123;
}
};

struct CustomString1 : CustomStringNonTemplateBase {};
struct CustomString2 : CustomStringTemplateBase<char> {};

void CustomStringClasses() {
std::string_view sv1("a");
std::string_view sv2("b");
if (sv1.compare(sv2)) { // No warning - if a std class is not listed in StringLikeClasses, it won't be checked.
}

CustomString1 custom1;
if (custom1.compare(custom1)) {
}
// CHECK-MESSAGES: [[@LINE-2]]:7: warning: do not use 'compare' to test equality of strings; use the string equality operator instead [readability-string-compare]

CustomString2 custom2;
if (custom2.compare(custom2)) {
}
// CHECK-MESSAGES: [[@LINE-2]]:7: warning: do not use 'compare' to test equality of strings; use the string equality operator instead [readability-string-compare]
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,27 @@ void Test() {
if (str1.compare(comp())) {
}
// CHECK-MESSAGES: [[@LINE-2]]:7: warning: do not use 'compare' to test equality of strings;

std::string_view sv1("a");
std::string_view sv2("b");
if (sv1.compare(sv2)) {
}
// CHECK-MESSAGES: [[@LINE-2]]:7: warning: do not use 'compare' to test equality of strings; use the string equality operator instead [readability-string-compare]
}

struct DerivedFromStdString : std::string {};

void TestDerivedClass() {
DerivedFromStdString derived;
if (derived.compare(derived)) {
}
// CHECK-MESSAGES: [[@LINE-2]]:7: warning: do not use 'compare' to test equality of strings; use the string equality operator instead [readability-string-compare]
}

void Valid() {
std::string str1("a", 1);
std::string str2("b", 1);

if (str1 == str2) {
}
if (str1 != str2) {
Expand All @@ -96,4 +112,11 @@ void Valid() {
}
if (str1.compare(str2) == -1) {
}

std::string_view sv1("a");
std::string_view sv2("b");
if (sv1 == sv2) {
}
if (sv1.compare(sv2) > 0) {
}
}
12 changes: 10 additions & 2 deletions clang/docs/ClangOffloadBundler.rst
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ Where:
object as a data section with the name ``.hip_fatbin``.

hipv4 Offload code object for the HIP language. Used for AMD GPU
code objects with at least ABI version V4 when the
code objects with at least ABI version V4 and above when the
``clang-offload-bundler`` is used to create a *fat binary*
to be loaded by the HIP runtime. The fat binary can be
loaded directly from a file, or be embedded in the host code
Expand All @@ -254,6 +254,14 @@ Where:
openmp Offload code object for the OpenMP language extension.
============= ==============================================================

Note: The distinction between the `hip` and `hipv4` offload kinds is historically based.
Originally, these designations might have indicated different versions of the
code object ABI. However, as the system has evolved, the ABI version is now embedded
directly within the code object itself, making these historical distinctions irrelevant
during the unbundling process. Consequently, `hip` and `hipv4` are treated as compatible
in current implementations, facilitating interchangeable handling of code objects
without differentiation based on offload kind.

**target-triple**
The target triple of the code object. See `Target Triple
<https://clang.llvm.org/docs/CrossCompilation.html#target-triple>`_.
Expand Down Expand Up @@ -295,7 +303,7 @@ Compatibility Rules for Bundle Entry ID
A code object, specified using its Bundle Entry ID, can be loaded and
executed on a target processor, if:

* Their offload kinds are the same.
* Their offload kinds are the same or comptible.
* Their target triples are compatible.
* Their Target IDs are compatible as defined in :ref:`compatibility-target-id`.

Expand Down
5 changes: 5 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -699,6 +699,10 @@ Bug Fixes to C++ Support
performed incorrectly when checking constraints. Fixes (#GH90349).
- Clang now allows constrained member functions to be explicitly specialized for an implicit instantiation
of a class template.
- Fix a C++23 bug in implementation of P2564R3 which evaluates immediate invocations in place
within initializers for variables that are usable in constant expressions or are constant
initialized, rather than evaluating them as a part of the larger manifestly constant evaluated
expression.

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -798,6 +802,7 @@ CUDA/HIP Language Changes

CUDA Support
^^^^^^^^^^^^
- Clang now supports CUDA SDK up to 12.4

AIX Support
^^^^^^^^^^^
Expand Down
45 changes: 44 additions & 1 deletion clang/include/clang/AST/OpenACCClause.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ class OpenACCClause {
protected:
OpenACCClause(OpenACCClauseKind K, SourceLocation BeginLoc,
SourceLocation EndLoc)
: Kind(K), Location(BeginLoc, EndLoc) {}
: Kind(K), Location(BeginLoc, EndLoc) {
assert(!BeginLoc.isInvalid() && !EndLoc.isInvalid() &&
"Begin and end location must be valid for OpenACCClause");
}

public:
OpenACCClauseKind getClauseKind() const { return Kind; }
Expand Down Expand Up @@ -189,6 +192,46 @@ class OpenACCClauseWithExprs : public OpenACCClauseWithParams {
}
};

// Represents the 'devnum' and expressions lists for the 'wait' clause.
class OpenACCWaitClause final
: public OpenACCClauseWithExprs,
public llvm::TrailingObjects<OpenACCWaitClause, Expr *> {
SourceLocation QueuesLoc;
OpenACCWaitClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
Expr *DevNumExpr, SourceLocation QueuesLoc,
ArrayRef<Expr *> QueueIdExprs, SourceLocation EndLoc)
: OpenACCClauseWithExprs(OpenACCClauseKind::Wait, BeginLoc, LParenLoc,
EndLoc),
QueuesLoc(QueuesLoc) {
// The first element of the trailing storage is always the devnum expr,
// whether it is used or not.
std::uninitialized_copy(&DevNumExpr, &DevNumExpr + 1,
getTrailingObjects<Expr *>());
std::uninitialized_copy(QueueIdExprs.begin(), QueueIdExprs.end(),
getTrailingObjects<Expr *>() + 1);
setExprs(
MutableArrayRef(getTrailingObjects<Expr *>(), QueueIdExprs.size() + 1));
}

public:
static OpenACCWaitClause *Create(const ASTContext &C, SourceLocation BeginLoc,
SourceLocation LParenLoc, Expr *DevNumExpr,
SourceLocation QueuesLoc,
ArrayRef<Expr *> QueueIdExprs,
SourceLocation EndLoc);

bool hasQueuesTag() const { return !QueuesLoc.isInvalid(); }
SourceLocation getQueuesLoc() const { return QueuesLoc; }
bool hasDevNumExpr() const { return getExprs()[0]; }
Expr *getDevNumExpr() const { return getExprs()[0]; }
llvm::ArrayRef<Expr *> getQueueIdExprs() {
return OpenACCClauseWithExprs::getExprs().drop_front();
}
llvm::ArrayRef<Expr *> getQueueIdExprs() const {
return OpenACCClauseWithExprs::getExprs().drop_front();
}
};

class OpenACCNumGangsClause final
: public OpenACCClauseWithExprs,
public llvm::TrailingObjects<OpenACCNumGangsClause, Expr *> {
Expand Down
12 changes: 12 additions & 0 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -4415,6 +4415,18 @@ def HLSLResourceBinding: InheritableAttr {
let Documentation = [HLSLResourceBindingDocs];
}

def HLSLPackOffset: HLSLAnnotationAttr {
let Spellings = [HLSLAnnotation<"packoffset">];
let LangOpts = [HLSL];
let Args = [IntArgument<"Subcomponent">, IntArgument<"Component">];
let Documentation = [HLSLPackOffsetDocs];
let AdditionalMembers = [{
unsigned getOffset() {
return subcomponent * 4 + component;
}
}];
}

def HLSLSV_DispatchThreadID: HLSLAnnotationAttr {
let Spellings = [HLSLAnnotation<"SV_DispatchThreadID">];
let Subjects = SubjectList<[ParmVar, Field]>;
Expand Down
20 changes: 20 additions & 0 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -7408,6 +7408,26 @@ The full documentation is available here: https://docs.microsoft.com/en-us/windo
}];
}

def HLSLPackOffsetDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
The packoffset attribute is used to change the layout of a cbuffer.
Attribute spelling in HLSL is: ``packoffset( c[Subcomponent][.component] )``.
A subcomponent is a register number, which is an integer. A component is in the form of [.xyzw].

Examples:

.. code-block:: c++

cbuffer A {
float3 a : packoffset(c0.y);
float4 b : packoffset(c4);
}

The full documentation is available here: https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-variable-packoffset
}];
}

def HLSLSV_DispatchThreadIDDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
Expand Down
5 changes: 4 additions & 1 deletion clang/include/clang/Basic/BuiltinsNVPTX.def
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@
#pragma push_macro("PTX81")
#pragma push_macro("PTX82")
#pragma push_macro("PTX83")
#define PTX83 "ptx83"
#pragma push_macro("PTX84")
#define PTX84 "ptx84"
#define PTX83 "ptx83|" PTX84
#define PTX82 "ptx82|" PTX83
#define PTX81 "ptx81|" PTX82
#define PTX80 "ptx80|" PTX81
Expand Down Expand Up @@ -1091,3 +1093,4 @@ TARGET_BUILTIN(__nvvm_getctarank_shared_cluster, "iv*3", "", AND(SM_90,PTX78))
#pragma pop_macro("PTX81")
#pragma pop_macro("PTX82")
#pragma pop_macro("PTX83")
#pragma pop_macro("PTX84")
1 change: 1 addition & 0 deletions clang/include/clang/Basic/BuiltinsWebAssembly.def
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ TARGET_BUILTIN(__builtin_wasm_relaxed_dot_bf16x8_add_f32_f32x4, "V4fV8UsV8UsV4f"

// Half-Precision (fp16)
TARGET_BUILTIN(__builtin_wasm_loadf16_f32, "fh*", "nU", "half-precision")
TARGET_BUILTIN(__builtin_wasm_storef16_f32, "vfh*", "n", "half-precision")

// Reference Types builtins
// Some builtins are custom type-checked - see 't' as part of the third argument,
Expand Down
3 changes: 2 additions & 1 deletion clang/include/clang/Basic/Cuda.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,10 @@ enum class CudaVersion {
CUDA_121,
CUDA_122,
CUDA_123,
CUDA_124,
FULLY_SUPPORTED = CUDA_123,
PARTIALLY_SUPPORTED =
CUDA_123, // Partially supported. Proceed with a warning.
CUDA_124, // Partially supported. Proceed with a warning.
NEW = 10000, // Too new. Issue a warning, but allow using it.
};
const char *CudaVersionToString(CudaVersion V);
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticGroups.td
Original file line number Diff line number Diff line change
Expand Up @@ -1507,6 +1507,9 @@ def BranchProtection : DiagGroup<"branch-protection">;
// Warnings for HLSL Clang extensions
def HLSLExtension : DiagGroup<"hlsl-extensions">;

// Warning for mix packoffset and non-packoffset.
def HLSLMixPackOffset : DiagGroup<"mix-packoffset">;

// Warnings for DXIL validation
def DXILValidation : DiagGroup<"dxil-validation">;

Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -1754,5 +1754,7 @@ def err_hlsl_separate_attr_arg_and_number : Error<"wrong argument format for hls
def ext_hlsl_access_specifiers : ExtWarn<
"access specifiers are a clang HLSL extension">,
InGroup<HLSLExtension>;
def err_hlsl_unsupported_component : Error<"invalid component '%0' used; expected 'x', 'y', 'z', or 'w'">;
def err_hlsl_packoffset_invalid_reg : Error<"invalid resource class specifier '%0' for packoffset, expected 'c'">;

} // end of Parser diagnostics
5 changes: 5 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -12184,6 +12184,11 @@ def err_hlsl_init_priority_unsupported : Error<
def err_hlsl_unsupported_register_type : Error<"invalid resource class specifier '%0' used; expected 'b', 's', 't', or 'u'">;
def err_hlsl_unsupported_register_number : Error<"register number should be an integer">;
def err_hlsl_expected_space : Error<"invalid space specifier '%0' used; expected 'space' followed by an integer, like space1">;
def warn_hlsl_packoffset_mix : Warning<"cannot mix packoffset elements with nonpackoffset elements in a cbuffer">,
InGroup<HLSLMixPackOffset>;
def err_hlsl_packoffset_overlap : Error<"packoffset overlap between %0, %1">;
def err_hlsl_packoffset_cross_reg_boundary : Error<"packoffset cannot cross register boundary">;
def err_hlsl_packoffset_alignment_mismatch : Error<"packoffset at 'y' not match alignment %0 required by %1">;
def err_hlsl_pointers_unsupported : Error<
"%select{pointers|references}0 are unsupported in HLSL">;

Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/Features.def
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,12 @@ FEATURE(thread_sanitizer, LangOpts.Sanitize.has(SanitizerKind::Thread))
FEATURE(dataflow_sanitizer, LangOpts.Sanitize.has(SanitizerKind::DataFlow))
FEATURE(scudo, LangOpts.Sanitize.hasOneOf(SanitizerKind::Scudo))
FEATURE(ptrauth_intrinsics, LangOpts.PointerAuthIntrinsics)
FEATURE(ptrauth_calls, LangOpts.PointerAuthCalls)
FEATURE(ptrauth_returns, LangOpts.PointerAuthReturns)
FEATURE(ptrauth_vtable_pointer_address_discrimination, LangOpts.PointerAuthVTPtrAddressDiscrimination)
FEATURE(ptrauth_vtable_pointer_type_discrimination, LangOpts.PointerAuthVTPtrTypeDiscrimination)
FEATURE(ptrauth_member_function_pointer_type_discrimination, LangOpts.PointerAuthCalls)
FEATURE(ptrauth_init_fini, LangOpts.PointerAuthInitFini)
EXTENSION(swiftcc,
PP.getTargetInfo().checkCallingConvention(CC_Swift) ==
clang::TargetInfo::CCCR_OK)
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/LangOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,12 @@ LANGOPT(RelaxedTemplateTemplateArgs, 1, 1, "C++17 relaxed matching of template t
LANGOPT(ExperimentalLibrary, 1, 0, "enable unstable and experimental library features")

LANGOPT(PointerAuthIntrinsics, 1, 0, "pointer authentication intrinsics")
LANGOPT(PointerAuthCalls , 1, 0, "function pointer authentication")
LANGOPT(PointerAuthReturns, 1, 0, "return pointer authentication")
LANGOPT(PointerAuthAuthTraps, 1, 0, "pointer authentication failure traps")
LANGOPT(PointerAuthVTPtrAddressDiscrimination, 1, 0, "incorporate address discrimination in authenticated vtable pointers")
LANGOPT(PointerAuthVTPtrTypeDiscrimination, 1, 0, "incorporate type discrimination in authenticated vtable pointers")
LANGOPT(PointerAuthInitFini, 1, 0, "sign function pointers in init/fini arrays")

LANGOPT(DoubleSquareBracketAttributes, 1, 0, "'[[]]' attributes extension for all language standard modes")
LANGOPT(ExperimentalLateParseAttributes, 1, 0, "experimental late parsing of attributes")
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/OpenACCClauses.def
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ VISIT_CLAUSE(Present)
VISIT_CLAUSE(Private)
VISIT_CLAUSE(Self)
VISIT_CLAUSE(VectorLength)
VISIT_CLAUSE(Wait)

#undef VISIT_CLAUSE
#undef CLAUSE_ALIAS
20 changes: 20 additions & 0 deletions clang/include/clang/Basic/TargetInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ struct TransferrableTargetInfo {
unsigned char LongLongWidth, LongLongAlign;
unsigned char Int128Align;

// This is an optional parameter for targets that
// don't use 'LongLongAlign' for '_BitInt' max alignment
std::optional<unsigned> BitIntMaxAlign;

// Fixed point bit widths
unsigned char ShortAccumWidth, ShortAccumAlign;
unsigned char AccumWidth, AccumAlign;
Expand Down Expand Up @@ -518,6 +522,22 @@ class TargetInfo : public TransferrableTargetInfo,
/// getInt128Align() - Returns the alignment of Int128.
unsigned getInt128Align() const { return Int128Align; }

/// getBitIntMaxAlign() - Returns the maximum possible alignment of
/// '_BitInt' and 'unsigned _BitInt'.
unsigned getBitIntMaxAlign() const {
return BitIntMaxAlign.value_or(LongLongAlign);
}

/// getBitIntAlign/Width - Return aligned size of '_BitInt' and
/// 'unsigned _BitInt' for this target, in bits.
unsigned getBitIntWidth(unsigned NumBits) const {
return llvm::alignTo(NumBits, getBitIntAlign(NumBits));
}
unsigned getBitIntAlign(unsigned NumBits) const {
return std::clamp<unsigned>(llvm::PowerOf2Ceil(NumBits), getCharWidth(),
getBitIntMaxAlign());
}

/// getShortAccumWidth/Align - Return the size of 'signed short _Accum' and
/// 'unsigned short _Accum' for this target, in bits.
unsigned getShortAccumWidth() const { return ShortAccumWidth; }
Expand Down
12 changes: 12 additions & 0 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -4180,6 +4180,14 @@ defm strict_return : BoolFOption<"strict-return",

let Flags = [TargetSpecific] in {
defm ptrauth_intrinsics : OptInCC1FFlag<"ptrauth-intrinsics", "Enable pointer authentication intrinsics">;
defm ptrauth_calls : OptInCC1FFlag<"ptrauth-calls", "Enable signing and authentication of all indirect calls">;
defm ptrauth_returns : OptInCC1FFlag<"ptrauth-returns", "Enable signing and authentication of return addresses">;
defm ptrauth_auth_traps : OptInCC1FFlag<"ptrauth-auth-traps", "Enable traps on authentication failures">;
defm ptrauth_vtable_pointer_address_discrimination :
OptInCC1FFlag<"ptrauth-vtable-pointer-address-discrimination", "Enable address discrimination of vtable pointers">;
defm ptrauth_vtable_pointer_type_discrimination :
OptInCC1FFlag<"ptrauth-vtable-pointer-type-discrimination", "Enable type discrimination of vtable pointers">;
defm ptrauth_init_fini : OptInCC1FFlag<"ptrauth-init-fini", "Enable signing of function pointers in init/fini arrays">;
}

def fenable_matrix : Flag<["-"], "fenable-matrix">, Group<f_Group>,
Expand Down Expand Up @@ -5077,6 +5085,10 @@ def maix_small_local_dynamic_tls : Flag<["-"], "maix-small-local-dynamic-tls">,
"where the offset from the TLS base is encoded as an "
"immediate operand (AIX 64-bit only). "
"This access sequence is not used for variables larger than 32KB.">;
def maix_shared_lib_tls_model_opt : Flag<["-"], "maix-shared-lib-tls-model-opt">,
Group<m_ppc_Features_Group>,
HelpText<"For shared library loaded with the main program, change local-dynamic access(es) "
"to initial-exec access(es) at the function level (AIX 64-bit only).">;
def maix_struct_return : Flag<["-"], "maix-struct-return">,
Group<m_Group>, Visibility<[ClangOption, CC1Option]>,
HelpText<"Return all structs in memory (PPC32 only)">,
Expand Down
10 changes: 9 additions & 1 deletion clang/include/clang/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -3632,6 +3632,13 @@ class Parser : public CodeCompletionHandler {
// Wait constructs, we likely want to put that information in here as well.
};

struct OpenACCWaitParseInfo {
bool Failed = false;
Expr *DevNumExpr = nullptr;
SourceLocation QueuesLoc;
SmallVector<Expr *> QueueIdExprs;
};

/// Represents the 'error' state of parsing an OpenACC Clause, and stores
/// whether we can continue parsing, or should give up on the directive.
enum class OpenACCParseCanContinue { Cannot = 0, Can = 1 };
Expand Down Expand Up @@ -3674,7 +3681,8 @@ class Parser : public CodeCompletionHandler {
/// Parses the clause-list for an OpenACC directive.
SmallVector<OpenACCClause *>
ParseOpenACCClauseList(OpenACCDirectiveKind DirKind);
bool ParseOpenACCWaitArgument(SourceLocation Loc, bool IsDirective);
OpenACCWaitParseInfo ParseOpenACCWaitArgument(SourceLocation Loc,
bool IsDirective);
/// Parses the clause of the 'bind' argument, which can be a string literal or
/// an ID expression.
ExprResult ParseOpenACCBindClauseArgument();
Expand Down
4 changes: 3 additions & 1 deletion clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -10202,7 +10202,9 @@ class Sema final : public SemaBase {
S.ExprEvalContexts.back().InImmediateFunctionContext =
FD->isImmediateFunction() ||
S.ExprEvalContexts[S.ExprEvalContexts.size() - 2]
.isConstantEvaluated();
.isConstantEvaluated() ||
S.ExprEvalContexts[S.ExprEvalContexts.size() - 2]
.isImmediateFunctionContext();
S.ExprEvalContexts.back().InImmediateEscalatingFunctionContext =
S.getLangOpts().CPlusPlus20 && FD->isImmediateEscalating();
} else
Expand Down
52 changes: 48 additions & 4 deletions clang/include/clang/Sema/SemaOpenACC.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,14 @@ class SemaOpenACC : public SemaBase {
bool IsZero;
};

struct WaitDetails {
Expr *DevNumExpr;
SourceLocation QueuesLoc;
SmallVector<Expr *> QueueIdExprs;
};

std::variant<std::monostate, DefaultDetails, ConditionDetails,
IntExprDetails, VarListDetails>
IntExprDetails, VarListDetails, WaitDetails>
Details = std::monostate{};

public:
Expand Down Expand Up @@ -104,14 +110,45 @@ class SemaOpenACC : public SemaBase {
ClauseKind == OpenACCClauseKind::Async ||
ClauseKind == OpenACCClauseKind::VectorLength) &&
"Parsed clause kind does not have a int exprs");
//
// 'async' has an optional IntExpr, so be tolerant of that.
if (ClauseKind == OpenACCClauseKind::Async &&

// 'async' and 'wait' have an optional IntExpr, so be tolerant of that.
if ((ClauseKind == OpenACCClauseKind::Async ||
ClauseKind == OpenACCClauseKind::Wait) &&
std::holds_alternative<std::monostate>(Details))
return 0;
return std::get<IntExprDetails>(Details).IntExprs.size();
}

SourceLocation getQueuesLoc() const {
assert(ClauseKind == OpenACCClauseKind::Wait &&
"Parsed clause kind does not have a queues location");

if (std::holds_alternative<std::monostate>(Details))
return SourceLocation{};

return std::get<WaitDetails>(Details).QueuesLoc;
}

Expr *getDevNumExpr() const {
assert(ClauseKind == OpenACCClauseKind::Wait &&
"Parsed clause kind does not have a device number expr");

if (std::holds_alternative<std::monostate>(Details))
return nullptr;

return std::get<WaitDetails>(Details).DevNumExpr;
}

ArrayRef<Expr *> getQueueIdExprs() const {
assert(ClauseKind == OpenACCClauseKind::Wait &&
"Parsed clause kind does not have a queue id expr list");

if (std::holds_alternative<std::monostate>(Details))
return ArrayRef<Expr *>{std::nullopt};

return std::get<WaitDetails>(Details).QueueIdExprs;
}

ArrayRef<Expr *> getIntExprs() {
assert((ClauseKind == OpenACCClauseKind::NumGangs ||
ClauseKind == OpenACCClauseKind::NumWorkers ||
Expand Down Expand Up @@ -282,6 +319,13 @@ class SemaOpenACC : public SemaBase {
"zero: tag only valid on copyout/create");
Details = VarListDetails{std::move(VarList), IsReadOnly, IsZero};
}

void setWaitDetails(Expr *DevNum, SourceLocation QueuesLoc,
llvm::SmallVector<Expr *> &&IntExprs) {
assert(ClauseKind == OpenACCClauseKind::Wait &&
"Parsed clause kind does not have a wait-details");
Details = WaitDetails{DevNum, QueuesLoc, std::move(IntExprs)};
}
};

SemaOpenACC(Sema &S);
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Serialization/ASTRecordReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,9 @@ class ASTRecordReader
/// Read a list of Exprs used for a var-list.
llvm::SmallVector<Expr *> readOpenACCVarList();

/// Read a list of Exprs used for a int-expr-list.
llvm::SmallVector<Expr *> readOpenACCIntExprList();

/// Read an OpenACC clause, advancing Idx.
OpenACCClause *readOpenACCClause();

Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Serialization/ASTRecordWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,8 @@ class ASTRecordWriter

void writeOpenACCVarList(const OpenACCClauseWithVarList *C);

void writeOpenACCIntExprList(ArrayRef<Expr *> Exprs);

/// Writes out a single OpenACC Clause.
void writeOpenACCClause(const OpenACCClause *C);

Expand Down
5 changes: 2 additions & 3 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2258,9 +2258,8 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
}
case Type::BitInt: {
const auto *EIT = cast<BitIntType>(T);
Align = std::clamp<unsigned>(llvm::PowerOf2Ceil(EIT->getNumBits()),
getCharWidth(), Target->getLongLongAlign());
Width = llvm::alignTo(EIT->getNumBits(), Align);
Align = Target->getBitIntAlign(EIT->getNumBits());
Width = Target->getBitIntWidth(EIT->getNumBits());
break;
}
case Type::Record:
Expand Down
31 changes: 31 additions & 0 deletions clang/lib/AST/OpenACCClause.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,18 @@ OpenACCAsyncClause *OpenACCAsyncClause::Create(const ASTContext &C,
return new (Mem) OpenACCAsyncClause(BeginLoc, LParenLoc, IntExpr, EndLoc);
}

OpenACCWaitClause *OpenACCWaitClause::Create(
const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc,
Expr *DevNumExpr, SourceLocation QueuesLoc, ArrayRef<Expr *> QueueIdExprs,
SourceLocation EndLoc) {
// Allocates enough room in trailing storage for all the int-exprs, plus a
// placeholder for the devnum.
void *Mem = C.Allocate(
OpenACCWaitClause::totalSizeToAlloc<Expr *>(QueueIdExprs.size() + 1));
return new (Mem) OpenACCWaitClause(BeginLoc, LParenLoc, DevNumExpr, QueuesLoc,
QueueIdExprs, EndLoc);
}

OpenACCNumGangsClause *OpenACCNumGangsClause::Create(const ASTContext &C,
SourceLocation BeginLoc,
SourceLocation LParenLoc,
Expand Down Expand Up @@ -393,3 +405,22 @@ void OpenACCClausePrinter::VisitCreateClause(const OpenACCCreateClause &C) {
[&](const Expr *E) { printExpr(E); });
OS << ")";
}

void OpenACCClausePrinter::VisitWaitClause(const OpenACCWaitClause &C) {
OS << "wait";
if (!C.getLParenLoc().isInvalid()) {
OS << "(";
if (C.hasDevNumExpr()) {
OS << "devnum: ";
printExpr(C.getDevNumExpr());
OS << " : ";
}

if (C.hasQueuesTag())
OS << "queues: ";

llvm::interleaveComma(C.getQueueIdExprs(), OS,
[&](const Expr *E) { printExpr(E); });
OS << ")";
}
}
7 changes: 7 additions & 0 deletions clang/lib/AST/StmtProfile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2578,6 +2578,13 @@ void OpenACCClauseProfiler::VisitAsyncClause(const OpenACCAsyncClause &Clause) {
if (Clause.hasIntExpr())
Profiler.VisitStmt(Clause.getIntExpr());
}

void OpenACCClauseProfiler::VisitWaitClause(const OpenACCWaitClause &Clause) {
if (Clause.hasDevNumExpr())
Profiler.VisitStmt(Clause.getDevNumExpr());
for (auto *E : Clause.getQueueIdExprs())
Profiler.VisitStmt(E);
}
} // namespace

void StmtProfiler::VisitOpenACCComputeConstruct(
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/AST/TextNodeDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,13 @@ void TextNodeDumper::Visit(const OpenACCClause *C) {
if (cast<OpenACCCreateClause>(C)->isZero())
OS << " : zero";
break;
case OpenACCClauseKind::Wait:
OS << " clause";
if (cast<OpenACCWaitClause>(C)->hasDevNumExpr())
OS << " has devnum";
if (cast<OpenACCWaitClause>(C)->hasQueuesTag())
OS << " has queues tag";
break;
default:
// Nothing to do here.
break;
Expand Down
5 changes: 3 additions & 2 deletions clang/lib/Basic/Cuda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ struct CudaVersionMapEntry {
};
#define CUDA_ENTRY(major, minor) \
{ \
#major "." #minor, CudaVersion::CUDA_##major##minor, \
#major "." #minor, CudaVersion::CUDA_##major##minor, \
llvm::VersionTuple(major, minor) \
}

Expand All @@ -41,6 +41,7 @@ static const CudaVersionMapEntry CudaNameVersionMap[] = {
CUDA_ENTRY(12, 1),
CUDA_ENTRY(12, 2),
CUDA_ENTRY(12, 3),
CUDA_ENTRY(12, 4),
{"", CudaVersion::NEW, llvm::VersionTuple(std::numeric_limits<int>::max())},
{"unknown", CudaVersion::UNKNOWN, {}} // End of list tombstone.
};
Expand Down Expand Up @@ -241,7 +242,7 @@ CudaVersion MaxVersionForCudaArch(CudaArch A) {
}
}

bool CudaFeatureEnabled(llvm::VersionTuple Version, CudaFeature Feature) {
bool CudaFeatureEnabled(llvm::VersionTuple Version, CudaFeature Feature) {
return CudaFeatureEnabled(ToCudaVersion(Version), Feature);
}

Expand Down
1 change: 1 addition & 0 deletions clang/lib/Basic/Targets/AArch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ AArch64TargetInfo::AArch64TargetInfo(const llvm::Triple &Triple,
else
LongWidth = LongAlign = PointerWidth = PointerAlign = 32;

BitIntMaxAlign = 128;
MaxVectorAlign = 128;
MaxAtomicInlineWidth = 128;
MaxAtomicPromoteWidth = 128;
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Basic/Targets/PPC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ bool PPCTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
IsISA3_1 = true;
} else if (Feature == "+quadword-atomics") {
HasQuadwordAtomics = true;
} else if (Feature == "+aix-shared-lib-tls-model-opt") {
HasAIXShLibTLSModelOpt = true;
}
// TODO: Finish this list and add an assert that we've handled them
// all.
Expand Down Expand Up @@ -580,6 +582,9 @@ bool PPCTargetInfo::initFeatureMap(
Features["aix-small-local-exec-tls"] = false;
Features["aix-small-local-dynamic-tls"] = false;

// Turn off TLS model opt by default.
Features["aix-shared-lib-tls-model-opt"] = false;

Features["spe"] = llvm::StringSwitch<bool>(CPU)
.Case("8548", true)
.Case("e500", true)
Expand Down Expand Up @@ -722,6 +727,7 @@ bool PPCTargetInfo::hasFeature(StringRef Feature) const {
.Case("isa-v30-instructions", IsISA3_0)
.Case("isa-v31-instructions", IsISA3_1)
.Case("quadword-atomics", HasQuadwordAtomics)
.Case("aix-shared-lib-tls-model-opt", HasAIXShLibTLSModelOpt)
.Default(false);
}

Expand Down
1 change: 1 addition & 0 deletions clang/lib/Basic/Targets/PPC.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ class LLVM_LIBRARY_VISIBILITY PPCTargetInfo : public TargetInfo {
bool IsISA3_0 = false;
bool IsISA3_1 = false;
bool HasQuadwordAtomics = false;
bool HasAIXShLibTLSModelOpt = false;

protected:
std::string ABI;
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21310,6 +21310,12 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID,
Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_loadf16_f32);
return Builder.CreateCall(Callee, {Addr});
}
case WebAssembly::BI__builtin_wasm_storef16_f32: {
Value *Val = EmitScalarExpr(E->getArg(0));
Value *Addr = EmitScalarExpr(E->getArg(1));
Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_storef16_f32);
return Builder.CreateCall(Callee, {Val, Addr});
}
case WebAssembly::BI__builtin_wasm_table_get: {
assert(E->getArg(0)->getType()->isArrayType());
Value *Table = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this);
Expand Down
32 changes: 32 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/Frontend/OpenMP/OMPIRBuilder.h"
#include "llvm/IR/AttributeMask.h"
#include "llvm/IR/CallingConv.h"
Expand Down Expand Up @@ -1190,6 +1191,37 @@ void CodeGenModule::Release() {
if (!LangOpts.isSignReturnAddressWithAKey())
getModule().addModuleFlag(llvm::Module::Min,
"sign-return-address-with-bkey", 1);

if (getTriple().isOSLinux()) {
assert(getTriple().isOSBinFormatELF());
using namespace llvm::ELF;
uint64_t PAuthABIVersion =
(LangOpts.PointerAuthIntrinsics
<< AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_INTRINSICS) |
(LangOpts.PointerAuthCalls
<< AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_CALLS) |
(LangOpts.PointerAuthReturns
<< AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_RETURNS) |
(LangOpts.PointerAuthAuthTraps
<< AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_AUTHTRAPS) |
(LangOpts.PointerAuthVTPtrAddressDiscrimination
<< AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_VPTRADDRDISCR) |
(LangOpts.PointerAuthVTPtrTypeDiscrimination
<< AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_VPTRTYPEDISCR) |
(LangOpts.PointerAuthInitFini
<< AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_INITFINI);
static_assert(AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_INITFINI ==
AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_LAST,
"Update when new enum items are defined");
if (PAuthABIVersion != 0) {
getModule().addModuleFlag(llvm::Module::Error,
"aarch64-elf-pauthabi-platform",
AARCH64_PAUTH_PLATFORM_LLVM_LINUX);
getModule().addModuleFlag(llvm::Module::Error,
"aarch64-elf-pauthabi-version",
PAuthABIVersion);
}
}
}

if (CodeGenOpts.StackClashProtector)
Expand Down
5 changes: 4 additions & 1 deletion clang/lib/Driver/OffloadBundler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,11 @@ bool OffloadTargetInfo::isOffloadKindValid() const {

bool OffloadTargetInfo::isOffloadKindCompatible(
const StringRef TargetOffloadKind) const {
if (OffloadKind == TargetOffloadKind)
if ((OffloadKind == TargetOffloadKind) ||
(OffloadKind == "hip" && TargetOffloadKind == "hipv4") ||
(OffloadKind == "hipv4" && TargetOffloadKind == "hip"))
return true;

if (BundlerConfig.HipOpenmpCompatible) {
bool HIPCompatibleWithOpenMP = OffloadKind.starts_with_insensitive("hip") &&
TargetOffloadKind == "openmp";
Expand Down
14 changes: 14 additions & 0 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1756,6 +1756,20 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args,

Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_intrinsics,
options::OPT_fno_ptrauth_intrinsics);
Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_calls,
options::OPT_fno_ptrauth_calls);
Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_returns,
options::OPT_fno_ptrauth_returns);
Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_auth_traps,
options::OPT_fno_ptrauth_auth_traps);
Args.addOptInFlag(
CmdArgs, options::OPT_fptrauth_vtable_pointer_address_discrimination,
options::OPT_fno_ptrauth_vtable_pointer_address_discrimination);
Args.addOptInFlag(
CmdArgs, options::OPT_fptrauth_vtable_pointer_type_discrimination,
options::OPT_fno_ptrauth_vtable_pointer_type_discrimination);
Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_init_fini,
options::OPT_fno_ptrauth_init_fini);
}

void Clang::AddLoongArchTargetArgs(const ArgList &Args,
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Driver/ToolChains/Cuda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ CudaVersion getCudaVersion(uint32_t raw_version) {
return CudaVersion::CUDA_122;
if (raw_version < 12040)
return CudaVersion::CUDA_123;
if (raw_version < 12050)
return CudaVersion::CUDA_124;
return CudaVersion::NEW;
}

Expand Down Expand Up @@ -688,6 +690,7 @@ void NVPTX::getNVPTXTargetFeatures(const Driver &D, const llvm::Triple &Triple,
case CudaVersion::CUDA_##CUDA_VER: \
PtxFeature = "+ptx" #PTX_VER; \
break;
CASE_CUDA_VERSION(124, 84);
CASE_CUDA_VERSION(123, 83);
CASE_CUDA_VERSION(122, 82);
CASE_CUDA_VERSION(121, 81);
Expand Down
20 changes: 20 additions & 0 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3346,11 +3346,31 @@ static void GeneratePointerAuthArgs(const LangOptions &Opts,
ArgumentConsumer Consumer) {
if (Opts.PointerAuthIntrinsics)
GenerateArg(Consumer, OPT_fptrauth_intrinsics);
if (Opts.PointerAuthCalls)
GenerateArg(Consumer, OPT_fptrauth_calls);
if (Opts.PointerAuthReturns)
GenerateArg(Consumer, OPT_fptrauth_returns);
if (Opts.PointerAuthAuthTraps)
GenerateArg(Consumer, OPT_fptrauth_auth_traps);
if (Opts.PointerAuthVTPtrAddressDiscrimination)
GenerateArg(Consumer, OPT_fptrauth_vtable_pointer_address_discrimination);
if (Opts.PointerAuthVTPtrTypeDiscrimination)
GenerateArg(Consumer, OPT_fptrauth_vtable_pointer_type_discrimination);
if (Opts.PointerAuthInitFini)
GenerateArg(Consumer, OPT_fptrauth_init_fini);
}

static void ParsePointerAuthArgs(LangOptions &Opts, ArgList &Args,
DiagnosticsEngine &Diags) {
Opts.PointerAuthIntrinsics = Args.hasArg(OPT_fptrauth_intrinsics);
Opts.PointerAuthCalls = Args.hasArg(OPT_fptrauth_calls);
Opts.PointerAuthReturns = Args.hasArg(OPT_fptrauth_returns);
Opts.PointerAuthAuthTraps = Args.hasArg(OPT_fptrauth_auth_traps);
Opts.PointerAuthVTPtrAddressDiscrimination =
Args.hasArg(OPT_fptrauth_vtable_pointer_address_discrimination);
Opts.PointerAuthVTPtrTypeDiscrimination =
Args.hasArg(OPT_fptrauth_vtable_pointer_type_discrimination);
Opts.PointerAuthInitFini = Args.hasArg(OPT_fptrauth_init_fini);
}

/// Check if input file kind and language standard are compatible.
Expand Down
21 changes: 10 additions & 11 deletions clang/lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2587,25 +2587,30 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
Parser &P;
Declarator &D;
Decl *ThisDecl;
bool Entered;

InitializerScopeRAII(Parser &P, Declarator &D, Decl *ThisDecl)
: P(P), D(D), ThisDecl(ThisDecl) {
: P(P), D(D), ThisDecl(ThisDecl), Entered(false) {
if (ThisDecl && P.getLangOpts().CPlusPlus) {
Scope *S = nullptr;
if (D.getCXXScopeSpec().isSet()) {
P.EnterScope(0);
S = P.getCurScope();
}
P.Actions.ActOnCXXEnterDeclInitializer(S, ThisDecl);
if (ThisDecl && !ThisDecl->isInvalidDecl()) {
P.Actions.ActOnCXXEnterDeclInitializer(S, ThisDecl);
Entered = true;
}
}
}
~InitializerScopeRAII() { pop(); }
void pop() {
~InitializerScopeRAII() {
if (ThisDecl && P.getLangOpts().CPlusPlus) {
Scope *S = nullptr;
if (D.getCXXScopeSpec().isSet())
S = P.getCurScope();
P.Actions.ActOnCXXExitDeclInitializer(S, ThisDecl);

if (Entered)
P.Actions.ActOnCXXExitDeclInitializer(S, ThisDecl);
if (S)
P.ExitScope();
}
Expand Down Expand Up @@ -2736,8 +2741,6 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
FRI->RangeExpr = Init;
}

InitScope.pop();

if (Init.isInvalid()) {
SmallVector<tok::TokenKind, 2> StopTokens;
StopTokens.push_back(tok::comma);
Expand Down Expand Up @@ -2785,8 +2788,6 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(

bool SawError = ParseExpressionList(Exprs, ExpressionStarts);

InitScope.pop();

if (SawError) {
if (ThisVarDecl && PP.isCodeCompletionReached() && !CalledSignatureHelp) {
Actions.ProduceConstructorSignatureHelp(
Expand Down Expand Up @@ -2818,8 +2819,6 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
PreferredType.enterVariableInit(Tok.getLocation(), ThisDecl);
ExprResult Init(ParseBraceInitializer());

InitScope.pop();

if (Init.isInvalid()) {
Actions.ActOnInitializerError(ThisDecl);
} else
Expand Down
88 changes: 88 additions & 0 deletions clang/lib/Parse/ParseHLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,94 @@ void Parser::ParseHLSLAnnotations(ParsedAttributes &Attrs,
return;
}
} break;
case ParsedAttr::AT_HLSLPackOffset: {
// Parse 'packoffset( c[Subcomponent][.component] )'.
// Check '('.
if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after)) {
SkipUntil(tok::r_paren, StopAtSemi); // skip through )
return;
}
// Check c[Subcomponent] as an identifier.
if (!Tok.is(tok::identifier)) {
Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;
SkipUntil(tok::r_paren, StopAtSemi); // skip through )
return;
}
StringRef OffsetStr = Tok.getIdentifierInfo()->getName();
SourceLocation SubComponentLoc = Tok.getLocation();
if (OffsetStr[0] != 'c') {
Diag(Tok.getLocation(), diag::err_hlsl_packoffset_invalid_reg)
<< OffsetStr;
SkipUntil(tok::r_paren, StopAtSemi); // skip through )
return;
}
OffsetStr = OffsetStr.substr(1);
unsigned SubComponent = 0;
if (!OffsetStr.empty()) {
// Make sure SubComponent is a number.
if (OffsetStr.getAsInteger(10, SubComponent)) {
Diag(SubComponentLoc.getLocWithOffset(1),
diag::err_hlsl_unsupported_register_number);
SkipUntil(tok::r_paren, StopAtSemi); // skip through )
return;
}
}
unsigned Component = 0;
ConsumeToken(); // consume identifier.
SourceLocation ComponentLoc;
if (Tok.is(tok::period)) {
ConsumeToken(); // consume period.
if (!Tok.is(tok::identifier)) {
Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;
SkipUntil(tok::r_paren, StopAtSemi); // skip through )
return;
}
StringRef ComponentStr = Tok.getIdentifierInfo()->getName();
ComponentLoc = Tok.getLocation();
ConsumeToken(); // consume identifier.
// Make sure Component is a single character.
if (ComponentStr.size() != 1) {
Diag(ComponentLoc, diag::err_hlsl_unsupported_component)
<< ComponentStr;
SkipUntil(tok::r_paren, StopAtSemi); // skip through )
return;
}
switch (ComponentStr[0]) {
case 'x':
case 'r':
Component = 0;
break;
case 'y':
case 'g':
Component = 1;
break;
case 'z':
case 'b':
Component = 2;
break;
case 'w':
case 'a':
Component = 3;
break;
default:
Diag(ComponentLoc, diag::err_hlsl_unsupported_component)
<< ComponentStr;
SkipUntil(tok::r_paren, StopAtSemi); // skip through )
return;
}
}
ASTContext &Ctx = Actions.getASTContext();
QualType SizeTy = Ctx.getSizeType();
uint64_t SizeTySize = Ctx.getTypeSize(SizeTy);
ArgExprs.push_back(IntegerLiteral::Create(
Ctx, llvm::APInt(SizeTySize, SubComponent), SizeTy, SubComponentLoc));
ArgExprs.push_back(IntegerLiteral::Create(
Ctx, llvm::APInt(SizeTySize, Component), SizeTy, ComponentLoc));
if (ExpectAndConsume(tok::r_paren, diag::err_expected)) {
SkipUntil(tok::r_paren, StopAtSemi); // skip through )
return;
}
} break;
case ParsedAttr::UnknownAttribute:
Diag(Loc, diag::err_unknown_hlsl_semantic) << II;
return;
Expand Down
61 changes: 43 additions & 18 deletions clang/lib/Parse/ParseOpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -867,7 +867,6 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams(
SemaOpenACC::OpenACCParsedClause ParsedClause(DirKind, ClauseKind, ClauseLoc);

if (ClauseHasRequiredParens(DirKind, ClauseKind)) {
ParsedClause.setLParenLoc(getCurToken().getLocation());
if (Parens.expectAndConsume()) {
// We are missing a paren, so assume that the person just forgot the
// parameter. Return 'false' so we try to continue on and parse the next
Expand All @@ -876,6 +875,7 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams(
Parser::StopBeforeMatch);
return OpenACCCanContinue();
}
ParsedClause.setLParenLoc(Parens.getOpenLocation());

switch (ClauseKind) {
case OpenACCClauseKind::Default: {
Expand Down Expand Up @@ -956,7 +956,6 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams(
break;
case OpenACCClauseKind::Attach:
case OpenACCClauseKind::DevicePtr:
// TODO: ERICH: Figure out how to limit to just ptrs?
ParsedClause.setVarListDetails(ParseOpenACCVarList(),
/*IsReadOnly=*/false, /*IsZero=*/false);
break;
Expand Down Expand Up @@ -1048,8 +1047,8 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams(
return OpenACCCannotContinue();

} else if (ClauseHasOptionalParens(DirKind, ClauseKind)) {
ParsedClause.setLParenLoc(getCurToken().getLocation());
if (!Parens.consumeOpen()) {
ParsedClause.setLParenLoc(Parens.getOpenLocation());
switch (ClauseKind) {
case OpenACCClauseKind::Self: {
assert(DirKind != OpenACCDirectiveKind::Update);
Expand Down Expand Up @@ -1099,19 +1098,29 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams(
return OpenACCCanContinue();
}
break;
case OpenACCClauseKind::Wait:
if (ParseOpenACCWaitArgument(ClauseLoc,
/*IsDirective=*/false)) {
case OpenACCClauseKind::Wait: {
OpenACCWaitParseInfo Info =
ParseOpenACCWaitArgument(ClauseLoc,
/*IsDirective=*/false);
if (Info.Failed) {
Parens.skipToEnd();
return OpenACCCanContinue();
}

ParsedClause.setWaitDetails(Info.DevNumExpr, Info.QueuesLoc,
std::move(Info.QueueIdExprs));
break;
}
default:
llvm_unreachable("Not an optional parens type?");
}
ParsedClause.setEndLoc(getCurToken().getLocation());
if (Parens.consumeClose())
return OpenACCCannotContinue();
} else {
// If we have optional parens, make sure we set the end-location to the
// clause, as we are a 'single token' clause.
ParsedClause.setEndLoc(ClauseLoc);
}
}
return OpenACCSuccess(
Expand All @@ -1135,7 +1144,9 @@ Parser::ParseOpenACCAsyncArgument(OpenACCDirectiveKind DK, OpenACCClauseKind CK,
/// In this section and throughout the specification, the term wait-argument
/// means:
/// [ devnum : int-expr : ] [ queues : ] async-argument-list
bool Parser::ParseOpenACCWaitArgument(SourceLocation Loc, bool IsDirective) {
Parser::OpenACCWaitParseInfo
Parser::ParseOpenACCWaitArgument(SourceLocation Loc, bool IsDirective) {
OpenACCWaitParseInfo Result;
// [devnum : int-expr : ]
if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::DevNum, Tok) &&
NextToken().is(tok::colon)) {
Expand All @@ -1149,18 +1160,25 @@ bool Parser::ParseOpenACCWaitArgument(SourceLocation Loc, bool IsDirective) {
: OpenACCDirectiveKind::Invalid,
IsDirective ? OpenACCClauseKind::Invalid : OpenACCClauseKind::Wait,
Loc);
if (Res.first.isInvalid() && Res.second == OpenACCParseCanContinue::Cannot)
return true;
if (Res.first.isInvalid() &&
Res.second == OpenACCParseCanContinue::Cannot) {
Result.Failed = true;
return Result;
}

if (ExpectAndConsume(tok::colon))
return true;
if (ExpectAndConsume(tok::colon)) {
Result.Failed = true;
return Result;
}

Result.DevNumExpr = Res.first.get();
}

// [ queues : ]
if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::Queues, Tok) &&
NextToken().is(tok::colon)) {
// Consume queues.
ConsumeToken();
Result.QueuesLoc = ConsumeToken();
// Consume colon.
ConsumeToken();
}
Expand All @@ -1172,8 +1190,10 @@ bool Parser::ParseOpenACCWaitArgument(SourceLocation Loc, bool IsDirective) {
bool FirstArg = true;
while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {
if (!FirstArg) {
if (ExpectAndConsume(tok::comma))
return true;
if (ExpectAndConsume(tok::comma)) {
Result.Failed = true;
return Result;
}
}
FirstArg = false;

Expand All @@ -1183,11 +1203,16 @@ bool Parser::ParseOpenACCWaitArgument(SourceLocation Loc, bool IsDirective) {
IsDirective ? OpenACCClauseKind::Invalid : OpenACCClauseKind::Wait,
Loc);

if (Res.first.isInvalid() && Res.second == OpenACCParseCanContinue::Cannot)
return true;
if (Res.first.isInvalid() &&
Res.second == OpenACCParseCanContinue::Cannot) {
Result.Failed = true;
return Result;
}

Result.QueueIdExprs.push_back(Res.first.get());
}

return false;
return Result;
}

ExprResult Parser::ParseOpenACCIDExpression() {
Expand Down Expand Up @@ -1356,7 +1381,7 @@ Parser::OpenACCDirectiveParseInfo Parser::ParseOpenACCDirective() {
break;
case OpenACCDirectiveKind::Wait:
// OpenACC has an optional paren-wrapped 'wait-argument'.
if (ParseOpenACCWaitArgument(StartLoc, /*IsDirective=*/true))
if (ParseOpenACCWaitArgument(StartLoc, /*IsDirective=*/true).Failed)
T.skipToEnd();
else
T.consumeClose();
Expand Down
9 changes: 4 additions & 5 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16574,11 +16574,10 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
std::string PrettySourceValue = toString(Value, 10);
std::string PrettyTargetValue = PrettyPrintInRange(Value, TargetRange);

S.DiagRuntimeBehavior(
E->getExprLoc(), E,
S.PDiag(diag::warn_impcast_integer_precision_constant)
<< PrettySourceValue << PrettyTargetValue << E->getType() << T
<< E->getSourceRange() << SourceRange(CC));
S.Diag(E->getExprLoc(),
S.PDiag(diag::warn_impcast_integer_precision_constant)
<< PrettySourceValue << PrettyTargetValue << E->getType()
<< T << E->getSourceRange() << SourceRange(CC));
return;
}
}
Expand Down
52 changes: 52 additions & 0 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7309,6 +7309,55 @@ static void handleHLSLSV_DispatchThreadIDAttr(Sema &S, Decl *D,
D->addAttr(::new (S.Context) HLSLSV_DispatchThreadIDAttr(S.Context, AL));
}

static void handleHLSLPackOffsetAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!isa<VarDecl>(D) || !isa<HLSLBufferDecl>(D->getDeclContext())) {
S.Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_ast_node)
<< AL << "shader constant in a constant buffer";
return;
}

uint32_t SubComponent;
if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(0), SubComponent))
return;
uint32_t Component;
if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(1), Component))
return;

QualType T = cast<VarDecl>(D)->getType().getCanonicalType();
// Check if T is an array or struct type.
// TODO: mark matrix type as aggregate type.
bool IsAggregateTy = (T->isArrayType() || T->isStructureType());

// Check Component is valid for T.
if (Component) {
unsigned Size = S.getASTContext().getTypeSize(T);
if (IsAggregateTy || Size > 128) {
S.Diag(AL.getLoc(), diag::err_hlsl_packoffset_cross_reg_boundary);
return;
} else {
// Make sure Component + sizeof(T) <= 4.
if ((Component * 32 + Size) > 128) {
S.Diag(AL.getLoc(), diag::err_hlsl_packoffset_cross_reg_boundary);
return;
}
QualType EltTy = T;
if (const auto *VT = T->getAs<VectorType>())
EltTy = VT->getElementType();
unsigned Align = S.getASTContext().getTypeAlign(EltTy);
if (Align > 32 && Component == 1) {
// NOTE: Component 3 will hit err_hlsl_packoffset_cross_reg_boundary.
// So we only need to check Component 1 here.
S.Diag(AL.getLoc(), diag::err_hlsl_packoffset_alignment_mismatch)
<< Align << EltTy;
return;
}
}
}

D->addAttr(::new (S.Context)
HLSLPackOffsetAttr(S.Context, AL, SubComponent, Component));
}

static void handleHLSLShaderAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
StringRef Str;
SourceLocation ArgLoc;
Expand Down Expand Up @@ -9730,6 +9779,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
case ParsedAttr::AT_HLSLSV_DispatchThreadID:
handleHLSLSV_DispatchThreadIDAttr(S, D, AL);
break;
case ParsedAttr::AT_HLSLPackOffset:
handleHLSLPackOffsetAttr(S, D, AL);
break;
case ParsedAttr::AT_HLSLShader:
handleHLSLShaderAttr(S, D, AL);
break;
Expand Down
53 changes: 29 additions & 24 deletions clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18553,15 +18553,6 @@ void Sema::ActOnPureSpecifier(Decl *D, SourceLocation ZeroLoc) {
Diag(D->getLocation(), diag::err_illegal_initializer);
}

/// Determine whether the given declaration is a global variable or
/// static data member.
static bool isNonlocalVariable(const Decl *D) {
if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(D))
return Var->hasGlobalStorage();

return false;
}

/// Invoked when we are about to parse an initializer for the declaration
/// 'Dcl'.
///
Expand All @@ -18570,9 +18561,7 @@ static bool isNonlocalVariable(const Decl *D) {
/// class X. If the declaration had a scope specifier, a scope will have
/// been created and passed in for this purpose. Otherwise, S will be null.
void Sema::ActOnCXXEnterDeclInitializer(Scope *S, Decl *D) {
// If there is no declaration, there was an error parsing it.
if (!D || D->isInvalidDecl())
return;
assert(D && !D->isInvalidDecl());

// We will always have a nested name specifier here, but this declaration
// might not be out of line if the specifier names the current namespace:
Expand All @@ -18581,25 +18570,41 @@ void Sema::ActOnCXXEnterDeclInitializer(Scope *S, Decl *D) {
if (S && D->isOutOfLine())
EnterDeclaratorContext(S, D->getDeclContext());

// If we are parsing the initializer for a static data member, push a
// new expression evaluation context that is associated with this static
// data member.
if (isNonlocalVariable(D))
PushExpressionEvaluationContext(
ExpressionEvaluationContext::PotentiallyEvaluated, D);
PushExpressionEvaluationContext(
ExpressionEvaluationContext::PotentiallyEvaluated, D);
}

/// Invoked after we are finished parsing an initializer for the declaration D.
void Sema::ActOnCXXExitDeclInitializer(Scope *S, Decl *D) {
// If there is no declaration, there was an error parsing it.
if (!D || D->isInvalidDecl())
return;

if (isNonlocalVariable(D))
PopExpressionEvaluationContext();
assert(D);

if (S && D->isOutOfLine())
ExitDeclaratorContext(S);

if (getLangOpts().CPlusPlus23) {
// An expression or conversion is 'manifestly constant-evaluated' if it is:
// [...]
// - the initializer of a variable that is usable in constant expressions or
// has constant initialization.
if (auto *VD = dyn_cast<VarDecl>(D);
VD && (VD->isUsableInConstantExpressions(Context) ||
VD->hasConstantInitialization())) {
// An expression or conversion is in an 'immediate function context' if it
// is potentially evaluated and either:
// [...]
// - it is a subexpression of a manifestly constant-evaluated expression
// or conversion.
ExprEvalContexts.back().InImmediateFunctionContext = true;
}
}

// Unless the initializer is in an immediate function context (as determined
// above), this will evaluate all contained immediate function calls as
// constant expressions. If the initializer IS an immediate function context,
// the initializer has been determined to be a constant expression, and all
// such evaluations will be elided (i.e., as if we "knew the whole time" that
// it was a constant expression).
PopExpressionEvaluationContext();
}

/// ActOnCXXConditionDeclarationExpr - Parsed a condition declaration of a
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18039,7 +18039,7 @@ HandleImmediateInvocations(Sema &SemaRef,
Sema::ExpressionEvaluationContextRecord &Rec) {
if ((Rec.ImmediateInvocationCandidates.size() == 0 &&
Rec.ReferenceToConsteval.size() == 0) ||
SemaRef.RebuildingImmediateInvocation)
Rec.isImmediateFunctionContext() || SemaRef.RebuildingImmediateInvocation)
return;

/// When we have more than 1 ImmediateInvocationCandidates or previously
Expand Down
5 changes: 4 additions & 1 deletion clang/lib/Sema/SemaExprMember.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -996,7 +996,10 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
// build a CXXDependentScopeMemberExpr.
if (R.wasNotFoundInCurrentInstantiation() ||
(IsArrow && !BaseExprType->isPointerType() &&
BaseExprType->isDependentType()))
BaseExprType->isDependentType()) ||
(R.getLookupName().getCXXOverloadedOperator() == OO_Equal &&
(SS.isSet() ? SS.getScopeRep()->isDependent()
: BaseExprType->isDependentType())))
return ActOnDependentMemberExpr(BaseExpr, BaseExprType, IsArrow, OpLoc, SS,
TemplateKWLoc, FirstQualifierInScope,
R.getLookupNameInfo(), TemplateArgs);
Expand Down
80 changes: 80 additions & 0 deletions clang/lib/Sema/SemaHLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,89 @@ Decl *SemaHLSL::ActOnStartBuffer(Scope *BufferScope, bool CBuffer,
return Result;
}

// Calculate the size of a legacy cbuffer type based on
// https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-packing-rules
static unsigned calculateLegacyCbufferSize(const ASTContext &Context,
QualType T) {
unsigned Size = 0;
constexpr unsigned CBufferAlign = 128;
if (const RecordType *RT = T->getAs<RecordType>()) {
const RecordDecl *RD = RT->getDecl();
for (const FieldDecl *Field : RD->fields()) {
QualType Ty = Field->getType();
unsigned FieldSize = calculateLegacyCbufferSize(Context, Ty);
unsigned FieldAlign = 32;
if (Ty->isAggregateType())
FieldAlign = CBufferAlign;
Size = llvm::alignTo(Size, FieldAlign);
Size += FieldSize;
}
} else if (const ConstantArrayType *AT = Context.getAsConstantArrayType(T)) {
if (unsigned ElementCount = AT->getSize().getZExtValue()) {
unsigned ElementSize =
calculateLegacyCbufferSize(Context, AT->getElementType());
unsigned AlignedElementSize = llvm::alignTo(ElementSize, CBufferAlign);
Size = AlignedElementSize * (ElementCount - 1) + ElementSize;
}
} else if (const VectorType *VT = T->getAs<VectorType>()) {
unsigned ElementCount = VT->getNumElements();
unsigned ElementSize =
calculateLegacyCbufferSize(Context, VT->getElementType());
Size = ElementSize * ElementCount;
} else {
Size = Context.getTypeSize(T);
}
return Size;
}

void SemaHLSL::ActOnFinishBuffer(Decl *Dcl, SourceLocation RBrace) {
auto *BufDecl = cast<HLSLBufferDecl>(Dcl);
BufDecl->setRBraceLoc(RBrace);

// Validate packoffset.
llvm::SmallVector<std::pair<VarDecl *, HLSLPackOffsetAttr *>> PackOffsetVec;
bool HasPackOffset = false;
bool HasNonPackOffset = false;
for (auto *Field : BufDecl->decls()) {
VarDecl *Var = dyn_cast<VarDecl>(Field);
if (!Var)
continue;
if (Field->hasAttr<HLSLPackOffsetAttr>()) {
PackOffsetVec.emplace_back(Var, Field->getAttr<HLSLPackOffsetAttr>());
HasPackOffset = true;
} else {
HasNonPackOffset = true;
}
}

if (HasPackOffset && HasNonPackOffset)
Diag(BufDecl->getLocation(), diag::warn_hlsl_packoffset_mix);

if (HasPackOffset) {
ASTContext &Context = getASTContext();
// Make sure no overlap in packoffset.
// Sort PackOffsetVec by offset.
std::sort(PackOffsetVec.begin(), PackOffsetVec.end(),
[](const std::pair<VarDecl *, HLSLPackOffsetAttr *> &LHS,
const std::pair<VarDecl *, HLSLPackOffsetAttr *> &RHS) {
return LHS.second->getOffset() < RHS.second->getOffset();
});

for (unsigned i = 0; i < PackOffsetVec.size() - 1; i++) {
VarDecl *Var = PackOffsetVec[i].first;
HLSLPackOffsetAttr *Attr = PackOffsetVec[i].second;
unsigned Size = calculateLegacyCbufferSize(Context, Var->getType());
unsigned Begin = Attr->getOffset() * 32;
unsigned End = Begin + Size;
unsigned NextBegin = PackOffsetVec[i + 1].second->getOffset() * 32;
if (End > NextBegin) {
VarDecl *NextVar = PackOffsetVec[i + 1].first;
Diag(NextVar->getLocation(), diag::err_hlsl_packoffset_overlap)
<< NextVar << Var;
}
}
}

SemaRef.PopDeclContext();
}

Expand Down
28 changes: 8 additions & 20 deletions clang/lib/Sema/SemaLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1282,6 +1282,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
if (DeclContext *DC = PreS->getEntity())
DeclareImplicitMemberFunctionsWithName(*this, Name, R.getNameLoc(), DC);
}

// C++23 [temp.dep.general]p2:
// The component name of an unqualified-id is dependent if
// - it is a conversion-function-id whose conversion-type-id
Expand All @@ -1294,21 +1295,6 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
return false;
}

// If this is the name of an implicitly-declared special member function,
// go through the scope stack to implicitly declare
if (isImplicitlyDeclaredMemberFunctionName(Name)) {
for (Scope *PreS = S; PreS; PreS = PreS->getParent())
if (DeclContext *DC = PreS->getEntity()) {
if (DC->isDependentContext() && isa<CXXRecordDecl>(DC) &&
Name.getCXXOverloadedOperator() == OO_Equal &&
!R.isTemplateNameLookup()) {
R.setNotFoundInCurrentInstantiation();
return false;
}
DeclareImplicitMemberFunctionsWithName(*this, Name, R.getNameLoc(), DC);
}
}

// Implicitly declare member functions with the name we're looking for, if in
// fact we are in a scope where it matters.

Expand Down Expand Up @@ -2472,8 +2458,10 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
}
} QL(LookupCtx);

bool TemplateNameLookup = R.isTemplateNameLookup();
CXXRecordDecl *LookupRec = dyn_cast<CXXRecordDecl>(LookupCtx);
// FIXME: Per [temp.dep.general]p2, an unqualified name is also dependent
// if it's a dependent conversion-function-id or operator= where the current
// class is a templated entity. This should be handled in LookupName.
if (!InUnqualifiedLookup && !R.isForRedeclaration()) {
// C++23 [temp.dep.type]p5:
// A qualified name is dependent if
Expand All @@ -2484,10 +2472,8 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
// is operator=, or
// - [...]
if (DeclarationName Name = R.getLookupName();
(Name.getNameKind() == DeclarationName::CXXConversionFunctionName &&
Name.getCXXNameType()->isDependentType()) ||
(Name.getCXXOverloadedOperator() == OO_Equal && LookupRec &&
LookupRec->isDependentContext() && !TemplateNameLookup)) {
Name.getNameKind() == DeclarationName::CXXConversionFunctionName &&
Name.getCXXNameType()->isDependentType()) {
R.setNotFoundInCurrentInstantiation();
return false;
}
Expand Down Expand Up @@ -2583,6 +2569,8 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
return true;
};

bool TemplateNameLookup = R.isTemplateNameLookup();

// Determine whether two sets of members contain the same members, as
// required by C++ [class.member.lookup]p6.
auto HasSameDeclarations = [&](DeclContext::lookup_iterator A,
Expand Down
28 changes: 28 additions & 0 deletions clang/lib/Sema/SemaOpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,22 @@ bool doesClauseApplyToDirective(OpenACCDirectiveKind DirectiveKind,
default:
return false;
}
case OpenACCClauseKind::Wait:
switch (DirectiveKind) {
case OpenACCDirectiveKind::Parallel:
case OpenACCDirectiveKind::Serial:
case OpenACCDirectiveKind::Kernels:
case OpenACCDirectiveKind::Data:
case OpenACCDirectiveKind::EnterData:
case OpenACCDirectiveKind::ExitData:
case OpenACCDirectiveKind::Update:
case OpenACCDirectiveKind::ParallelLoop:
case OpenACCDirectiveKind::SerialLoop:
case OpenACCDirectiveKind::KernelsLoop:
return true;
default:
return false;
}

default:
// Do nothing so we can go to the 'unimplemented' diagnostic instead.
Expand Down Expand Up @@ -623,6 +639,18 @@ SemaOpenACC::ActOnClause(ArrayRef<const OpenACCClause *> ExistingClauses,
getASTContext(), Clause.getBeginLoc(), Clause.getLParenLoc(),
Clause.getVarList(), Clause.getEndLoc());
}
case OpenACCClauseKind::Wait: {
// Restrictions only properly implemented on 'compute' constructs, and
// 'compute' constructs are the only construct that can do anything with
// this yet, so skip/treat as unimplemented in this case.
if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
break;

return OpenACCWaitClause::Create(
getASTContext(), Clause.getBeginLoc(), Clause.getLParenLoc(),
Clause.getDevNumExpr(), Clause.getQueuesLoc(), Clause.getQueueIdExprs(),
Clause.getEndLoc());
}
default:
break;
}
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -750,7 +750,8 @@ Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS,
if (!MightBeCxx11UnevalField && !isAddressOfOperand && !IsEnum &&
isa<CXXMethodDecl>(DC) &&
cast<CXXMethodDecl>(DC)->isImplicitObjectMemberFunction()) {
QualType ThisType = cast<CXXMethodDecl>(DC)->getThisType().getNonReferenceType();
QualType ThisType =
cast<CXXMethodDecl>(DC)->getThisType().getNonReferenceType();

// Since the 'this' expression is synthesized, we don't need to
// perform the double-lookup check.
Expand Down
45 changes: 45 additions & 0 deletions clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -11425,6 +11425,51 @@ void OpenACCClauseTransform<Derived>::VisitAsyncClause(
: nullptr,
ParsedClause.getEndLoc());
}
template <typename Derived>
void OpenACCClauseTransform<Derived>::VisitWaitClause(
const OpenACCWaitClause &C) {
if (!C.getLParenLoc().isInvalid()) {
Expr *DevNumExpr = nullptr;
llvm::SmallVector<Expr *> InstantiatedQueueIdExprs;

// Instantiate devnum expr if it exists.
if (C.getDevNumExpr()) {
ExprResult Res = Self.TransformExpr(C.getDevNumExpr());
if (!Res.isUsable())
return;
Res = Self.getSema().OpenACC().ActOnIntExpr(OpenACCDirectiveKind::Invalid,
C.getClauseKind(),
C.getBeginLoc(), Res.get());
if (!Res.isUsable())
return;

DevNumExpr = Res.get();
}

// Instantiate queue ids.
for (Expr *CurQueueIdExpr : C.getQueueIdExprs()) {
ExprResult Res = Self.TransformExpr(CurQueueIdExpr);
if (!Res.isUsable())
return;
Res = Self.getSema().OpenACC().ActOnIntExpr(OpenACCDirectiveKind::Invalid,
C.getClauseKind(),
C.getBeginLoc(), Res.get());
if (!Res.isUsable())
return;

InstantiatedQueueIdExprs.push_back(Res.get());
}

ParsedClause.setWaitDetails(DevNumExpr, C.getQueuesLoc(),
std::move(InstantiatedQueueIdExprs));
}

NewClause = OpenACCWaitClause::Create(
Self.getSema().getASTContext(), ParsedClause.getBeginLoc(),
ParsedClause.getLParenLoc(), ParsedClause.getDevNumExpr(),
ParsedClause.getQueuesLoc(), ParsedClause.getQueueIdExprs(),
ParsedClause.getEndLoc());
}
} // namespace
template <typename Derived>
OpenACCClause *TreeTransform<Derived>::TransformOpenACCClause(
Expand Down
18 changes: 17 additions & 1 deletion clang/lib/Serialization/ASTReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11766,6 +11766,14 @@ SmallVector<Expr *> ASTRecordReader::readOpenACCVarList() {
return VarList;
}

SmallVector<Expr *> ASTRecordReader::readOpenACCIntExprList() {
unsigned NumExprs = readInt();
llvm::SmallVector<Expr *> ExprList;
for (unsigned I = 0; I < NumExprs; ++I)
ExprList.push_back(readSubExpr());
return ExprList;
}

OpenACCClause *ASTRecordReader::readOpenACCClause() {
OpenACCClauseKind ClauseKind = readEnum<OpenACCClauseKind>();
SourceLocation BeginLoc = readSourceLocation();
Expand Down Expand Up @@ -11888,6 +11896,15 @@ OpenACCClause *ASTRecordReader::readOpenACCClause() {
return OpenACCAsyncClause::Create(getContext(), BeginLoc, LParenLoc,
AsyncExpr, EndLoc);
}
case OpenACCClauseKind::Wait: {
SourceLocation LParenLoc = readSourceLocation();
Expr *DevNumExpr = readBool() ? readSubExpr() : nullptr;
SourceLocation QueuesLoc = readSourceLocation();
llvm::SmallVector<Expr *> QueueIdExprs = readOpenACCIntExprList();
return OpenACCWaitClause::Create(getContext(), BeginLoc, LParenLoc,
DevNumExpr, QueuesLoc, QueueIdExprs,
EndLoc);
}

case OpenACCClauseKind::Finalize:
case OpenACCClauseKind::IfPresent:
Expand All @@ -11913,7 +11930,6 @@ OpenACCClause *ASTRecordReader::readOpenACCClause() {
case OpenACCClauseKind::DType:
case OpenACCClauseKind::Tile:
case OpenACCClauseKind::Gang:
case OpenACCClauseKind::Wait:
case OpenACCClauseKind::Invalid:
llvm_unreachable("Clause serialization not yet implemented");
}
Expand Down
18 changes: 17 additions & 1 deletion clang/lib/Serialization/ASTWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7791,6 +7791,12 @@ void ASTRecordWriter::writeOpenACCVarList(const OpenACCClauseWithVarList *C) {
AddStmt(E);
}

void ASTRecordWriter::writeOpenACCIntExprList(ArrayRef<Expr *> Exprs) {
writeUInt32(Exprs.size());
for (Expr *E : Exprs)
AddStmt(E);
}

void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) {
writeEnum(C->getClauseKind());
writeSourceLocation(C->getBeginLoc());
Expand Down Expand Up @@ -7916,6 +7922,17 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) {
AddStmt(const_cast<Expr *>(AC->getIntExpr()));
return;
}
case OpenACCClauseKind::Wait: {
const auto *WC = cast<OpenACCWaitClause>(C);
writeSourceLocation(WC->getLParenLoc());
writeBool(WC->getDevNumExpr());
if (const Expr *DNE = WC->getDevNumExpr())
AddStmt(const_cast<Expr *>(DNE));
writeSourceLocation(WC->getQueuesLoc());

writeOpenACCIntExprList(WC->getQueueIdExprs());
return;
}

case OpenACCClauseKind::Finalize:
case OpenACCClauseKind::IfPresent:
Expand All @@ -7941,7 +7958,6 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) {
case OpenACCClauseKind::DType:
case OpenACCClauseKind::Tile:
case OpenACCClauseKind::Gang:
case OpenACCClauseKind::Wait:
case OpenACCClauseKind::Invalid:
llvm_unreachable("Clause serialization not yet implemented");
}
Expand Down
19 changes: 15 additions & 4 deletions clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3451,7 +3451,7 @@ static bool isReferenceCountingPointerDestructor(const CXXDestructorDecl *DD) {
if (N.contains_insensitive("ptr") || N.contains_insensitive("pointer")) {
if (N.contains_insensitive("ref") || N.contains_insensitive("cnt") ||
N.contains_insensitive("intrusive") ||
N.contains_insensitive("shared")) {
N.contains_insensitive("shared") || N.ends_with_insensitive("rc")) {
return true;
}
}
Expand Down Expand Up @@ -3483,13 +3483,24 @@ PathDiagnosticPieceRef MallocBugVisitor::VisitNode(const ExplodedNode *N,
// original reference count is positive, we should not report use-after-frees
// on objects deleted in such destructors. This can probably be improved
// through better shared pointer modeling.
if (ReleaseDestructorLC) {
if (ReleaseDestructorLC && (ReleaseDestructorLC == CurrentLC ||
ReleaseDestructorLC->isParentOf(CurrentLC))) {
if (const auto *AE = dyn_cast<AtomicExpr>(S)) {
// Check for manual use of atomic builtins.
AtomicExpr::AtomicOp Op = AE->getOp();
if (Op == AtomicExpr::AO__c11_atomic_fetch_add ||
Op == AtomicExpr::AO__c11_atomic_fetch_sub) {
if (ReleaseDestructorLC == CurrentLC ||
ReleaseDestructorLC->isParentOf(CurrentLC)) {
BR.markInvalid(getTag(), S);
}
} else if (const auto *CE = dyn_cast<CallExpr>(S)) {
// Check for `std::atomic` and such. This covers both regular method calls
// and operator calls.
if (const auto *MD =
dyn_cast_or_null<CXXMethodDecl>(CE->getDirectCallee())) {
const CXXRecordDecl *RD = MD->getParent();
// A bit wobbly with ".contains()" because it may be like
// "__atomic_base" or something.
if (StringRef(RD->getNameAsString()).contains("atomic")) {
BR.markInvalid(getTag(), S);
}
}
Expand Down
23 changes: 15 additions & 8 deletions clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@

namespace clang {

std::pair<const Expr *, bool>
tryToFindPtrOrigin(const Expr *E, bool StopAtFirstRefCountedObj) {
bool tryToFindPtrOrigin(
const Expr *E, bool StopAtFirstRefCountedObj,
std::function<bool(const clang::Expr *, bool)> callback) {
while (E) {
if (auto *tempExpr = dyn_cast<MaterializeTemporaryExpr>(E)) {
E = tempExpr->getSubExpr();
Expand All @@ -31,12 +32,18 @@ tryToFindPtrOrigin(const Expr *E, bool StopAtFirstRefCountedObj) {
E = tempExpr->getSubExpr();
continue;
}
if (auto *Expr = dyn_cast<ConditionalOperator>(E)) {
return tryToFindPtrOrigin(Expr->getTrueExpr(), StopAtFirstRefCountedObj,
callback) &&
tryToFindPtrOrigin(Expr->getFalseExpr(), StopAtFirstRefCountedObj,
callback);
}
if (auto *cast = dyn_cast<CastExpr>(E)) {
if (StopAtFirstRefCountedObj) {
if (auto *ConversionFunc =
dyn_cast_or_null<FunctionDecl>(cast->getConversionFunction())) {
if (isCtorOfRefCounted(ConversionFunc))
return {E, true};
return callback(E, true);
}
}
// FIXME: This can give false "origin" that would lead to false negatives
Expand All @@ -51,7 +58,7 @@ tryToFindPtrOrigin(const Expr *E, bool StopAtFirstRefCountedObj) {
if (IsGetterOfRefCt && *IsGetterOfRefCt) {
E = memberCall->getImplicitObjectArgument();
if (StopAtFirstRefCountedObj) {
return {E, true};
return callback(E, true);
}
continue;
}
Expand All @@ -68,17 +75,17 @@ tryToFindPtrOrigin(const Expr *E, bool StopAtFirstRefCountedObj) {
if (auto *callee = call->getDirectCallee()) {
if (isCtorOfRefCounted(callee)) {
if (StopAtFirstRefCountedObj)
return {E, true};
return callback(E, true);

E = call->getArg(0);
continue;
}

if (isReturnValueRefCounted(callee))
return {E, true};
return callback(E, true);

if (isSingleton(callee))
return {E, true};
return callback(E, true);

if (isPtrConversion(callee)) {
E = call->getArg(0);
Expand All @@ -95,7 +102,7 @@ tryToFindPtrOrigin(const Expr *E, bool StopAtFirstRefCountedObj) {
break;
}
// Some other expression.
return {E, false};
return callback(E, false);
}

bool isASafeCallArg(const Expr *E) {
Expand Down
11 changes: 7 additions & 4 deletions clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "llvm/ADT/APInt.h"
#include "llvm/Support/Casting.h"

#include <functional>
#include <string>
#include <utility>

Expand Down Expand Up @@ -48,10 +49,12 @@ class Expr;
/// represents ref-counted object during the traversal we return relevant
/// sub-expression and true.
///
/// \returns subexpression that we traversed to and if \p
/// StopAtFirstRefCountedObj is true we also return whether we stopped early.
std::pair<const clang::Expr *, bool>
tryToFindPtrOrigin(const clang::Expr *E, bool StopAtFirstRefCountedObj);
/// Calls \p callback with the subexpression that we traversed to and if \p
/// StopAtFirstRefCountedObj is true we also specify whether we stopped early.
/// Returns false if any of calls to callbacks returned false. Otherwise true.
bool tryToFindPtrOrigin(
const clang::Expr *E, bool StopAtFirstRefCountedObj,
std::function<bool(const clang::Expr *, bool)> callback);

/// For \p E referring to a ref-countable/-counted pointer/reference we return
/// whether it's a safe call argument. Examples: function parameter or
Expand Down
29 changes: 13 additions & 16 deletions clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -309,21 +309,8 @@ class TrivialFunctionAnalysisVisitor
bool VisitDefaultStmt(const DefaultStmt *DS) { return VisitChildren(DS); }

bool VisitUnaryOperator(const UnaryOperator *UO) {
// Operator '*' and '!' are allowed as long as the operand is trivial.
auto op = UO->getOpcode();
if (op == UO_Deref || op == UO_AddrOf || op == UO_LNot || op == UO_Not)
return Visit(UO->getSubExpr());

if (UO->isIncrementOp() || UO->isDecrementOp()) {
// Allow increment or decrement of a POD type.
if (auto *RefExpr = dyn_cast<DeclRefExpr>(UO->getSubExpr())) {
if (auto *Decl = dyn_cast<VarDecl>(RefExpr->getDecl()))
return Decl->isLocalVarDeclOrParm() &&
Decl->getType().isPODType(Decl->getASTContext());
}
}
// Other operators are non-trivial.
return false;
// Unary operators are trivial if its operand is trivial except co_await.
return UO->getOpcode() != UO_Coawait && Visit(UO->getSubExpr());
}

bool VisitBinaryOperator(const BinaryOperator *BO) {
Expand Down Expand Up @@ -364,7 +351,7 @@ class TrivialFunctionAnalysisVisitor

if (Name == "WTFCrashWithInfo" || Name == "WTFBreakpointTrap" ||
Name == "WTFReportAssertionFailure" ||
Name == "compilerFenceForCrash" || Name == "__builtin_unreachable")
Name == "compilerFenceForCrash" || Name.find("__builtin") == 0)
return true;

return TrivialFunctionAnalysis::isTrivialImpl(Callee, Cache);
Expand Down Expand Up @@ -405,6 +392,16 @@ class TrivialFunctionAnalysisVisitor
return TrivialFunctionAnalysis::isTrivialImpl(Callee, Cache);
}

bool VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *OCE) {
if (!checkArguments(OCE))
return false;
auto *Callee = OCE->getCalleeDecl();
if (!Callee)
return false;
// Recursively descend into the callee to confirm that it's trivial as well.
return TrivialFunctionAnalysis::isTrivialImpl(Callee, Cache);
}

bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E) {
if (auto *Expr = E->getExpr()) {
if (!Visit(Expr))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,25 +126,23 @@ class UncountedCallArgsChecker
}

bool isPtrOriginSafe(const Expr *Arg) const {
std::pair<const clang::Expr *, bool> ArgOrigin =
tryToFindPtrOrigin(Arg, true);

// Temporary ref-counted object created as part of the call argument
// would outlive the call.
if (ArgOrigin.second)
return true;

if (isa<CXXNullPtrLiteralExpr>(ArgOrigin.first)) {
// foo(nullptr)
return true;
}
if (isa<IntegerLiteral>(ArgOrigin.first)) {
// FIXME: Check the value.
// foo(NULL)
return true;
}

return isASafeCallArg(ArgOrigin.first);
return tryToFindPtrOrigin(Arg, /*StopAtFirstRefCountedObj=*/true,
[](const clang::Expr *ArgOrigin, bool IsSafe) {
if (IsSafe)
return true;
if (isa<CXXNullPtrLiteralExpr>(ArgOrigin)) {
// foo(nullptr)
return true;
}
if (isa<IntegerLiteral>(ArgOrigin)) {
// FIXME: Check the value.
// foo(NULL)
return true;
}
if (isASafeCallArg(ArgOrigin))
return true;
return false;
});
}

bool shouldSkipCall(const CallExpr *CE) const {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,39 +188,50 @@ class UncountedLocalVarsChecker
if (!InitExpr)
return; // FIXME: later on we might warn on uninitialized vars too

const clang::Expr *const InitArgOrigin =
tryToFindPtrOrigin(InitExpr, /*StopAtFirstRefCountedObj=*/false)
.first;
if (!InitArgOrigin)
if (tryToFindPtrOrigin(
InitExpr, /*StopAtFirstRefCountedObj=*/false,
[&](const clang::Expr *InitArgOrigin, bool IsSafe) {
if (!InitArgOrigin)
return true;

if (isa<CXXThisExpr>(InitArgOrigin))
return true;

if (isa<CXXNullPtrLiteralExpr>(InitArgOrigin))
return true;

if (isa<IntegerLiteral>(InitArgOrigin))
return true;

if (auto *Ref = llvm::dyn_cast<DeclRefExpr>(InitArgOrigin)) {
if (auto *MaybeGuardian =
dyn_cast_or_null<VarDecl>(Ref->getFoundDecl())) {
const auto *MaybeGuardianArgType =
MaybeGuardian->getType().getTypePtr();
if (MaybeGuardianArgType) {
const CXXRecordDecl *const MaybeGuardianArgCXXRecord =
MaybeGuardianArgType->getAsCXXRecordDecl();
if (MaybeGuardianArgCXXRecord) {
if (MaybeGuardian->isLocalVarDecl() &&
(isRefCounted(MaybeGuardianArgCXXRecord) ||
isRefcountedStringsHack(MaybeGuardian)) &&
isGuardedScopeEmbeddedInGuardianScope(
V, MaybeGuardian))
return true;
}
}

// Parameters are guaranteed to be safe for the duration of
// the call by another checker.
if (isa<ParmVarDecl>(MaybeGuardian))
return true;
}
}

return false;
}))
return;

if (isa<CXXThisExpr>(InitArgOrigin))
return;

if (auto *Ref = llvm::dyn_cast<DeclRefExpr>(InitArgOrigin)) {
if (auto *MaybeGuardian =
dyn_cast_or_null<VarDecl>(Ref->getFoundDecl())) {
const auto *MaybeGuardianArgType =
MaybeGuardian->getType().getTypePtr();
if (MaybeGuardianArgType) {
const CXXRecordDecl *const MaybeGuardianArgCXXRecord =
MaybeGuardianArgType->getAsCXXRecordDecl();
if (MaybeGuardianArgCXXRecord) {
if (MaybeGuardian->isLocalVarDecl() &&
(isRefCounted(MaybeGuardianArgCXXRecord) ||
isRefcountedStringsHack(MaybeGuardian)) &&
isGuardedScopeEmbeddedInGuardianScope(V, MaybeGuardian))
return;
}
}

// Parameters are guaranteed to be safe for the duration of the call
// by another checker.
if (isa<ParmVarDecl>(MaybeGuardian))
return;
}
}

reportBug(V);
}
}
Expand Down
100 changes: 100 additions & 0 deletions clang/test/AST/HLSL/packoffset.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// RUN: %clang_cc1 -triple dxil-unknown-shadermodel6.3-library -S -finclude-default-header -fnative-half-type -ast-dump -x hlsl %s | FileCheck %s


// CHECK: HLSLBufferDecl {{.*}} cbuffer A
cbuffer A
{
// CHECK-NEXT: VarDecl {{.*}} A1 'float4'
// CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 0 0
float4 A1 : packoffset(c);
// CHECK-NEXT: VarDecl {{.*}} col:11 A2 'float'
// CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 1 0
float A2 : packoffset(c1);
// CHECK-NEXT: VarDecl {{.*}} col:11 A3 'float'
// CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 1 1
float A3 : packoffset(c1.y);
}

// CHECK: HLSLBufferDecl {{.*}} cbuffer B
cbuffer B
{
// CHECK: VarDecl {{.*}} B0 'float'
// CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 0 1
float B0 : packoffset(c0.g);
// CHECK-NEXT: VarDecl {{.*}} B1 'double'
// CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 0 2
double B1 : packoffset(c0.b);
// CHECK-NEXT: VarDecl {{.*}} B2 'half'
// CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 0 0
half B2 : packoffset(c0.r);
}

// CHECK: HLSLBufferDecl {{.*}} cbuffer C
cbuffer C
{
// CHECK: VarDecl {{.*}} C0 'float'
// CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 1
float C0 : packoffset(c0.y);
// CHECK-NEXT: VarDecl {{.*}} C1 'float2'
// CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 2
float2 C1 : packoffset(c0.z);
// CHECK-NEXT: VarDecl {{.*}} C2 'half'
// CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 0
half C2 : packoffset(c0.x);
}


// CHECK: HLSLBufferDecl {{.*}} cbuffer D
cbuffer D
{
// CHECK: VarDecl {{.*}} D0 'float'
// CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 0 1
float D0 : packoffset(c0.y);
// CHECK-NEXT: VarDecl {{.*}} D1 'float[2]'
// CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 1 0
float D1[2] : packoffset(c1.x);
// CHECK-NEXT: VarDecl {{.*}} D2 'half3'
// CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 2 1
half3 D2 : packoffset(c2.y);
// CHECK-NEXT: VarDecl {{.*}} D3 'double'
// CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 0 2
double D3 : packoffset(c0.z);
}

struct ST {
float a;
float2 b;
half c;
};

// CHECK: HLSLBufferDecl {{.*}} cbuffer S
cbuffer S {
// CHECK: VarDecl {{.*}} S0 'float'
// CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 0 1
float S0 : packoffset(c0.y);
// CHECK: VarDecl {{.*}} S1 'ST'
// CHECK: HLSLPackOffsetAttr {{.*}} 1 0
ST S1 : packoffset(c1);
// CHECK: VarDecl {{.*}} S2 'double2'
// CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 2 0
double2 S2 : packoffset(c2);
}

struct ST2 {
float s0;
ST s1;
half s2;
};

// CHECK: HLSLBufferDecl {{.*}} cbuffer S2
cbuffer S2 {
// CHECK: VarDecl {{.*}} S20 'float'
// CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 0 3
float S20 : packoffset(c0.a);
// CHECK: VarDecl {{.*}} S21 'ST2'
// CHECK: HLSLPackOffsetAttr {{.*}} 1 0
ST2 S21 : packoffset(c1);
// CHECK: VarDecl {{.*}} S22 'half'
// CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 3 1
half S22 : packoffset(c3.y);
}
24 changes: 24 additions & 0 deletions clang/test/AST/ast-print-openacc-compute-construct.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,5 +83,29 @@ void foo() {
// CHECK: #pragma acc kernels async
#pragma acc kernels async
while(true);

// CHECK: #pragma acc parallel wait
#pragma acc parallel wait
while(true);

// CHECK: #pragma acc parallel wait()
#pragma acc parallel wait()
while(true);

// CHECK: #pragma acc parallel wait(*iPtr, i)
#pragma acc parallel wait(*iPtr, i)
while(true);

// CHECK: #pragma acc parallel wait(queues: *iPtr, i)
#pragma acc parallel wait(queues:*iPtr, i)
while(true);

// CHECK: #pragma acc parallel wait(devnum: i : *iPtr, i)
#pragma acc parallel wait(devnum:i:*iPtr, i)
while(true);

// CHECK: #pragma acc parallel wait(devnum: i : queues: *iPtr, i)
#pragma acc parallel wait(devnum:i:queues:*iPtr, i)
while(true);
}

14 changes: 14 additions & 0 deletions clang/test/Analysis/Checkers/WebKit/call-args.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -344,3 +344,17 @@ namespace cxx_member_operator_call {
// expected-warning@-1{{Call argument for parameter 'bad' is uncounted and unsafe}}
}
}

namespace call_with_ptr_on_ref {
Ref<RefCountable> provideProtected();
void bar(RefCountable* bad);
bool baz();
void foo(bool v) {
bar(v ? nullptr : provideProtected().ptr());
bar(baz() ? provideProtected().ptr() : nullptr);
bar(v ? provide() : provideProtected().ptr());
// expected-warning@-1{{Call argument for parameter 'bad' is uncounted and unsafe}}
bar(v ? provideProtected().ptr() : provide());
// expected-warning@-1{{Call argument for parameter 'bad' is uncounted and unsafe}}
}
}
18 changes: 18 additions & 0 deletions clang/test/Analysis/Checkers/WebKit/uncounted-local-vars.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,3 +198,21 @@ void system_header() {
}

} // ignore_system_headers

namespace conditional_op {
RefCountable *provide_ref_ctnbl();
bool bar();

void foo() {
RefCountable *a = bar() ? nullptr : provide_ref_ctnbl();
// expected-warning@-1{{Local variable 'a' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}}
RefPtr<RefCountable> b = provide_ref_ctnbl();
{
RefCountable* c = bar() ? nullptr : b.get();
c->method();
RefCountable* d = bar() ? b.get() : nullptr;
d->method();
}
}

} // namespace conditional_op
43 changes: 43 additions & 0 deletions clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,29 @@ class Number {
Number(int v) : v(v) { }
Number(double);
Number operator+(const Number&);
Number& operator++() { ++v; return *this; }
Number operator++(int) { Number returnValue(v); ++v; return returnValue; }
const int& value() const { return v; }
void someMethod();

private:
int v;
};

class ComplexNumber {
public:
ComplexNumber() : real(0), complex(0) { }
ComplexNumber(const ComplexNumber&);
ComplexNumber& operator++() { real.someMethod(); return *this; }
ComplexNumber operator++(int);
ComplexNumber& operator<<(int);
ComplexNumber& operator+();

private:
Number real;
Number complex;
};

class RefCounted {
public:
void ref() const;
Expand Down Expand Up @@ -210,6 +228,12 @@ class RefCounted {
unsigned trivial32() { return sizeof(int); }
unsigned trivial33() { return ~0xff; }
template <unsigned v> unsigned trivial34() { return v; }
void trivial35() { v++; }
void trivial36() { ++(*number); }
void trivial37() { (*number)++; }
void trivial38() { v++; if (__builtin_expect(!!(number), 1)) (*number)++; }
int trivial39() { return -v; }
int trivial40() { return v << 2; }

static RefCounted& singleton() {
static RefCounted s_RefCounted;
Expand Down Expand Up @@ -284,9 +308,14 @@ class RefCounted {

int nonTrivial13() { return ~otherFunction(); }
int nonTrivial14() { int r = 0xff; r |= otherFunction(); return r; }
void nonTrivial15() { ++complex; }
void nonTrivial16() { complex++; }
ComplexNumber nonTrivial17() { return complex << 2; }
ComplexNumber nonTrivial18() { return +complex; }

unsigned v { 0 };
Number* number { nullptr };
ComplexNumber complex;
Enum enumValue { Enum::Value1 };
};

Expand Down Expand Up @@ -342,6 +371,12 @@ class UnrelatedClass {
getFieldTrivial().trivial32(); // no-warning
getFieldTrivial().trivial33(); // no-warning
getFieldTrivial().trivial34<7>(); // no-warning
getFieldTrivial().trivial35(); // no-warning
getFieldTrivial().trivial36(); // no-warning
getFieldTrivial().trivial37(); // no-warning
getFieldTrivial().trivial38(); // no-warning
getFieldTrivial().trivial39(); // no-warning
getFieldTrivial().trivial40(); // no-warning

RefCounted::singleton().trivial18(); // no-warning
RefCounted::singleton().someFunction(); // no-warning
Expand Down Expand Up @@ -376,6 +411,14 @@ class UnrelatedClass {
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
getFieldTrivial().nonTrivial14();
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
getFieldTrivial().nonTrivial15();
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
getFieldTrivial().nonTrivial16();
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
getFieldTrivial().nonTrivial17();
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
getFieldTrivial().nonTrivial18();
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
}
};

Expand Down
7 changes: 7 additions & 0 deletions clang/test/Analysis/Inputs/system-header-simulator-cxx.h
Original file line number Diff line number Diff line change
Expand Up @@ -1260,6 +1260,13 @@ template<
iterator end() const { return iterator(val + 1); }
};

template <typename T>
class atomic {
public:
T operator++();
T operator--();
};

namespace execution {
class sequenced_policy {};
}
Expand Down
116 changes: 108 additions & 8 deletions clang/test/Analysis/NewDelete-atomics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ typedef enum memory_order {
memory_order_seq_cst = __ATOMIC_SEQ_CST
} memory_order;

class Obj {
class RawObj {
int RefCnt;

public:
Expand All @@ -37,11 +37,27 @@ class Obj {
void foo();
};

class StdAtomicObj {
std::atomic<int> RefCnt;

public:
int incRef() {
return ++RefCnt;
}

int decRef() {
return --RefCnt;
}

void foo();
};

template <typename T>
class IntrusivePtr {
Obj *Ptr;
T *Ptr;

public:
IntrusivePtr(Obj *Ptr) : Ptr(Ptr) {
IntrusivePtr(T *Ptr) : Ptr(Ptr) {
Ptr->incRef();
}

Expand All @@ -55,22 +71,106 @@ class IntrusivePtr {
delete Ptr;
}

Obj *getPtr() const { return Ptr; } // no-warning
T *getPtr() const { return Ptr; } // no-warning
};

// Also IntrusivePtr but let's dodge name-based heuristics.
template <typename T>
class DifferentlyNamed {
T *Ptr;

public:
DifferentlyNamed(T *Ptr) : Ptr(Ptr) {
Ptr->incRef();
}

DifferentlyNamed(const DifferentlyNamed &Other) : Ptr(Other.Ptr) {
Ptr->incRef();
}

~DifferentlyNamed() {
// We should not take the path on which the object is deleted.
if (Ptr->decRef() == 1)
delete Ptr;
}

T *getPtr() const { return Ptr; } // no-warning
};

void testDestroyLocalRefPtr() {
IntrusivePtr p1(new Obj());
IntrusivePtr<RawObj> p1(new RawObj());
{
IntrusivePtr<RawObj> p2(p1);
}

// p1 still maintains ownership. The object is not deleted.
p1.getPtr()->foo(); // no-warning
}

void testDestroySymbolicRefPtr(const IntrusivePtr<RawObj> &p1) {
{
IntrusivePtr<RawObj> p2(p1);
}

// p1 still maintains ownership. The object is not deleted.
p1.getPtr()->foo(); // no-warning
}

void testDestroyLocalRefPtrWithAtomics() {
IntrusivePtr<StdAtomicObj> p1(new StdAtomicObj());
{
IntrusivePtr<StdAtomicObj> p2(p1);
}

// p1 still maintains ownership. The object is not deleted.
p1.getPtr()->foo(); // no-warning
}


void testDestroyLocalRefPtrWithAtomics(const IntrusivePtr<StdAtomicObj> &p1) {
{
IntrusivePtr p2(p1);
IntrusivePtr<StdAtomicObj> p2(p1);
}

// p1 still maintains ownership. The object is not deleted.
p1.getPtr()->foo(); // no-warning
}

void testDestroySymbolicRefPtr(const IntrusivePtr &p1) {
void testDestroyLocalRefPtrDifferentlyNamed() {
DifferentlyNamed<RawObj> p1(new RawObj());
{
DifferentlyNamed<RawObj> p2(p1);
}

// p1 still maintains ownership. The object is not deleted.
p1.getPtr()->foo(); // no-warning
}

void testDestroySymbolicRefPtrDifferentlyNamed(
const DifferentlyNamed<RawObj> &p1) {
{
DifferentlyNamed<RawObj> p2(p1);
}

// p1 still maintains ownership. The object is not deleted.
p1.getPtr()->foo(); // no-warning
}

void testDestroyLocalRefPtrWithAtomicsDifferentlyNamed() {
DifferentlyNamed<StdAtomicObj> p1(new StdAtomicObj());
{
DifferentlyNamed<StdAtomicObj> p2(p1);
}

// p1 still maintains ownership. The object is not deleted.
p1.getPtr()->foo(); // no-warning
}


void testDestroyLocalRefPtrWithAtomicsDifferentlyNamed(
const DifferentlyNamed<StdAtomicObj> &p1) {
{
IntrusivePtr p2(p1);
DifferentlyNamed<StdAtomicObj> p2(p1);
}

// p1 still maintains ownership. The object is not deleted.
Expand Down
294 changes: 294 additions & 0 deletions clang/test/CXX/dcl/dcl.init/aggr.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,294 @@
// RUN: %clang_cc1 -std=c++2c -verify %s

namespace ex1 {
struct C {
union {
int a;
const char* p;
};
int x;
};

constexpr C c = { .a = 1, .x = 3 };
static_assert(c.a == 1);
static_assert(c.x == 3);

static constexpr C c2 = { .a = 1.0, .x = 3 };
// expected-error@-1 {{type 'double' cannot be narrowed to 'int' in initializer list}}
// expected-note@-2 {{insert an explicit cast to silence this issue}}
} // namespace ex1

namespace ex2 {
struct A {
int x;
struct B {
int i;
int j;
} b;
};

constexpr A a = { 1, { 2, 3 } };
static_assert(a.x == 1);
static_assert(a.b.i == 2);
static_assert(a.b.j == 3);

struct base1 { int b1, b2 = 42; };
struct base2 {
constexpr base2() {
b3 = 43;
}
int b3;
};
struct derived : base1, base2 {
int d;
};

constexpr derived d1{{1, 2}, {}, 4};
static_assert(d1.b1 == 1);
static_assert(d1.b2 == 2);
static_assert(d1.b3 == 43);
static_assert(d1.d == 4);

constexpr derived d2{{}, {}, 4};
static_assert(d2.b1 == 0);
static_assert(d2.b2 == 42);
static_assert(d2.b3 == 43);
static_assert(d2.d == 4);
} // namespace ex2

namespace ex3 {
struct S {
int a;
const char* b;
int c;
int d = b[a];
};

constexpr S ss = { 1, "asdf" };
static_assert(ss.a == 1);
static_assert(__builtin_strcmp(ss.b, "asdf") == 0);
static_assert(ss.c == int{});
static_assert(ss.d == ss.b[ss.a]);

struct string {
int d = 43;
};

struct A {
string a;
int b = 42;
int c = -1;
};

constexpr A a{.c = 21};
static_assert(a.a.d == string{}.d);
static_assert(a.b == 42);
static_assert(a.c == 21);
} // namespace ex3

namespace ex4 {
int x[] = { 1, 3, 5 };
static_assert(sizeof(x) / sizeof(int) == 3);
} // namespace ex4

namespace ex5 {
struct X { int i, j, k; };

constexpr X a[] = { 1, 2, 3, 4, 5, 6 };
constexpr X b[2] = { { 1, 2, 3 }, { 4, 5, 6 } };
static_assert(sizeof(a) == sizeof(b));
static_assert(a[0].i == b[0].i);
static_assert(a[0].j == b[0].j);
static_assert(a[0].k == b[0].k);
static_assert(a[1].i == b[1].i);
static_assert(a[1].j == b[1].j);
static_assert(a[1].k == b[1].k);
} // namespace ex5

namespace ex6 {
struct S {
int y[] = { 0 };
// expected-error@-1 {{array bound cannot be deduced from a default member initializer}}
};
} // namespace ex6

namespace ex7 {
struct A {
int i;
static int s;
int j;
int :17;
int k;
};

constexpr A a = { 1, 2, 3 };
static_assert(a.i == 1);
static_assert(a.j == 2);
static_assert(a.k == 3);
} // namespace ex7

namespace ex8 {
struct A;
extern A a;
struct A {
const A& a1 { A{a,a} };
const A& a2 { A{} };
// expected-error@-1 {{default member initializer for 'a2' needed within definition of enclosing class 'A' outside of member functions}}
// expected-note@-2 {{default member initializer declared here}}
};
A a{a,a};

struct B {
int n = B{}.n;
// expected-error@-1 {{default member initializer for 'n' needed within definition of enclosing class 'B' outside of member functions}}
// expected-note@-2 {{default member initializer declared here}}
};
} // namespace ex8

namespace ex9 {
constexpr int x[2][2] = { 3, 1, 4, 2 };
static_assert(x[0][0] == 3);
static_assert(x[0][1] == 1);
static_assert(x[1][0] == 4);
static_assert(x[1][1] == 2);

constexpr float y[4][3] = {
{ 1 }, { 2 }, { 3 }, { 4 }
};
static_assert(y[0][0] == 1);
static_assert(y[0][1] == 0);
static_assert(y[0][2] == 0);
static_assert(y[1][0] == 2);
static_assert(y[1][1] == 0);
static_assert(y[1][2] == 0);
static_assert(y[2][0] == 3);
static_assert(y[2][1] == 0);
static_assert(y[2][2] == 0);
static_assert(y[3][0] == 4);
static_assert(y[3][1] == 0);
static_assert(y[3][2] == 0);
} // namespace ex9

namespace ex10 {
struct S1 { int a, b; };
struct S2 { S1 s, t; };

constexpr S2 x[2] = { 1, 2, 3, 4, 5, 6, 7, 8 };
constexpr S2 y[2] = {
{
{ 1, 2 },
{ 3, 4 }
},
{
{ 5, 6 },
{ 7, 8 }
}
};
static_assert(x[0].s.a == 1);
static_assert(x[0].s.b == 2);
static_assert(x[0].t.a == 3);
static_assert(x[0].t.b == 4);
static_assert(x[1].s.a == 5);
static_assert(x[1].s.b == 6);
static_assert(x[1].t.a == 7);
static_assert(x[1].t.b == 8);
} // namespace ex10

namespace ex11 {
char cv[4] = { 'a', 's', 'd', 'f', 0 };
// expected-error@-1 {{excess elements in array initializer}}
} // namespace ex11

namespace ex12 {
constexpr float y[4][3] = {
{ 1, 3, 5 },
{ 2, 4, 6 },
{ 3, 5, 7 },
};
static_assert(y[0][0] == 1);
static_assert(y[0][1] == 3);
static_assert(y[0][2] == 5);
static_assert(y[1][0] == 2);
static_assert(y[1][1] == 4);
static_assert(y[1][2] == 6);
static_assert(y[2][0] == 3);
static_assert(y[2][1] == 5);
static_assert(y[2][2] == 7);
static_assert(y[3][0] == 0.0);
static_assert(y[3][1] == 0.0);
static_assert(y[3][2] == 0.0);

constexpr float z[4][3] = {
1, 3, 5, 2, 4, 6, 3, 5, 7
};
static_assert(z[0][0] == 1);
static_assert(z[0][1] == 3);
static_assert(z[0][2] == 5);
static_assert(z[1][0] == 2);
static_assert(z[1][1] == 4);
static_assert(z[1][2] == 6);
static_assert(z[2][0] == 3);
static_assert(z[2][1] == 5);
static_assert(z[2][2] == 7);
static_assert(z[3][0] == 0.0);
static_assert(z[3][1] == 0.0);
static_assert(z[3][2] == 0.0);
} // namespace ex12

namespace ex13 {
struct S { } s;
struct A {
S s1;
int i1;
S s2;
int i2;
S s3;
int i3;
} a = {
{ }, // Required initialization
0,
s, // Required initialization
0
}; // Initialization not required for A​::​s3 because A​::​i3 is also not initialized
} // namespace ex13

namespace ex14 {
struct A {
int i;
constexpr operator int() const { return 42; };
};
struct B {
A a1, a2;
int z;
};
constexpr A a{};
constexpr B b = { 4, a, a };
static_assert(b.a1.i == 4);
static_assert(b.a2.i == a.i);
static_assert(b.z == a.operator int());
} // namespace ex14

namespace ex15 {
union u { // #ex15-u
int a;
const char* b;
};

u a = { 1 };
u b = a;
u c = 1;
// expected-error@-1 {{no viable conversion from 'int' to 'u'}}
// expected-note@#ex15-u {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'int' to 'const u &' for 1st argument}}
// expected-note@#ex15-u {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'int' to 'u &&' for 1st argument}}
u d = { 0, "asdf" };
// expected-error@-1 {{excess elements in union initializer}}
u e = { "asdf" };
// expected-error@-1 {{cannot initialize a member subobject of type 'int' with an lvalue of type 'const char[5]'}}
u f = { .b = "asdf" };
u g = {
.a = 1, // #ex15-g-a
.b = "asdf"
// expected-error@-1 {{initializer partially overrides prior initialization of this subobject}}
// expected-note@#ex15-g-a {{previous initialization is here}}
};
} // namespace ex15
13 changes: 13 additions & 0 deletions clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,18 @@ namespace N3 {
this->C::operator=(*this);
}
};

template<typename T>
struct D {
auto not_instantiated() -> decltype(operator=(0)); // expected-error {{use of undeclared 'operator='}}
};

template<typename T>
struct E {
auto instantiated(E& e) -> decltype(operator=(e)); // expected-error {{use of undeclared 'operator='}}
};

template struct E<int>; // expected-note {{in instantiation of template class 'N3::E<int>' requested here}}
} // namespace N3

namespace N4 {
Expand Down Expand Up @@ -538,4 +550,5 @@ namespace N4 {
};

template void D<B>::instantiated(D); // expected-note {{in instantiation of}}

} // namespace N4
64 changes: 63 additions & 1 deletion clang/test/CodeGen/aapcs64-align.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// REQUIRES: arm-registered-target
// RUN: %clang_cc1 -triple aarch64-none-elf \
// RUN: -O2 \
// RUN: -emit-llvm -o - %s | FileCheck %s
// RUN: -emit-llvm -fexperimental-max-bitint-width=1024 -o - %s | FileCheck %s

extern "C" {

Expand Down Expand Up @@ -100,4 +100,66 @@ void f5m(int, int, int, int, int, P16);
// CHECK: declare void @f5(i32 noundef, [2 x i64])
// CHECK: declare void @f5m(i32 noundef, i32 noundef, i32 noundef, i32 noundef, i32 noundef, [2 x i64])

//BitInt alignment
struct BITINT129 {
char ch;
unsigned _BitInt(129) v;
};

int test_bitint129(){
return __builtin_offsetof(struct BITINT129, v);
}
// CHECK: ret i32 16

struct BITINT127 {
char ch;
_BitInt(127) v;
};

int test_bitint127(){
return __builtin_offsetof(struct BITINT127, v);
}
// CHECK: ret i32 16

struct BITINT63 {
char ch;
_BitInt(63) v;
};

int test_bitint63(){
return __builtin_offsetof(struct BITINT63, v);
}
// CHECK: ret i32 8

struct BITINT32 {
char ch;
unsigned _BitInt(32) v;
};

int test_bitint32(){
return __builtin_offsetof(struct BITINT32, v);
}
// CHECK: ret i32 4

struct BITINT9 {
char ch;
unsigned _BitInt(9) v;
};

int test_bitint9(){
return __builtin_offsetof(struct BITINT9, v);
}
// CHECK: ret i32 2

struct BITINT8 {
char ch;
unsigned _BitInt(8) v;
};

int test_bitint8(){
return __builtin_offsetof(struct BITINT8, v);
}
// CHECK: ret i32 1

}

Loading