585 changes: 585 additions & 0 deletions clang/docs/SafeBuffers.rst

Large diffs are not rendered by default.

17 changes: 14 additions & 3 deletions clang/docs/analyzer/checkers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3371,12 +3371,23 @@ Checks for overlap in two buffer arguments. Applies to: ``memcpy, mempcpy, wmem
alpha.unix.cstring.NotNullTerminated (C)
""""""""""""""""""""""""""""""""""""""""
Check for arguments which are not null-terminated strings; applies to: ``strlen, strnlen, strcpy, strncpy, strcat, strncat, wcslen, wcsnlen``.
Check for arguments which are not null-terminated strings;
applies to the ``strlen``, ``strcpy``, ``strcat``, ``strcmp`` family of functions.
Only very fundamental cases are detected where the passed memory block is
absolutely different from a null-terminated string. This checker does not
find if a memory buffer is passed where the terminating zero character
is missing.
.. code-block:: c
void test() {
int y = strlen((char *)&test); // warn
void test1() {
int l = strlen((char *)&test); // warn
}
void test2() {
label:
int l = strlen((char *)&&label); // warn
}
.. _alpha-unix-cstring-OutOfBounds:
Expand Down
1 change: 1 addition & 0 deletions clang/docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Using Clang as a Compiler
CrossCompilation
ClangStaticAnalyzer
ThreadSafetyAnalysis
SafeBuffers
DataFlowAnalysisIntro
AddressSanitizer
ThreadSanitizer
Expand Down
18 changes: 17 additions & 1 deletion clang/include/clang/AST/DeclTemplate.h
Original file line number Diff line number Diff line change
Expand Up @@ -2085,7 +2085,11 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl,
class ClassTemplatePartialSpecializationDecl
: public ClassTemplateSpecializationDecl {
/// The list of template parameters
TemplateParameterList* TemplateParams = nullptr;
TemplateParameterList *TemplateParams = nullptr;

/// The set of "injected" template arguments used within this
/// partial specialization.
TemplateArgument *InjectedArgs = nullptr;

/// The class template partial specialization from which this
/// class template partial specialization was instantiated.
Expand Down Expand Up @@ -2132,6 +2136,10 @@ class ClassTemplatePartialSpecializationDecl
return TemplateParams;
}

/// Retrieve the template arguments list of the template parameter list
/// of this template.
ArrayRef<TemplateArgument> getInjectedTemplateArgs();

/// \brief All associated constraints of this partial specialization,
/// including the requires clause and any constraints derived from
/// constrained-parameters.
Expand Down Expand Up @@ -2856,6 +2864,10 @@ class VarTemplatePartialSpecializationDecl
/// The list of template parameters
TemplateParameterList *TemplateParams = nullptr;

/// The set of "injected" template arguments used within this
/// partial specialization.
TemplateArgument *InjectedArgs = nullptr;

/// The variable template partial specialization from which this
/// variable template partial specialization was instantiated.
///
Expand Down Expand Up @@ -2902,6 +2914,10 @@ class VarTemplatePartialSpecializationDecl
return TemplateParams;
}

/// Retrieve the template arguments list of the template parameter list
/// of this template.
ArrayRef<TemplateArgument> getInjectedTemplateArgs();

/// \brief All associated constraints of this partial specialization,
/// including the requires clause and any constraints derived from
/// constrained-parameters.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
//===-- CachedConstAccessorsLattice.h ---------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file defines the lattice mixin that additionally maintains a cache of
// stable method call return values to model const accessor member functions.
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_CACHED_CONST_ACCESSORS_LATTICE_H
#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_CACHED_CONST_ACCESSORS_LATTICE_H

#include "clang/AST/Expr.h"
#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
#include "clang/Analysis/FlowSensitive/DataflowLattice.h"
#include "clang/Analysis/FlowSensitive/StorageLocation.h"
#include "clang/Analysis/FlowSensitive/Value.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLFunctionalExtras.h"

namespace clang {
namespace dataflow {

/// A mixin for a lattice that additionally maintains a cache of stable method
/// call return values to model const accessors methods. When a non-const method
/// is called, the cache should be cleared causing the next call to a const
/// method to be considered a different value. NOTE: The user is responsible for
/// clearing the cache.
///
/// For example:
///
/// class Bar {
/// public:
/// const std::optional<Foo>& getFoo() const;
/// void clear();
/// };
//
/// void func(Bar& s) {
/// if (s.getFoo().has_value()) {
/// use(s.getFoo().value()); // safe (checked earlier getFoo())
/// s.clear();
/// use(s.getFoo().value()); // unsafe (invalidate cache for s)
/// }
/// }
template <typename Base> class CachedConstAccessorsLattice : public Base {
public:
using Base::Base; // inherit all constructors

/// Creates or returns a previously created `Value` associated with a const
/// method call `obj.getFoo()` where `RecordLoc` is the
/// `RecordStorageLocation` of `obj`.
/// Returns nullptr if unable to find or create a value.
///
/// Requirements:
///
/// - `CE` should return a value (not a reference or record type)
Value *
getOrCreateConstMethodReturnValue(const RecordStorageLocation &RecordLoc,
const CallExpr *CE, Environment &Env);

/// Creates or returns a previously created `StorageLocation` associated with
/// a const method call `obj.getFoo()` where `RecordLoc` is the
/// `RecordStorageLocation` of `obj`.
///
/// The callback `Initialize` runs on the storage location if newly created.
/// Returns nullptr if unable to find or create a value.
///
/// Requirements:
///
/// - `CE` should return a location (GLValue or a record type).
StorageLocation *getOrCreateConstMethodReturnStorageLocation(
const RecordStorageLocation &RecordLoc, const CallExpr *CE,
Environment &Env, llvm::function_ref<void(StorageLocation &)> Initialize);

void clearConstMethodReturnValues(const RecordStorageLocation &RecordLoc) {
ConstMethodReturnValues.erase(&RecordLoc);
}

void clearConstMethodReturnStorageLocations(
const RecordStorageLocation &RecordLoc) {
ConstMethodReturnStorageLocations.erase(&RecordLoc);
}

bool operator==(const CachedConstAccessorsLattice &Other) const {
return Base::operator==(Other);
}

LatticeJoinEffect join(const CachedConstAccessorsLattice &Other);

private:
// Maps a record storage location and const method to the value to return
// from that const method.
using ConstMethodReturnValuesType =
llvm::SmallDenseMap<const RecordStorageLocation *,
llvm::SmallDenseMap<const FunctionDecl *, Value *>>;
ConstMethodReturnValuesType ConstMethodReturnValues;

// Maps a record storage location and const method to the record storage
// location to return from that const method.
using ConstMethodReturnStorageLocationsType = llvm::SmallDenseMap<
const RecordStorageLocation *,
llvm::SmallDenseMap<const FunctionDecl *, StorageLocation *>>;
ConstMethodReturnStorageLocationsType ConstMethodReturnStorageLocations;
};

namespace internal {

template <typename T>
llvm::SmallDenseMap<const RecordStorageLocation *,
llvm::SmallDenseMap<const FunctionDecl *, T *>>
joinConstMethodMap(
const llvm::SmallDenseMap<const RecordStorageLocation *,
llvm::SmallDenseMap<const FunctionDecl *, T *>>
&Map1,
const llvm::SmallDenseMap<const RecordStorageLocation *,
llvm::SmallDenseMap<const FunctionDecl *, T *>>
&Map2,
LatticeEffect &Effect) {
llvm::SmallDenseMap<const RecordStorageLocation *,
llvm::SmallDenseMap<const FunctionDecl *, T *>>
Result;
for (auto &[Loc, DeclToT] : Map1) {
auto It = Map2.find(Loc);
if (It == Map2.end()) {
Effect = LatticeJoinEffect::Changed;
continue;
}
const auto &OtherDeclToT = It->second;
auto &JoinedDeclToT = Result[Loc];
for (auto [Func, Var] : DeclToT) {
T *OtherVar = OtherDeclToT.lookup(Func);
if (OtherVar == nullptr || OtherVar != Var) {
Effect = LatticeJoinEffect::Changed;
continue;
}
JoinedDeclToT.insert({Func, Var});
}
}
return Result;
}

} // namespace internal

template <typename Base>
LatticeEffect CachedConstAccessorsLattice<Base>::join(
const CachedConstAccessorsLattice<Base> &Other) {

LatticeEffect Effect = Base::join(Other);

// For simplicity, we only retain values that are identical, but not ones that
// are non-identical but equivalent. This is likely to be sufficient in
// practice, and it reduces implementation complexity considerably.

ConstMethodReturnValues = internal::joinConstMethodMap<Value>(
ConstMethodReturnValues, Other.ConstMethodReturnValues, Effect);

ConstMethodReturnStorageLocations =
internal::joinConstMethodMap<StorageLocation>(
ConstMethodReturnStorageLocations,
Other.ConstMethodReturnStorageLocations, Effect);

return Effect;
}

template <typename Base>
Value *CachedConstAccessorsLattice<Base>::getOrCreateConstMethodReturnValue(
const RecordStorageLocation &RecordLoc, const CallExpr *CE,
Environment &Env) {
QualType Type = CE->getType();
assert(!Type.isNull());
assert(!Type->isReferenceType());
assert(!Type->isRecordType());

auto &ObjMap = ConstMethodReturnValues[&RecordLoc];
const FunctionDecl *DirectCallee = CE->getDirectCallee();
if (DirectCallee == nullptr)
return nullptr;
auto it = ObjMap.find(DirectCallee);
if (it != ObjMap.end())
return it->second;

Value *Val = Env.createValue(Type);
if (Val != nullptr)
ObjMap.insert({DirectCallee, Val});
return Val;
}

template <typename Base>
StorageLocation *
CachedConstAccessorsLattice<Base>::getOrCreateConstMethodReturnStorageLocation(
const RecordStorageLocation &RecordLoc, const CallExpr *CE,
Environment &Env, llvm::function_ref<void(StorageLocation &)> Initialize) {
assert(!CE->getType().isNull());
assert(CE->isGLValue() || CE->getType()->isRecordType());
auto &ObjMap = ConstMethodReturnStorageLocations[&RecordLoc];
const FunctionDecl *DirectCallee = CE->getDirectCallee();
if (DirectCallee == nullptr)
return nullptr;
auto it = ObjMap.find(DirectCallee);
if (it != ObjMap.end())
return it->second;

StorageLocation &Loc =
Env.createStorageLocation(CE->getType().getNonReferenceType());
Initialize(Loc);

ObjMap.insert({DirectCallee, &Loc});
return &Loc;
}

} // namespace dataflow
} // namespace clang

#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_CACHED_CONST_ACCESSORS_LATTICE_H
25 changes: 25 additions & 0 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -4593,6 +4593,31 @@ def HLSLResourceBinding: InheritableAttr {
let LangOpts = [HLSL];
let Args = [StringArgument<"Slot">, StringArgument<"Space", 1>];
let Documentation = [HLSLResourceBindingDocs];
let AdditionalMembers = [{
public:
enum class RegisterType : unsigned { SRV, UAV, CBuffer, Sampler, C, I };

private:
RegisterType RegType;
unsigned SlotNumber;
unsigned SpaceNumber;

public:
void setBinding(RegisterType RT, unsigned SlotNum, unsigned SpaceNum) {
RegType = RT;
SlotNumber = SlotNum;
SpaceNumber = SpaceNum;
}
RegisterType getRegisterType() const {
return RegType;
}
unsigned getSlotNumber() const {
return SlotNumber;
}
unsigned getSpaceNumber() const {
return SpaceNumber;
}
}];
}

def HLSLPackOffset: HLSLAnnotationAttr {
Expand Down
24 changes: 19 additions & 5 deletions clang/include/clang/CodeGen/CodeGenABITypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,25 @@ const CGFunctionInfo &arrangeCXXMethodType(CodeGenModule &CGM,
const FunctionProtoType *FTP,
const CXXMethodDecl *MD);

const CGFunctionInfo &arrangeFreeFunctionCall(CodeGenModule &CGM,
CanQualType returnType,
ArrayRef<CanQualType> argTypes,
FunctionType::ExtInfo info,
RequiredArgs args);
const CGFunctionInfo &
arrangeCXXMethodCall(CodeGenModule &CGM, CanQualType returnType,
ArrayRef<CanQualType> argTypes, FunctionType::ExtInfo info,
ArrayRef<FunctionProtoType::ExtParameterInfo> paramInfos,
RequiredArgs args);

const CGFunctionInfo &arrangeFreeFunctionCall(
CodeGenModule &CGM, CanQualType returnType, ArrayRef<CanQualType> argTypes,
FunctionType::ExtInfo info,
ArrayRef<FunctionProtoType::ExtParameterInfo> paramInfos,
RequiredArgs args);

// An overload with an empty `paramInfos`
inline const CGFunctionInfo &
arrangeFreeFunctionCall(CodeGenModule &CGM, CanQualType returnType,
ArrayRef<CanQualType> argTypes,
FunctionType::ExtInfo info, RequiredArgs args) {
return arrangeFreeFunctionCall(CGM, returnType, argTypes, info, {}, args);
}

/// Returns the implicit arguments to add to a complete, non-delegating C++
/// constructor call.
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -8531,7 +8531,7 @@ def _SLASH_execution_charset : CLCompileJoined<"execution-charset:">,
HelpText<"Set runtime encoding, supports only UTF-8">,
Alias<fexec_charset_EQ>;
def _SLASH_std : CLCompileJoined<"std:">,
HelpText<"Set language version (c++14,c++17,c++20,c++latest,c11,c17)">;
HelpText<"Set language version (c++14,c++17,c++20,c++23preview,c++latest,c11,c17)">;
def _SLASH_U : CLJoinedOrSeparate<"U">, HelpText<"Undefine macro">,
MetaVarName<"<macro>">, Alias<U>;
def _SLASH_validate_charset : CLFlag<"validate-charset">,
Expand Down
37 changes: 35 additions & 2 deletions clang/include/clang/ExtractAPI/API.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
#include "llvm/TargetParser/Triple.h"
#include <cstddef>
#include <iterator>
Expand Down Expand Up @@ -615,7 +616,24 @@ struct TagRecord : APIRecord, RecordContext {
return classofKind(Record->getKind());
}
static bool classofKind(RecordKind K) {
return K == RK_Struct || K == RK_Union || K == RK_Enum;
switch (K) {
case RK_Enum:
LLVM_FALLTHROUGH;
case RK_Struct:
LLVM_FALLTHROUGH;
case RK_Union:
LLVM_FALLTHROUGH;
case RK_CXXClass:
LLVM_FALLTHROUGH;
case RK_ClassTemplate:
LLVM_FALLTHROUGH;
case RK_ClassTemplateSpecialization:
LLVM_FALLTHROUGH;
case RK_ClassTemplatePartialSpecialization:
return true;
default:
return false;
}
}

bool IsEmbeddedInVarDeclarator;
Expand Down Expand Up @@ -684,7 +702,22 @@ struct RecordRecord : TagRecord {
return classofKind(Record->getKind());
}
static bool classofKind(RecordKind K) {
return K == RK_Struct || K == RK_Union;
switch (K) {
case RK_Struct:
LLVM_FALLTHROUGH;
case RK_Union:
LLVM_FALLTHROUGH;
case RK_CXXClass:
LLVM_FALLTHROUGH;
case RK_ClassTemplate:
LLVM_FALLTHROUGH;
case RK_ClassTemplateSpecialization:
LLVM_FALLTHROUGH;
case RK_ClassTemplatePartialSpecialization:
return true;
default:
return false;
}
}

bool isAnonymousWithNoTypedef() { return Name.empty(); }
Expand Down
57 changes: 57 additions & 0 deletions clang/include/clang/Sema/SemaHLSL.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,60 @@ class AttributeCommonInfo;
class IdentifierInfo;
class ParsedAttr;
class Scope;
class VarDecl;

using llvm::dxil::ResourceClass;

// FIXME: This can be hidden (as static function in SemaHLSL.cpp) once we no
// longer need to create builtin buffer types in HLSLExternalSemaSource.
bool CreateHLSLAttributedResourceType(
Sema &S, QualType Wrapped, ArrayRef<const Attr *> AttrList,
QualType &ResType, HLSLAttributedResourceLocInfo *LocInfo = nullptr);

enum class BindingType : uint8_t { NotAssigned, Explicit, Implicit };

// DeclBindingInfo struct stores information about required/assigned resource
// binding onon a declaration for specific resource class.
struct DeclBindingInfo {
const VarDecl *Decl;
ResourceClass ResClass;
const HLSLResourceBindingAttr *Attr;
BindingType BindType;

DeclBindingInfo(const VarDecl *Decl, ResourceClass ResClass,
BindingType BindType = BindingType::NotAssigned,
const HLSLResourceBindingAttr *Attr = nullptr)
: Decl(Decl), ResClass(ResClass), Attr(Attr), BindType(BindType) {}

void setBindingAttribute(HLSLResourceBindingAttr *A, BindingType BT) {
assert(Attr == nullptr && BindType == BindingType::NotAssigned &&
"binding attribute already assigned");
Attr = A;
BindType = BT;
}
};

// ResourceBindings class stores information about all resource bindings
// in a shader. It is used for binding diagnostics and implicit binding
// assigments.
class ResourceBindings {
public:
DeclBindingInfo *addDeclBindingInfo(const VarDecl *VD,
ResourceClass ResClass);
DeclBindingInfo *getDeclBindingInfo(const VarDecl *VD,
ResourceClass ResClass);
bool hasBindingInfoForDecl(const VarDecl *VD) const;

private:
// List of all resource bindings required by the shader.
// A global declaration can have multiple bindings for different
// resource classes. They are all stored sequentially in this list.
// The DeclToBindingListIndex hashtable maps a declaration to the
// index of the first binding info in the list.
llvm::SmallVector<DeclBindingInfo> BindingsList;
llvm::DenseMap<const VarDecl *, unsigned> DeclToBindingListIndex;
};

class SemaHLSL : public SemaBase {
public:
SemaHLSL(Sema &S);
Expand All @@ -55,6 +102,7 @@ class SemaHLSL : public SemaBase {
mergeParamModifierAttr(Decl *D, const AttributeCommonInfo &AL,
HLSLParamModifierAttr::Spelling Spelling);
void ActOnTopLevelFunction(FunctionDecl *FD);
void ActOnVariableDeclarator(VarDecl *VD);
void CheckEntryPoint(FunctionDecl *FD);
void CheckSemanticAnnotation(FunctionDecl *EntryPoint, const Decl *Param,
const HLSLAnnotationAttr *AnnotationAttr);
Expand Down Expand Up @@ -102,6 +150,15 @@ class SemaHLSL : public SemaBase {
llvm::DenseMap<const HLSLAttributedResourceType *,
HLSLAttributedResourceLocInfo>
LocsForHLSLAttributedResources;

// List of all resource bindings
ResourceBindings Bindings;

private:
void collectResourcesOnVarDecl(VarDecl *D);
void collectResourcesOnUserRecordDecl(const VarDecl *VD,
const RecordType *RT);
void processExplicitBindingsOnDecl(VarDecl *D);
};

} // namespace clang
Expand Down
13 changes: 6 additions & 7 deletions clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -299,13 +299,12 @@ ANALYZER_OPTION(

ANALYZER_OPTION(
bool, ShouldEagerlyAssume, "eagerly-assume",
"Whether we should eagerly assume evaluations of conditionals, thus, "
"bifurcating the path. This indicates how the engine should handle "
"expressions such as: 'x = (y != 0)'. When this is true then the "
"subexpression 'y != 0' will be eagerly assumed to be true or false, thus "
"evaluating it to the integers 0 or 1 respectively. The upside is that "
"this can increase analysis precision until we have a better way to lazily "
"evaluate such logic. The downside is that it eagerly bifurcates paths.",
"If this is enabled (the default behavior), when the analyzer encounters "
"a comparison operator or logical negation, it immediately splits the "
"state to separate the case when the expression is true and the case when "
"it's false. The upside is that this can increase analysis precision until "
"we have a better way to lazily evaluate such logic; the downside is that "
"it eagerly bifurcates paths.",
true)

ANALYZER_OPTION(
Expand Down
8 changes: 3 additions & 5 deletions clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -229,8 +229,6 @@ class AnalyzerOptions : public RefCountedBase<AnalyzerOptions> {
unsigned AnalyzerDisplayProgress : 1;
unsigned AnalyzerNoteAnalysisEntryPoints : 1;

unsigned eagerlyAssumeBinOpBifurcation : 1;

unsigned TrimGraph : 1;
unsigned visualizeExplodedGraphWithGraphViz : 1;
unsigned UnoptimizedCFG : 1;
Expand Down Expand Up @@ -293,9 +291,9 @@ class AnalyzerOptions : public RefCountedBase<AnalyzerOptions> {
ShowConfigOptionsList(false),
ShouldEmitErrorsOnInvalidConfigValue(false), AnalyzeAll(false),
AnalyzerDisplayProgress(false), AnalyzerNoteAnalysisEntryPoints(false),
eagerlyAssumeBinOpBifurcation(false), TrimGraph(false),
visualizeExplodedGraphWithGraphViz(false), UnoptimizedCFG(false),
PrintStats(false), NoRetryExhausted(false), AnalyzerWerror(false) {}
TrimGraph(false), visualizeExplodedGraphWithGraphViz(false),
UnoptimizedCFG(false), PrintStats(false), NoRetryExhausted(false),
AnalyzerWerror(false) {}

/// Interprets an option's string value as a boolean. The "true" string is
/// interpreted as true and the "false" string is interpreted as false.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -583,14 +583,13 @@ class ExprEngine {
ExplodedNode *Pred,
ExplodedNodeSet &Dst);

/// evalEagerlyAssumeBinOpBifurcation - Given the nodes in 'Src', eagerly assume symbolic
/// expressions of the form 'x != 0' and generate new nodes (stored in Dst)
/// with those assumptions.
void evalEagerlyAssumeBinOpBifurcation(ExplodedNodeSet &Dst, ExplodedNodeSet &Src,
const Expr *Ex);
/// evalEagerlyAssumeBifurcation - Given the nodes in 'Src', eagerly assume
/// concrete boolean values for 'Ex', storing the resulting nodes in 'Dst'.
void evalEagerlyAssumeBifurcation(ExplodedNodeSet &Dst, ExplodedNodeSet &Src,
const Expr *Ex);

static std::pair<const ProgramPointTag *, const ProgramPointTag *>
geteagerlyAssumeBinOpBifurcationTags();
getEagerlyAssumeBifurcationTags();

ProgramStateRef handleLValueBitCast(ProgramStateRef state, const Expr *Ex,
const LocationContext *LCtx, QualType T,
Expand Down
28 changes: 28 additions & 0 deletions clang/lib/AST/DeclTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1185,6 +1185,20 @@ SourceRange ClassTemplatePartialSpecializationDecl::getSourceRange() const {
return Range;
}

ArrayRef<TemplateArgument>
ClassTemplatePartialSpecializationDecl::getInjectedTemplateArgs() {
TemplateParameterList *Params = getTemplateParameters();
auto *First = cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl());
if (!First->InjectedArgs) {
auto &Context = getASTContext();
SmallVector<TemplateArgument, 16> TemplateArgs;
Context.getInjectedTemplateArgs(Params, TemplateArgs);
First->InjectedArgs = new (Context) TemplateArgument[TemplateArgs.size()];
std::copy(TemplateArgs.begin(), TemplateArgs.end(), First->InjectedArgs);
}
return llvm::ArrayRef(First->InjectedArgs, Params->size());
}

//===----------------------------------------------------------------------===//
// FriendTemplateDecl Implementation
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -1535,6 +1549,20 @@ SourceRange VarTemplatePartialSpecializationDecl::getSourceRange() const {
return Range;
}

ArrayRef<TemplateArgument>
VarTemplatePartialSpecializationDecl::getInjectedTemplateArgs() {
TemplateParameterList *Params = getTemplateParameters();
auto *First = cast<VarTemplatePartialSpecializationDecl>(getFirstDecl());
if (!First->InjectedArgs) {
auto &Context = getASTContext();
SmallVector<TemplateArgument, 16> TemplateArgs;
Context.getInjectedTemplateArgs(Params, TemplateArgs);
First->InjectedArgs = new (Context) TemplateArgument[TemplateArgs.size()];
std::copy(TemplateArgs.begin(), TemplateArgs.end(), First->InjectedArgs);
}
return llvm::ArrayRef(First->InjectedArgs, Params->size());
}

static TemplateParameterList *
createMakeIntegerSeqParameterList(const ASTContext &C, DeclContext *DC) {
// typename T
Expand Down
43 changes: 43 additions & 0 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7237,6 +7237,7 @@ class APValueToBufferConverter {

case APValue::ComplexInt:
case APValue::ComplexFloat:
return visitComplex(Val, Ty, Offset);
case APValue::FixedPoint:
// FIXME: We should support these.

Expand Down Expand Up @@ -7323,6 +7324,31 @@ class APValueToBufferConverter {
return true;
}

bool visitComplex(const APValue &Val, QualType Ty, CharUnits Offset) {
const ComplexType *ComplexTy = Ty->castAs<ComplexType>();
QualType EltTy = ComplexTy->getElementType();
CharUnits EltSizeChars = Info.Ctx.getTypeSizeInChars(EltTy);
bool IsInt = Val.isComplexInt();

if (IsInt) {
if (!visitInt(Val.getComplexIntReal(), EltTy,
Offset + (0 * EltSizeChars)))
return false;
if (!visitInt(Val.getComplexIntImag(), EltTy,
Offset + (1 * EltSizeChars)))
return false;
} else {
if (!visitFloat(Val.getComplexFloatReal(), EltTy,
Offset + (0 * EltSizeChars)))
return false;
if (!visitFloat(Val.getComplexFloatImag(), EltTy,
Offset + (1 * EltSizeChars)))
return false;
}

return true;
}

bool visitVector(const APValue &Val, QualType Ty, CharUnits Offset) {
const VectorType *VTy = Ty->castAs<VectorType>();
QualType EltTy = VTy->getElementType();
Expand Down Expand Up @@ -7595,6 +7621,23 @@ class BufferToAPValueConverter {
return ArrayValue;
}

std::optional<APValue> visit(const ComplexType *Ty, CharUnits Offset) {
QualType ElementType = Ty->getElementType();
CharUnits ElementWidth = Info.Ctx.getTypeSizeInChars(ElementType);
bool IsInt = ElementType->isIntegerType();

std::optional<APValue> Values[2];
for (unsigned I = 0; I != 2; ++I) {
Values[I] = visitType(Ty->getElementType(), Offset + I * ElementWidth);
if (!Values[I])
return std::nullopt;
}

if (IsInt)
return APValue(Values[0]->getInt(), Values[1]->getInt());
return APValue(Values[0]->getFloat(), Values[1]->getFloat());
}

std::optional<APValue> visit(const VectorType *VTy, CharUnits Offset) {
QualType EltTy = VTy->getElementType();
unsigned NElts = VTy->getNumElements();
Expand Down
6 changes: 4 additions & 2 deletions clang/lib/Basic/Targets/OSTargets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -214,9 +214,11 @@ static void addVisualCDefines(const LangOptions &Opts, MacroBuilder &Builder) {
Builder.defineMacro("_HAS_CHAR16_T_LANGUAGE_SUPPORT", Twine(1));

if (Opts.isCompatibleWithMSVC(LangOptions::MSVC2015)) {
if (Opts.CPlusPlus23)
if (Opts.CPlusPlus26)
// TODO update to the proper value.
Builder.defineMacro("_MSVC_LANG", "202004L");
Builder.defineMacro("_MSVC_LANG", "202400L");
else if (Opts.CPlusPlus23)
Builder.defineMacro("_MSVC_LANG", "202302L");
else if (Opts.CPlusPlus20)
Builder.defineMacro("_MSVC_LANG", "202002L");
else if (Opts.CPlusPlus17)
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5657,13 +5657,14 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
*Arg3 = EmitScalarExpr(E->getArg(3));
llvm::FunctionType *FTy = llvm::FunctionType::get(
Int32Ty, llvm::ArrayRef<llvm::Type *>(ArgTys), false);
Value *ACast = Builder.CreateAddrSpaceCast(Arg3, I8PTy);
// We know the third argument is an integer type, but we may need to cast
// it to i32.
if (Arg2->getType() != Int32Ty)
Arg2 = Builder.CreateZExtOrTrunc(Arg2, Int32Ty);
return RValue::get(
EmitRuntimeCall(CGM.CreateRuntimeFunction(FTy, Name),
{Arg0, Arg1, Arg2, Arg3, PacketSize, PacketAlign}));
{Arg0, Arg1, Arg2, ACast, PacketSize, PacketAlign}));
}
}
// OpenCL v2.0 s6.13.16 ,s9.17.3.5 - Built-in pipe reserve read and write
Expand Down
25 changes: 17 additions & 8 deletions clang/lib/CodeGen/CodeGenABITypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,23 @@ CodeGen::arrangeCXXMethodType(CodeGenModule &CGM,
return CGM.getTypes().arrangeCXXMethodType(RD, FTP, MD);
}

const CGFunctionInfo &
CodeGen::arrangeFreeFunctionCall(CodeGenModule &CGM,
CanQualType returnType,
ArrayRef<CanQualType> argTypes,
FunctionType::ExtInfo info,
RequiredArgs args) {
return CGM.getTypes().arrangeLLVMFunctionInfo(returnType, FnInfoOpts::None,
argTypes, info, {}, args);
const CGFunctionInfo &CodeGen::arrangeCXXMethodCall(
CodeGenModule &CGM, CanQualType returnType, ArrayRef<CanQualType> argTypes,
FunctionType::ExtInfo info,
ArrayRef<FunctionProtoType::ExtParameterInfo> paramInfos,
RequiredArgs args) {
return CGM.getTypes().arrangeLLVMFunctionInfo(
returnType, FnInfoOpts::IsInstanceMethod, argTypes, info, paramInfos,
args);
}

const CGFunctionInfo &CodeGen::arrangeFreeFunctionCall(
CodeGenModule &CGM, CanQualType returnType, ArrayRef<CanQualType> argTypes,
FunctionType::ExtInfo info,
ArrayRef<FunctionProtoType::ExtParameterInfo> paramInfos,
RequiredArgs args) {
return CGM.getTypes().arrangeLLVMFunctionInfo(
returnType, FnInfoOpts::None, argTypes, info, paramInfos, args);
}

ImplicitCXXConstructorArgs
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ createTargetCodeGenInfo(CodeGenModule &CGM) {
return createCommonSPIRTargetCodeGenInfo(CGM);
case llvm::Triple::spirv32:
case llvm::Triple::spirv64:
case llvm::Triple::spirv:
return createSPIRVTargetCodeGenInfo(CGM);
case llvm::Triple::dxil:
return createDirectXTargetCodeGenInfo(CGM);
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CodeGen/Targets/DirectX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ llvm::Type *DirectXTargetCodeGenInfo::getHLSLType(CodeGenModule &CGM,
llvm_unreachable("dx.Sampler handles are not implemented yet");
break;
}
llvm_unreachable("Unknown llvm::dxil::ResourceClass enum");
}

} // namespace
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7225,6 +7225,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
.Case("c++17", "-std=c++17")
.Case("c++20", "-std=c++20")
// TODO add c++23 and c++26 when MSVC supports it.
.Case("c++23preview", "-std=c++23")
.Case("c++latest", "-std=c++26")
.Default("");
if (LanguageStandard.empty())
Expand Down
10 changes: 10 additions & 0 deletions clang/lib/Driver/ToolChains/CommonArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1294,6 +1294,16 @@ void tools::addFortranRuntimeLibs(const ToolChain &TC, const ArgList &Args,
CmdArgs.push_back("-lFortranRuntime");
CmdArgs.push_back("-lFortranDecimal");
}

// libomp needs libatomic for atomic operations if using libgcc
if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ,
options::OPT_fno_openmp, false)) {
Driver::OpenMPRuntimeKind OMPRuntime =
TC.getDriver().getOpenMPRuntime(Args);
ToolChain::RuntimeLibType RuntimeLib = TC.GetRuntimeLibType(Args);
if (OMPRuntime == Driver::OMPRT_OMP && RuntimeLib == ToolChain::RLT_Libgcc)
CmdArgs.push_back("-latomic");
}
}

void tools::addFortranRuntimeLibraryPath(const ToolChain &TC,
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7883,6 +7883,9 @@ NamedDecl *Sema::ActOnVariableDeclarator(
// Handle attributes prior to checking for duplicates in MergeVarDecl
ProcessDeclAttributes(S, NewVD, D);

if (getLangOpts().HLSL)
HLSL().ActOnVariableDeclarator(NewVD);

// FIXME: This is probably the wrong location to be doing this and we should
// probably be doing this for more attributes (especially for function
// pointer attributes such as format, warn_unused_result, etc.). Ideally
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18273,7 +18273,7 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
}

// The return types aren't either both pointers or references to a class type.
if (NewClassTy.isNull()) {
if (NewClassTy.isNull() || !NewClassTy->isStructureOrClassType()) {
Diag(New->getLocation(),
diag::err_different_return_type_for_overriding_virtual_function)
<< New->getDeclName() << NewTy << OldTy
Expand Down
376 changes: 263 additions & 113 deletions clang/lib/Sema/SemaHLSL.cpp

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion clang/lib/Sema/SemaOpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2216,7 +2216,7 @@ ExprResult SemaOpenACC::CheckGangExpr(OpenACCGangKind GK, Expr *E) {
case OpenACCGangKind::Static:
return CheckGangStaticExpr(*this, E);
}
}
} break;
default:
llvm_unreachable("Non compute construct in active compute construct?");
}
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Sema/SemaTemplateInstantiate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ struct TemplateInstantiationArgumentCollecter
if (Innermost)
AddInnermostTemplateArguments(VTPSD);
else if (ForConstraintInstantiation)
AddOuterTemplateArguments(VTPSD, VTPSD->getTemplateArgs().asArray(),
AddOuterTemplateArguments(VTPSD, VTPSD->getInjectedTemplateArgs(),
/*Final=*/false);

if (VTPSD->isMemberSpecialization())
Expand Down Expand Up @@ -274,7 +274,7 @@ struct TemplateInstantiationArgumentCollecter
if (Innermost)
AddInnermostTemplateArguments(CTPSD);
else if (ForConstraintInstantiation)
AddOuterTemplateArguments(CTPSD, CTPSD->getTemplateArgs().asArray(),
AddOuterTemplateArguments(CTPSD, CTPSD->getInjectedTemplateArgs(),
/*Final=*/false);

if (CTPSD->isMemberSpecialization())
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2695,7 +2695,7 @@ ConditionBRVisitor::VisitNodeImpl(const ExplodedNode *N,
PathSensitiveBugReport &BR) {
ProgramPoint ProgPoint = N->getLocation();
const std::pair<const ProgramPointTag *, const ProgramPointTag *> &Tags =
ExprEngine::geteagerlyAssumeBinOpBifurcationTags();
ExprEngine::getEagerlyAssumeBifurcationTags();

// If an assumption was made on a branch, it should be caught
// here by looking at the state transition.
Expand Down
41 changes: 18 additions & 23 deletions clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2129,7 +2129,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
(B->isRelationalOp() || B->isEqualityOp())) {
ExplodedNodeSet Tmp;
VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Tmp);
evalEagerlyAssumeBinOpBifurcation(Dst, Tmp, cast<Expr>(S));
evalEagerlyAssumeBifurcation(Dst, Tmp, cast<Expr>(S));
}
else
VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst);
Expand Down Expand Up @@ -2402,7 +2402,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
if (AMgr.options.ShouldEagerlyAssume && (U->getOpcode() == UO_LNot)) {
ExplodedNodeSet Tmp;
VisitUnaryOperator(U, Pred, Tmp);
evalEagerlyAssumeBinOpBifurcation(Dst, Tmp, U);
evalEagerlyAssumeBifurcation(Dst, Tmp, U);
}
else
VisitUnaryOperator(U, Pred, Dst);
Expand Down Expand Up @@ -3742,23 +3742,20 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst,
BldrTop.addNodes(Tmp);
}

std::pair<const ProgramPointTag *, const ProgramPointTag*>
ExprEngine::geteagerlyAssumeBinOpBifurcationTags() {
static SimpleProgramPointTag
eagerlyAssumeBinOpBifurcationTrue(TagProviderName,
"Eagerly Assume True"),
eagerlyAssumeBinOpBifurcationFalse(TagProviderName,
"Eagerly Assume False");
return std::make_pair(&eagerlyAssumeBinOpBifurcationTrue,
&eagerlyAssumeBinOpBifurcationFalse);
std::pair<const ProgramPointTag *, const ProgramPointTag *>
ExprEngine::getEagerlyAssumeBifurcationTags() {
static SimpleProgramPointTag TrueTag(TagProviderName, "Eagerly Assume True"),
FalseTag(TagProviderName, "Eagerly Assume False");

return std::make_pair(&TrueTag, &FalseTag);
}

void ExprEngine::evalEagerlyAssumeBinOpBifurcation(ExplodedNodeSet &Dst,
ExplodedNodeSet &Src,
const Expr *Ex) {
void ExprEngine::evalEagerlyAssumeBifurcation(ExplodedNodeSet &Dst,
ExplodedNodeSet &Src,
const Expr *Ex) {
StmtNodeBuilder Bldr(Src, Dst, *currBldrCtx);

for (const auto Pred : Src) {
for (ExplodedNode *Pred : Src) {
// Test if the previous node was as the same expression. This can happen
// when the expression fails to evaluate to anything meaningful and
// (as an optimization) we don't generate a node.
Expand All @@ -3767,28 +3764,26 @@ void ExprEngine::evalEagerlyAssumeBinOpBifurcation(ExplodedNodeSet &Dst,
continue;
}

ProgramStateRef state = Pred->getState();
SVal V = state->getSVal(Ex, Pred->getLocationContext());
ProgramStateRef State = Pred->getState();
SVal V = State->getSVal(Ex, Pred->getLocationContext());
std::optional<nonloc::SymbolVal> SEV = V.getAs<nonloc::SymbolVal>();
if (SEV && SEV->isExpression()) {
const std::pair<const ProgramPointTag *, const ProgramPointTag*> &tags =
geteagerlyAssumeBinOpBifurcationTags();
const auto &[TrueTag, FalseTag] = getEagerlyAssumeBifurcationTags();

ProgramStateRef StateTrue, StateFalse;
std::tie(StateTrue, StateFalse) = state->assume(*SEV);
auto [StateTrue, StateFalse] = State->assume(*SEV);

// First assume that the condition is true.
if (StateTrue) {
SVal Val = svalBuilder.makeIntVal(1U, Ex->getType());
StateTrue = StateTrue->BindExpr(Ex, Pred->getLocationContext(), Val);
Bldr.generateNode(Ex, Pred, StateTrue, tags.first);
Bldr.generateNode(Ex, Pred, StateTrue, TrueTag);
}

// Next, assume that the condition is false.
if (StateFalse) {
SVal Val = svalBuilder.makeIntVal(0U, Ex->getType());
StateFalse = StateFalse->BindExpr(Ex, Pred->getLocationContext(), Val);
Bldr.generateNode(Ex, Pred, StateFalse, tags.second);
Bldr.generateNode(Ex, Pred, StateFalse, FalseTag);
}
}
}
Expand Down
46 changes: 40 additions & 6 deletions clang/test/Analysis/string.c
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,10 @@ void strcpy_fn_const(char *x) {
strcpy(x, (const char*)&strcpy_fn); // expected-warning{{Argument to string copy function is the address of the function 'strcpy_fn', which is not a null-terminated string}}
}

void strcpy_fn_dst(const char *x) {
strcpy((char*)&strcpy_fn, x); // expected-warning{{Argument to string copy function is the address of the function 'strcpy_fn', which is not a null-terminated string}}
}

extern int globalInt;
void strcpy_effects(char *x, char *y) {
char a = x[0];
Expand Down Expand Up @@ -469,8 +473,22 @@ void strcat_null_src(char *x) {
strcat(x, NULL); // expected-warning{{Null pointer passed as 2nd argument to string concatenation function}}
}

void strcat_fn(char *x) {
strcat(x, (char*)&strcat_fn); // expected-warning{{Argument to string concatenation function is the address of the function 'strcat_fn', which is not a null-terminated string}}
void strcat_fn_dst(const char *x) {
strcat((char*)&strcat_fn_dst, x); // expected-warning{{Argument to string concatenation function is the address of the function 'strcat_fn_dst', which is not a null-terminated string}}
}

void strcat_fn_src(char *x) {
strcat(x, (char*)&strcat_fn_src); // expected-warning{{Argument to string concatenation function is the address of the function 'strcat_fn_src', which is not a null-terminated string}}
}

void strcat_label_dst(const char *x) {
label:
strcat((char*)&&label, x); // expected-warning{{Argument to string concatenation function is the address of the label 'label', which is not a null-terminated string}}
}

void strcat_label_src(char *x) {
label:
strcat(x, (char*)&&label); // expected-warning{{Argument to string concatenation function is the address of the label 'label', which is not a null-terminated string}}
}

void strcat_effects(char *y) {
Expand Down Expand Up @@ -568,8 +586,12 @@ void strncpy_null_src(char *x) {
strncpy(x, NULL, 5); // expected-warning{{Null pointer passed as 2nd argument to string copy function}}
}

void strncpy_fn(char *x) {
strncpy(x, (char*)&strcpy_fn, 5); // expected-warning{{Argument to string copy function is the address of the function 'strcpy_fn', which is not a null-terminated string}}
void strncpy_fn_src(char *x) {
strncpy(x, (char*)&strncpy_fn_src, 5); // expected-warning{{Argument to string copy function is the address of the function 'strncpy_fn_src', which is not a null-terminated string}}
}

void strncpy_fn_dst(const char *x) {
strncpy((char*)&strncpy_fn_dst, x, 5); // expected-warning{{Argument to string copy function is the address of the function 'strncpy_fn_dst', which is not a null-terminated string}}
}

void strncpy_effects(char *x, char *y) {
Expand Down Expand Up @@ -680,8 +702,12 @@ void strncat_null_src(char *x) {
strncat(x, NULL, 4); // expected-warning{{Null pointer passed as 2nd argument to string concatenation function}}
}

void strncat_fn(char *x) {
strncat(x, (char*)&strncat_fn, 4); // expected-warning{{Argument to string concatenation function is the address of the function 'strncat_fn', which is not a null-terminated string}}
void strncat_fn_src(char *x) {
strncat(x, (char*)&strncat_fn_src, 4); // expected-warning{{Argument to string concatenation function is the address of the function 'strncat_fn_src', which is not a null-terminated string}}
}

void strncat_fn_dst(const char *x) {
strncat((char*)&strncat_fn_dst, x, 4); // expected-warning{{Argument to string concatenation function is the address of the function 'strncat_fn_dst', which is not a null-terminated string}}
}

void strncat_effects(char *y) {
Expand Down Expand Up @@ -921,6 +947,14 @@ int strcmp_null_argument(char *a) {
return strcmp(a, b); // expected-warning{{Null pointer passed as 2nd argument to string comparison function}}
}

void strcmp_fn_r(char *x) {
strcmp(x, (char*)&strcmp_null_argument); // expected-warning{{Argument to string comparison function is the address of the function 'strcmp_null_argument', which is not a null-terminated string}}
}

void strcmp_fn_l(char *x) {
strcmp((char*)&strcmp_null_argument, x); // expected-warning{{Argument to string comparison function is the address of the function 'strcmp_null_argument', which is not a null-terminated string}}
}

//===----------------------------------------------------------------------===
// strncmp()
//===----------------------------------------------------------------------===
Expand Down
10 changes: 9 additions & 1 deletion clang/test/Analysis/string.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix,debug.ExprInspection -verify %s
// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix,alpha.unix.cstring,debug.ExprInspection -verify %s

// Test functions that are called "memcpy" but aren't the memcpy
// we're looking for. Unfortunately, this test cannot be put into
// a namespace. The out-of-class weird memcpy needs to be recognized
// as a normal C function for the test to make sense.
typedef __typeof(sizeof(int)) size_t;
void *memcpy(void *, const void *, size_t);
size_t strlen(const char *s);

int sprintf(char *str, const char *format, ...);
int snprintf(char *str, size_t size, const char *format, ...);
Expand Down Expand Up @@ -45,3 +46,10 @@ void log(const char* fmt, const Args&... args) {
void test_gh_74269_no_crash() {
log("%d", 1);
}

struct TestNotNullTerm {
void test1() {
TestNotNullTerm * const &x = this;
strlen((char *)&x); // expected-warning{{Argument to string length function is not a null-terminated string}}
}
};
284 changes: 164 additions & 120 deletions clang/test/CXX/temp/temp.constr/temp.constr.decl/p4.cpp
Original file line number Diff line number Diff line change
@@ -1,175 +1,219 @@
// RUN: %clang_cc1 -std=c++20 -verify %s
// expected-no-diagnostics

template<typename T>
concept D = true;
namespace Primary {
template<typename T>
concept D = true;

template<typename T>
struct A {
template<typename U, bool V>
void f() requires V;
template<typename T>
struct A {
template<typename U, bool V>
void f() requires V;

template<>
void f<short, true>();
template<>
void f<short, true>();

template<D U>
void g();

template<typename U, bool V> requires V
struct B;

template<typename U, bool V> requires V
struct B<U*, V>;

template<>
struct B<short, true>;

template<D U>
struct C;

template<D U>
struct C<U*>;

template<typename U, bool V> requires V
static int x;

template<typename U, bool V> requires V
static int x<U*, V>;

template<>
int x<short, true>;

template<D U>
static int y;

template<D U>
static int y<U*>;
};

template<typename T>
template<typename U, bool V>
void A<T>::f() requires V { }

template<typename T>
template<D U>
void g();
void A<T>::g() { }

template<typename T>
template<typename U, bool V> requires V
struct B;
struct A<T>::B { };

template<typename T>
template<typename U, bool V> requires V
struct B<U*, V>;
struct A<T>::B<U*, V> { };

template<>
struct B<short, true>;
template<typename T>
template<typename U, bool V> requires V
struct A<T>::B<U&, V> { };

template<typename T>
template<D U>
struct C;
struct A<T>::C { };

template<typename T>
template<D U>
struct C<U*>;
struct A<T>::C<U*> { };

template<typename T>
template<typename U, bool V> requires V
static int x;
int A<T>::x = 0;

template<typename T>
template<typename U, bool V> requires V
static int x<U*, V>;
int A<T>::x<U*, V> = 0;

template<>
int x<short, true>;
template<typename T>
template<typename U, bool V> requires V
int A<T>::x<U&, V> = 0;

template<typename T>
template<D U>
static int y;
int A<T>::y = 0;

template<typename T>
template<D U>
static int y<U*>;
};

template<typename T>
template<typename U, bool V>
void A<T>::f() requires V { }
int A<T>::y<U*> = 0;

template<typename T>
template<D U>
void A<T>::g() { }

template<typename T>
template<typename U, bool V> requires V
struct A<T>::B { };
template<>
template<typename U, bool V>
void A<short>::f() requires V;

template<typename T>
template<typename U, bool V> requires V
struct A<T>::B<U*, V> { };
template<>
template<>
void A<short>::f<int, true>();

template<typename T>
template<typename U, bool V> requires V
struct A<T>::B<U&, V> { };
template<>
template<>
void A<void>::f<int, true>();

template<typename T>
template<D U>
struct A<T>::C { };
template<>
template<D U>
void A<short>::g();

template<typename T>
template<D U>
struct A<T>::C<U*> { };
template<>
template<typename U, bool V> requires V
struct A<int>::B;

template<typename T>
template<typename U, bool V> requires V
int A<T>::x = 0;
template<>
template<>
struct A<int>::B<int, true>;

template<typename T>
template<typename U, bool V> requires V
int A<T>::x<U*, V> = 0;
template<>
template<>
struct A<void>::B<int, true>;

template<typename T>
template<typename U, bool V> requires V
int A<T>::x<U&, V> = 0;
template<>
template<typename U, bool V> requires V
struct A<int>::B<U*, V>;

template<typename T>
template<D U>
int A<T>::y = 0;
template<>
template<typename U, bool V> requires V
struct A<int>::B<U&, V>;

template<typename T>
template<D U>
int A<T>::y<U*> = 0;
template<>
template<D U>
struct A<int>::C;

template<>
template<typename U, bool V>
void A<short>::f() requires V;
template<>
template<D U>
struct A<int>::C<U*>;

template<>
template<>
void A<short>::f<int, true>();
template<>
template<D U>
struct A<int>::C<U&>;

template<>
template<>
void A<void>::f<int, true>();
template<>
template<typename U, bool V> requires V
int A<long>::x;

template<>
template<D U>
void A<short>::g();
template<>
template<>
int A<long>::x<int, true>;

template<>
template<typename U, bool V> requires V
struct A<int>::B;
template<>
template<>
int A<void>::x<int, true>;

template<>
template<>
struct A<int>::B<int, true>;
template<>
template<typename U, bool V> requires V
int A<long>::x<U*, V>;

template<>
template<>
struct A<void>::B<int, true>;
template<>
template<typename U, bool V> requires V
int A<long>::x<U&, V>;

template<>
template<typename U, bool V> requires V
struct A<int>::B<U*, V>;
template<>
template<D U>
int A<long>::y;

template<>
template<typename U, bool V> requires V
struct A<int>::B<U&, V>;
template<>
template<D U>
int A<long>::y<U*>;

template<>
template<D U>
struct A<int>::C;
template<>
template<D U>
int A<long>::y<U&>;
} // namespace Primary

template<>
template<D U>
struct A<int>::C<U*>;
namespace Partial {
template<typename T, bool B>
struct A;

template<>
template<D U>
struct A<int>::C<U&>;
template<bool U>
struct A<int, U>
{
template<typename V> requires U
void f();

template<>
template<typename U, bool V> requires V
int A<long>::x;
template<typename V> requires U
static const int x;

template<>
template<>
int A<long>::x<int, true>;
template<typename V> requires U
struct B;
};

template<>
template<>
int A<void>::x<int, true>;
template<bool U>
template<typename V> requires U
void A<int, U>::f() { }

template<>
template<typename U, bool V> requires V
int A<long>::x<U*, V>;
template<bool U>
template<typename V> requires U
constexpr int A<int, U>::x = 0;

template<>
template<typename U, bool V> requires V
int A<long>::x<U&, V>;
template<bool U>
template<typename V> requires U
struct A<int, U>::B { };

template<>
template<D U>
int A<long>::y;
template<>
template<typename V> requires true
void A<int, true>::f() { }

template<>
template<D U>
int A<long>::y<U*>;
template<>
template<typename V> requires true
constexpr int A<int, true>::x = 1;

template<>
template<D U>
int A<long>::y<U&>;
template<>
template<typename V> requires true
struct A<int, true>::B { };
} // namespace Partial
42 changes: 42 additions & 0 deletions clang/test/CodeGen/sanitize-coverage-gated-callbacks.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// RUN: %clang %s -target arm64-apple-darwin -emit-llvm -S -fsanitize-coverage=trace-pc-guard -mllvm -sanitizer-coverage-gated-trace-callbacks=1 -o - | FileCheck %s --check-prefixes=CHECK,GATED
// RUN: %clang %s -target arm64-apple-darwin -emit-llvm -S -fsanitize-coverage=trace-pc-guard -mllvm -sanitizer-coverage-gated-trace-callbacks=0 -o - | FileCheck %s --check-prefixes=CHECK,PLAIN
// RUN: not %clang %s -target arm64-apple-darwin -emit-llvm -S -fsanitize-coverage=trace-pc -mllvm -sanitizer-coverage-gated-trace-callbacks=1 -o /dev/null 2>&1 | FileCheck %s --check-prefixes=INCOMPATIBLE
// RUN: not %clang %s -target arm64-apple-darwin -emit-llvm -S -fsanitize-coverage=inline-8bit-counters -mllvm -sanitizer-coverage-gated-trace-callbacks=1 -o /dev/null 2>&1 | FileCheck %s --check-prefixes=INCOMPATIBLE
// RUN: not %clang %s -target arm64-apple-darwin -emit-llvm -S -fsanitize-coverage=inline-bool-flag -mllvm -sanitizer-coverage-gated-trace-callbacks=1 -o /dev/null 2>&1 | FileCheck %s --check-prefixes=INCOMPATIBLE

// Verify that we do not emit the __sancov_gate section for "plain" trace-pc-guard
// GATED: section "__DATA,__sancov_gate"
// PLAIN-NOT: section "__DATA,__sancov_gate"

// Produce an error for all incompatible sanitizer coverage modes.
// INCOMPATIBLE: error: 'sanitizer-coverage-gated-trace-callbacks' is only supported with trace-pc-guard

int x[10];

// CHECK: define{{.*}} void @foo
void foo(int n, int m) {
// COM: Verify that we're emitting the call to __sanitizer_cov_trace_pc_guard upon
// COM: checking the value of __sancov_should_track.
// GATED: [[VAL:%.*]] = load i64, {{.*}}@__sancov_should_track
// GATED-NOT: [[VAL:%.*]] = load i64, i64* @__sancov_should_track
// GATED-NEXT: [[CMP:%.*]] = icmp ne i64 [[VAL]], 0
// GATED-NEXT: br i1 [[CMP]], label %[[L_TRUE:.*]], label %[[L_FALSE:.*]], !prof [[WEIGHTS:!.+]]
// GATED: [[L_TRUE]]:
// GATED-NEXT: call void @__sanitizer_cov_trace_pc_guard
// GATED: br i1 [[CMP]], label %[[L_TRUE_2:.*]], label %[[L_FALSE_2:.*]]
// GATED: [[L_TRUE_2]]:
// GATED-NEXT: call void @__sanitizer_cov_trace_pc_guard
// GATED: [[WEIGHTS]] = !{!"branch_weights", i32 1, i32 100000}

// COM: With the non-gated instrumentation, we should not emit the
// COM: __sancov_should_track global.
// PLAIN-NOT: __sancov_should_track
// But we should still be emitting the calls to the callback.
// PLAIN: call void @__sanitizer_cov_trace_pc_guard
if (n) {
x[n] = 42;
if (m) {
x[m] = 41;
}
}
}
20 changes: 10 additions & 10 deletions clang/test/CodeGenHLSL/builtins/WaveReadLaneAt.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -10,65 +10,65 @@
// CHECK-LABEL: test_int
int test_int(int expr, uint idx) {
// CHECK-SPIRV: %[[#entry_tok0:]] = call token @llvm.experimental.convergence.entry()
// CHECK-SPIRV: %[[RET:.*]] = call [[TY:.*]] @llvm.spv.wave.readlane.i32([[TY]] %[[#]], i32 %[[#]]) [ "convergencectrl"(token %[[#entry_tok0]]) ]
// CHECK-SPIRV: %[[RET:.*]] = call spir_func [[TY:.*]] @llvm.spv.wave.readlane.i32([[TY]] %[[#]], i32 %[[#]]) [ "convergencectrl"(token %[[#entry_tok0]]) ]
// CHECK-DXIL: %[[RET:.*]] = call [[TY:.*]] @llvm.dx.wave.readlane.i32([[TY]] %[[#]], i32 %[[#]])
// CHECK: ret [[TY]] %[[RET]]
return WaveReadLaneAt(expr, idx);
}

// CHECK-DXIL: declare [[TY]] @llvm.dx.wave.readlane.i32([[TY]], i32) #[[#attr:]]
// CHECK-SPIRV: declare [[TY]] @llvm.spv.wave.readlane.i32([[TY]], i32) #[[#attr:]]
// CHECK-SPIRV: declare spir_func [[TY]] @llvm.spv.wave.readlane.i32([[TY]], i32) #[[#attr:]]

#ifdef __HLSL_ENABLE_16_BIT
// CHECK-LABEL: test_int16
int16_t test_int16(int16_t expr, uint idx) {
// CHECK-SPIRV: %[[#entry_tok1:]] = call token @llvm.experimental.convergence.entry()
// CHECK-SPIRV: %[[RET:.*]] = call [[TY:.*]] @llvm.spv.wave.readlane.i16([[TY]] %[[#]], i32 %[[#]]) [ "convergencectrl"(token %[[#entry_tok1]]) ]
// CHECK-SPIRV: %[[RET:.*]] = call spir_func [[TY:.*]] @llvm.spv.wave.readlane.i16([[TY]] %[[#]], i32 %[[#]]) [ "convergencectrl"(token %[[#entry_tok1]]) ]
// CHECK-DXIL: %[[RET:.*]] = call [[TY:.*]] @llvm.dx.wave.readlane.i16([[TY]] %[[#]], i32 %[[#]])
// CHECK: ret [[TY]] %[[RET]]
return WaveReadLaneAt(expr, idx);
}

// CHECK-DXIL: declare [[TY]] @llvm.dx.wave.readlane.i16([[TY]], i32) #[[#attr:]]
// CHECK-SPIRV: declare [[TY]] @llvm.spv.wave.readlane.i16([[TY]], i32) #[[#attr:]]
// CHECK-SPIRV: declare spir_func [[TY]] @llvm.spv.wave.readlane.i16([[TY]], i32) #[[#attr:]]
#endif

// Test basic lowering to runtime function call with array and float values.

// CHECK-LABEL: test_half
half test_half(half expr, uint idx) {
// CHECK-SPIRV: %[[#entry_tok2:]] = call token @llvm.experimental.convergence.entry()
// CHECK-SPIRV: %[[RET:.*]] = call [[TY:.*]] @llvm.spv.wave.readlane.f16([[TY]] %[[#]], i32 %[[#]]) [ "convergencectrl"(token %[[#entry_tok2]]) ]
// CHECK-SPIRV: %[[RET:.*]] = call spir_func [[TY:.*]] @llvm.spv.wave.readlane.f16([[TY]] %[[#]], i32 %[[#]]) [ "convergencectrl"(token %[[#entry_tok2]]) ]
// CHECK-DXIL: %[[RET:.*]] = call [[TY:.*]] @llvm.dx.wave.readlane.f16([[TY]] %[[#]], i32 %[[#]])
// CHECK: ret [[TY]] %[[RET]]
return WaveReadLaneAt(expr, idx);
}

// CHECK-DXIL: declare [[TY]] @llvm.dx.wave.readlane.f16([[TY]], i32) #[[#attr:]]
// CHECK-SPIRV: declare [[TY]] @llvm.spv.wave.readlane.f16([[TY]], i32) #[[#attr:]]
// CHECK-SPIRV: declare spir_func [[TY]] @llvm.spv.wave.readlane.f16([[TY]], i32) #[[#attr:]]

// CHECK-LABEL: test_double
double test_double(double expr, uint idx) {
// CHECK-SPIRV: %[[#entry_tok3:]] = call token @llvm.experimental.convergence.entry()
// CHECK-SPIRV: %[[RET:.*]] = call [[TY:.*]] @llvm.spv.wave.readlane.f64([[TY]] %[[#]], i32 %[[#]]) [ "convergencectrl"(token %[[#entry_tok3]]) ]
// CHECK-SPIRV: %[[RET:.*]] = call spir_func [[TY:.*]] @llvm.spv.wave.readlane.f64([[TY]] %[[#]], i32 %[[#]]) [ "convergencectrl"(token %[[#entry_tok3]]) ]
// CHECK-DXIL: %[[RET:.*]] = call [[TY:.*]] @llvm.dx.wave.readlane.f64([[TY]] %[[#]], i32 %[[#]])
// CHECK: ret [[TY]] %[[RET]]
return WaveReadLaneAt(expr, idx);
}

// CHECK-DXIL: declare [[TY]] @llvm.dx.wave.readlane.f64([[TY]], i32) #[[#attr:]]
// CHECK-SPIRV: declare [[TY]] @llvm.spv.wave.readlane.f64([[TY]], i32) #[[#attr:]]
// CHECK-SPIRV: declare spir_func [[TY]] @llvm.spv.wave.readlane.f64([[TY]], i32) #[[#attr:]]

// CHECK-LABEL: test_floatv4
float4 test_floatv4(float4 expr, uint idx) {
// CHECK-SPIRV: %[[#entry_tok4:]] = call token @llvm.experimental.convergence.entry()
// CHECK-SPIRV: %[[RET1:.*]] = call [[TY1:.*]] @llvm.spv.wave.readlane.v4f32([[TY1]] %[[#]], i32 %[[#]]) [ "convergencectrl"(token %[[#entry_tok4]]) ]
// CHECK-SPIRV: %[[RET1:.*]] = call spir_func [[TY1:.*]] @llvm.spv.wave.readlane.v4f32([[TY1]] %[[#]], i32 %[[#]]) [ "convergencectrl"(token %[[#entry_tok4]]) ]
// CHECK-DXIL: %[[RET1:.*]] = call [[TY1:.*]] @llvm.dx.wave.readlane.v4f32([[TY1]] %[[#]], i32 %[[#]])
// CHECK: ret [[TY1]] %[[RET1]]
return WaveReadLaneAt(expr, idx);
}

// CHECK-DXIL: declare [[TY1]] @llvm.dx.wave.readlane.v4f32([[TY1]], i32) #[[#attr]]
// CHECK-SPIRV: declare [[TY1]] @llvm.spv.wave.readlane.v4f32([[TY1]], i32) #[[#attr]]
// CHECK-SPIRV: declare spir_func [[TY1]] @llvm.spv.wave.readlane.v4f32([[TY1]], i32) #[[#attr]]

// CHECK: attributes #[[#attr]] = {{{.*}} convergent {{.*}}}
8 changes: 4 additions & 4 deletions clang/test/CodeGenHLSL/builtins/sign.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -202,19 +202,19 @@ int4 test_sign_int64_t4(int64_t4 p0) { return sign(p0); }
// CHECK: define [[FNATTRS]] i32 @
// CHECK: [[CMP:%.*]] = icmp eq i64 [[ARG:%.*]], 0
// CHECK: %hlsl.sign = select i1 [[CMP]], i32 0, i32 1
int test_sign_int64_t(uint64_t p0) { return sign(p0); }
int test_sign_uint64_t(uint64_t p0) { return sign(p0); }

// CHECK: define [[FNATTRS]] <2 x i32> @
// CHECK: [[CMP:%.*]] = icmp eq <2 x i64> [[ARG:%.*]], zeroinitializer
// CHECK: %hlsl.sign = select <2 x i1> [[CMP]], <2 x i32> zeroinitializer, <2 x i32> <i32 1, i32 1>
int2 test_sign_int64_t2(uint64_t2 p0) { return sign(p0); }
int2 test_sign_uint64_t2(uint64_t2 p0) { return sign(p0); }

// CHECK: define [[FNATTRS]] <3 x i32> @
// CHECK: [[CMP:%.*]] = icmp eq <3 x i64> [[ARG:%.*]], zeroinitializer
// CHECK: %hlsl.sign = select <3 x i1> [[CMP]], <3 x i32> zeroinitializer, <3 x i32> <i32 1, i32 1, i32 1>
int3 test_sign_int64_t3(uint64_t3 p0) { return sign(p0); }
int3 test_sign_uint64_t3(uint64_t3 p0) { return sign(p0); }

// CHECK: define [[FNATTRS]] <4 x i32> @
// CHECK: [[CMP:%.*]] = icmp eq <4 x i64> [[ARG:%.*]], zeroinitializer
// CHECK: %hlsl.sign = select <4 x i1> [[CMP]], <4 x i32> zeroinitializer, <4 x i32> <i32 1, i32 1, i32 1, i32 1>
int4 test_sign_int64_t4(uint64_t4 p0) { return sign(p0); }
int4 test_sign_uint64_t4(uint64_t4 p0) { return sign(p0); }
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ void main() {
// CHECK: br i1 {{%.+}}, label %[[LABEL_IF_THEN:.+]], label %[[LABEL_IF_END:.+]]

// CHECK: [[LABEL_IF_THEN]]:
// CHECK: call i32 @__hlsl_wave_get_lane_index() [ "convergencectrl"(token %[[CT_LOOP]]) ]
// CHECK: call spir_func i32 @__hlsl_wave_get_lane_index() [ "convergencectrl"(token %[[CT_LOOP]]) ]
// CHECK: br label %[[LABEL_WHILE_END:.+]]
if (cond == 2) {
uint index = WaveGetLaneIndex();
Expand All @@ -33,7 +33,7 @@ void main() {
// CHECK: ret void
}

// CHECK-DAG: declare i32 @__hlsl_wave_get_lane_index() [[A1:#[0-9]+]]
// CHECK-DAG: declare spir_func i32 @__hlsl_wave_get_lane_index() [[A1:#[0-9]+]]

// CHECK-DAG: attributes [[A0]] = {{{.*}}convergent{{.*}}}
// CHECK-DAG: attributes [[A1]] = {{{.*}}convergent{{.*}}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@
// CHECK-SPIRV: define spir_func noundef i32 @{{.*test_1.*}}() [[A0:#[0-9]+]] {
// CHECK-DXIL: define noundef i32 @{{.*test_1.*}}() [[A0:#[0-9]+]] {
// CHECK-SPIRV: %[[CI:[0-9]+]] = call token @llvm.experimental.convergence.entry()
// CHECK-SPIRV: call i32 @__hlsl_wave_get_lane_index() [ "convergencectrl"(token %[[CI]]) ]
// CHECK-SPIRV: call spir_func i32 @__hlsl_wave_get_lane_index() [ "convergencectrl"(token %[[CI]]) ]
// CHECK-DXIL: call i32 @llvm.dx.wave.getlaneindex()
int test_1() {
return WaveGetLaneIndex();
}

// CHECK-SPIRV: declare i32 @__hlsl_wave_get_lane_index() [[A1:#[0-9]+]]
// CHECK-SPIRV: declare spir_func i32 @__hlsl_wave_get_lane_index() [[A1:#[0-9]+]]
// CHECK-DXIL: declare i32 @llvm.dx.wave.getlaneindex() [[A1:#[0-9]+]]

// CHECK-DAG: attributes [[A0]] = { {{.*}}convergent{{.*}} }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@

// CHECK: define spir_func noundef i32 @_Z6test_1v() [[A0:#[0-9]+]] {
// CHECK: %[[C1:[0-9]+]] = call token @llvm.experimental.convergence.entry()
// CHECK: call i32 @__hlsl_wave_get_lane_index() [ "convergencectrl"(token %[[C1]]) ]
// CHECK: call spir_func i32 @__hlsl_wave_get_lane_index() [ "convergencectrl"(token %[[C1]]) ]
uint test_1() {
return WaveGetLaneIndex();
}

// CHECK-DAG: declare i32 @__hlsl_wave_get_lane_index() [[A1:#[0-9]+]]
// CHECK-DAG: declare spir_func i32 @__hlsl_wave_get_lane_index() [[A1:#[0-9]+]]

// CHECK: define spir_func noundef i32 @_Z6test_2v() [[A0]] {
// CHECK: %[[C2:[0-9]+]] = call token @llvm.experimental.convergence.entry()
Expand Down
4 changes: 2 additions & 2 deletions clang/test/CodeGenHLSL/builtins/wave_is_first_lane.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ void main() {
while (true) {

// CHECK-DXIL: %[[#]] = call i1 @llvm.dx.wave.is.first.lane()
// CHECK-SPIRV: %[[#]] = call i1 @llvm.spv.wave.is.first.lane()
// CHECK-SPIRV: %[[#]] = call spir_func i1 @llvm.spv.wave.is.first.lane()
// CHECK-SPIRV-SAME: [ "convergencectrl"(token %[[#loop_tok]]) ]
if (WaveIsFirstLane()) {
break;
}
}

// CHECK-DXIL: %[[#]] = call i1 @llvm.dx.wave.is.first.lane()
// CHECK-SPIRV: %[[#]] = call i1 @llvm.spv.wave.is.first.lane()
// CHECK-SPIRV: %[[#]] = call spir_func i1 @llvm.spv.wave.is.first.lane()
// CHECK-SPIRV-SAME: [ "convergencectrl"(token %[[#entry_tok]]) ]
if (WaveIsFirstLane()) {
return;
Expand Down
1,252 changes: 1,171 additions & 81 deletions clang/test/CodeGenOpenCL/addr-space-struct-arg.cl

Large diffs are not rendered by default.

122 changes: 81 additions & 41 deletions clang/test/CodeGenOpenCL/amdgcn-automatic-variable.cl
Original file line number Diff line number Diff line change
@@ -1,67 +1,107 @@
// RUN: %clang_cc1 -O0 -cl-std=CL1.2 -triple amdgcn---amdgizcl -emit-llvm %s -o - | FileCheck -check-prefixes=CHECK,CL12 %s
// RUN: %clang_cc1 -O0 -cl-std=CL2.0 -triple amdgcn---amdgizcl -emit-llvm %s -o - | FileCheck -check-prefixes=CHECK,CL20 %s
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
// RUN: %clang_cc1 -O0 -cl-std=CL1.2 -triple amdgcn-amd-amdhsa -emit-llvm %s -o - | FileCheck -check-prefixes=CL12 %s
// RUN: %clang_cc1 -O0 -cl-std=CL2.0 -triple amdgcn-amd-amdhsa -emit-llvm %s -o - | FileCheck -check-prefixes=CL20 %s

// CL12-LABEL: define{{.*}} void @func1(ptr addrspace(5) noundef %x)
// CL20-LABEL: define{{.*}} void @func1(ptr noundef %x)
// CL12-LABEL: define dso_local void @func1(
// CL12-SAME: ptr addrspace(5) noundef [[X:%.*]]) #[[ATTR0:[0-9]+]] {
// CL12-NEXT: [[ENTRY:.*:]]
// CL12-NEXT: [[X_ADDR:%.*]] = alloca ptr addrspace(5), align 4, addrspace(5)
// CL12-NEXT: store ptr addrspace(5) [[X]], ptr addrspace(5) [[X_ADDR]], align 4
// CL12-NEXT: [[TMP0:%.*]] = load ptr addrspace(5), ptr addrspace(5) [[X_ADDR]], align 4
// CL12-NEXT: store i32 1, ptr addrspace(5) [[TMP0]], align 4
// CL12-NEXT: ret void
//
// CL20-LABEL: define dso_local void @func1(
// CL20-SAME: ptr noundef [[X:%.*]]) #[[ATTR0:[0-9]+]] {
// CL20-NEXT: [[ENTRY:.*:]]
// CL20-NEXT: [[X_ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
// CL20-NEXT: store ptr [[X]], ptr addrspace(5) [[X_ADDR]], align 8
// CL20-NEXT: [[TMP0:%.*]] = load ptr, ptr addrspace(5) [[X_ADDR]], align 8
// CL20-NEXT: store i32 1, ptr [[TMP0]], align 4
// CL20-NEXT: ret void
//
void func1(int *x) {
// CL12: %[[x_addr:.*]] = alloca ptr addrspace(5){{.*}}addrspace(5)
// CL12: store ptr addrspace(5) %x, ptr addrspace(5) %[[x_addr]]
// CL12: %[[r0:.*]] = load ptr addrspace(5), ptr addrspace(5) %[[x_addr]]
// CL12: store i32 1, ptr addrspace(5) %[[r0]]
// CL20: %[[x_addr:.*]] = alloca ptr{{.*}}addrspace(5)
// CL20: store ptr %x, ptr addrspace(5) %[[x_addr]]
// CL20: %[[r0:.*]] = load ptr, ptr addrspace(5) %[[x_addr]]
// CL20: store i32 1, ptr %[[r0]]
*x = 1;
}

// CHECK-LABEL: define{{.*}} void @func2()
// CL12-LABEL: define dso_local void @func2(
// CL12-SAME: ) #[[ATTR0]] {
// CL12-NEXT: [[ENTRY:.*:]]
// CL12-NEXT: [[LV1:%.*]] = alloca i32, align 4, addrspace(5)
// CL12-NEXT: [[LV2:%.*]] = alloca i32, align 4, addrspace(5)
// CL12-NEXT: [[LA:%.*]] = alloca [100 x i32], align 4, addrspace(5)
// CL12-NEXT: [[LP1:%.*]] = alloca ptr addrspace(5), align 4, addrspace(5)
// CL12-NEXT: [[LP2:%.*]] = alloca ptr addrspace(5), align 4, addrspace(5)
// CL12-NEXT: [[LVC:%.*]] = alloca i32, align 4, addrspace(5)
// CL12-NEXT: store i32 1, ptr addrspace(5) [[LV1]], align 4
// CL12-NEXT: store i32 2, ptr addrspace(5) [[LV2]], align 4
// CL12-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [100 x i32], ptr addrspace(5) [[LA]], i64 0, i64 0
// CL12-NEXT: store i32 3, ptr addrspace(5) [[ARRAYIDX]], align 4
// CL12-NEXT: store ptr addrspace(5) [[LV1]], ptr addrspace(5) [[LP1]], align 4
// CL12-NEXT: [[ARRAYDECAY:%.*]] = getelementptr inbounds [100 x i32], ptr addrspace(5) [[LA]], i64 0, i64 0
// CL12-NEXT: store ptr addrspace(5) [[ARRAYDECAY]], ptr addrspace(5) [[LP2]], align 4
// CL12-NEXT: call void @func1(ptr addrspace(5) noundef [[LV1]]) #[[ATTR2:[0-9]+]]
// CL12-NEXT: store i32 4, ptr addrspace(5) [[LVC]], align 4
// CL12-NEXT: store i32 4, ptr addrspace(5) [[LV1]], align 4
// CL12-NEXT: ret void
//
// CL20-LABEL: define dso_local void @func2(
// CL20-SAME: ) #[[ATTR0]] {
// CL20-NEXT: [[ENTRY:.*:]]
// CL20-NEXT: [[LV1:%.*]] = alloca i32, align 4, addrspace(5)
// CL20-NEXT: [[LV2:%.*]] = alloca i32, align 4, addrspace(5)
// CL20-NEXT: [[LA:%.*]] = alloca [100 x i32], align 4, addrspace(5)
// CL20-NEXT: [[LP1:%.*]] = alloca ptr, align 8, addrspace(5)
// CL20-NEXT: [[LP2:%.*]] = alloca ptr, align 8, addrspace(5)
// CL20-NEXT: [[LVC:%.*]] = alloca i32, align 4, addrspace(5)
// CL20-NEXT: store i32 1, ptr addrspace(5) [[LV1]], align 4
// CL20-NEXT: store i32 2, ptr addrspace(5) [[LV2]], align 4
// CL20-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [100 x i32], ptr addrspace(5) [[LA]], i64 0, i64 0
// CL20-NEXT: store i32 3, ptr addrspace(5) [[ARRAYIDX]], align 4
// CL20-NEXT: [[LV1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[LV1]] to ptr
// CL20-NEXT: store ptr [[LV1_ASCAST]], ptr addrspace(5) [[LP1]], align 8
// CL20-NEXT: [[ARRAYDECAY:%.*]] = getelementptr inbounds [100 x i32], ptr addrspace(5) [[LA]], i64 0, i64 0
// CL20-NEXT: [[ARRAYDECAY_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[ARRAYDECAY]] to ptr
// CL20-NEXT: store ptr [[ARRAYDECAY_ASCAST]], ptr addrspace(5) [[LP2]], align 8
// CL20-NEXT: [[LV1_ASCAST1:%.*]] = addrspacecast ptr addrspace(5) [[LV1]] to ptr
// CL20-NEXT: call void @func1(ptr noundef [[LV1_ASCAST1]]) #[[ATTR2:[0-9]+]]
// CL20-NEXT: store i32 4, ptr addrspace(5) [[LVC]], align 4
// CL20-NEXT: store i32 4, ptr addrspace(5) [[LV1]], align 4
// CL20-NEXT: ret void
//
void func2(void) {
// CHECK: %lv1 = alloca i32, align 4, addrspace(5)
// CHECK: %lv2 = alloca i32, align 4, addrspace(5)
// CHECK: %la = alloca [100 x i32], align 4, addrspace(5)
// CL12: %lp1 = alloca ptr addrspace(5), align 4, addrspace(5)
// CL12: %lp2 = alloca ptr addrspace(5), align 4, addrspace(5)
// CL20: %lp1 = alloca ptr, align 8, addrspace(5)
// CL20: %lp2 = alloca ptr, align 8, addrspace(5)
// CHECK: %lvc = alloca i32, align 4, addrspace(5)

// CHECK: store i32 1, ptr addrspace(5) %lv1
int lv1;
lv1 = 1;
// CHECK: store i32 2, ptr addrspace(5) %lv2

int lv2 = 2;

// CHECK: %[[arrayidx:.*]] = getelementptr inbounds [100 x i32], ptr addrspace(5) %la, i64 0, i64 0
// CHECK: store i32 3, ptr addrspace(5) %[[arrayidx]], align 4
int la[100];
la[0] = 3;

// CL12: store ptr addrspace(5) %lv1, ptr addrspace(5) %lp1, align 4
// CL20: %[[r0:.*]] = addrspacecast ptr addrspace(5) %lv1 to ptr
// CL20: store ptr %[[r0]], ptr addrspace(5) %lp1, align 8
int *lp1 = &lv1;

// CHECK: %[[arraydecay:.*]] = getelementptr inbounds [100 x i32], ptr addrspace(5) %la, i64 0, i64 0
// CL12: store ptr addrspace(5) %[[arraydecay]], ptr addrspace(5) %lp2, align 4
// CL20: %[[r1:.*]] = addrspacecast ptr addrspace(5) %[[arraydecay]] to ptr
// CL20: store ptr %[[r1]], ptr addrspace(5) %lp2, align 8
int *lp2 = la;

// CL12: call void @func1(ptr addrspace(5) noundef %lv1)
// CL20: %[[r2:.*]] = addrspacecast ptr addrspace(5) %lv1 to ptr
// CL20: call void @func1(ptr noundef %[[r2]])
func1(&lv1);

// CHECK: store i32 4, ptr addrspace(5) %lvc
// CHECK: store i32 4, ptr addrspace(5) %lv1
const int lvc = 4;
lv1 = lvc;
}

// CHECK-LABEL: define{{.*}} void @func3()
// CHECK: %a = alloca [16 x [1 x float]], align 4, addrspace(5)
// CHECK: call void @llvm.memset.p5.i64(ptr addrspace(5) align 4 %a, i8 0, i64 64, i1 false)
// CL12-LABEL: define dso_local void @func3(
// CL12-SAME: ) #[[ATTR0]] {
// CL12-NEXT: [[ENTRY:.*:]]
// CL12-NEXT: [[A:%.*]] = alloca [16 x [1 x float]], align 4, addrspace(5)
// CL12-NEXT: call void @llvm.memset.p5.i64(ptr addrspace(5) align 4 [[A]], i8 0, i64 64, i1 false)
// CL12-NEXT: ret void
//
// CL20-LABEL: define dso_local void @func3(
// CL20-SAME: ) #[[ATTR0]] {
// CL20-NEXT: [[ENTRY:.*:]]
// CL20-NEXT: [[A:%.*]] = alloca [16 x [1 x float]], align 4, addrspace(5)
// CL20-NEXT: call void @llvm.memset.p5.i64(ptr addrspace(5) align 4 [[A]], i8 0, i64 64, i1 false)
// CL20-NEXT: ret void
//
void func3(void) {
float a[16][1] = {{0.}};
}
21 changes: 21 additions & 0 deletions clang/test/CodeGenOpenCL/pipe_builtin.cl
Original file line number Diff line number Diff line change
@@ -1,69 +1,90 @@
// RUN: %clang_cc1 -triple spir-unknown-unknown -emit-llvm -cl-ext=+cl_khr_subgroups -O0 -cl-std=clc++ -o - %s | FileCheck --check-prefix=CHECK-SPIR %s
// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm -cl-ext=+cl_khr_subgroups -O0 -cl-std=clc++ -o - %s | FileCheck %s
// FIXME: Add MS ABI manglings of OpenCL things and remove %itanium_abi_triple
// above to support OpenCL in the MS C++ ABI.

#pragma OPENCL EXTENSION cl_khr_subgroups : enable

void test1(read_only pipe int p, global int *ptr) {
// CHECK-SPIR: call spir_func i32 @__read_pipe_2(target("spirv.Pipe", 0) %{{.*}}, ptr addrspace(4) %{{.*}}, i32 4, i32 4)
// CHECK: call i32 @__read_pipe_2(ptr %{{.*}}, ptr %{{.*}}, i32 4, i32 4)
read_pipe(p, ptr);
// CHECK-SPIR: call spir_func target("spirv.ReserveId") @__reserve_read_pipe(target("spirv.Pipe", 0) %{{.*}}, i32 {{.*}}, i32 4, i32 4)
// CHECK: call ptr @__reserve_read_pipe(ptr %{{.*}}, i32 {{.*}}, i32 4, i32 4)
reserve_id_t rid = reserve_read_pipe(p, 2);
// CHECK-SPIR: call spir_func i32 @__read_pipe_4(target("spirv.Pipe", 0) %{{.*}}, ptr addrspace(4) %{{.*}}, i32 4, i32 4)
// CHECK: call i32 @__read_pipe_4(ptr %{{.*}}, ptr %{{.*}}, i32 {{.*}}, ptr %{{.*}}, i32 4, i32 4)
read_pipe(p, rid, 2, ptr);
// CHECK-SPIR: call spir_func void @__commit_read_pipe(target("spirv.Pipe", 0) %{{.*}}, target("spirv.ReserveId") %{{.*}}, i32 4, i32 4)
// CHECK: call void @__commit_read_pipe(ptr %{{.*}}, ptr %{{.*}}, i32 4, i32 4)
commit_read_pipe(p, rid);
}

void test2(write_only pipe int p, global int *ptr) {
// CHECK-SPIR: call spir_func i32 @__write_pipe_2(target("spirv.Pipe", 1) %{{.*}}, ptr addrspace(4) %{{.*}}, i32 4, i32 4)
// CHECK: call i32 @__write_pipe_2(ptr %{{.*}}, ptr %{{.*}}, i32 4, i32 4)
write_pipe(p, ptr);
// CHECK-SPIR: call spir_func target("spirv.ReserveId") @__reserve_write_pipe(target("spirv.Pipe", 1) %{{.*}}, i32 {{.*}}, i32 4, i32 4)
// CHECK: call ptr @__reserve_write_pipe(ptr %{{.*}}, i32 {{.*}}, i32 4, i32 4)
reserve_id_t rid = reserve_write_pipe(p, 2);
// CHECK-SPIR: call spir_func i32 @__write_pipe_4(target("spirv.Pipe", 1) %{{.*}}, ptr addrspace(4) %{{.*}}, i32 4, i32 4)
// CHECK: call i32 @__write_pipe_4(ptr %{{.*}}, ptr %{{.*}}, i32 {{.*}}, ptr %{{.*}}, i32 4, i32 4)
write_pipe(p, rid, 2, ptr);
// CHECK-SPIR: call spir_func void @__commit_write_pipe(target("spirv.Pipe", 1) %{{.*}}, target("spirv.ReserveId") %{{.*}}, i32 4, i32 4)
// CHECK: call void @__commit_write_pipe(ptr %{{.*}}, ptr %{{.*}}, i32 4, i32 4)
commit_write_pipe(p, rid);
}

void test3(read_only pipe int p, global int *ptr) {
// CHECK-SPIR: call spir_func target("spirv.ReserveId") @__work_group_reserve_read_pipe(target("spirv.Pipe", 0) %{{.*}}, i32 {{.*}}, i32 4, i32 4)
// CHECK: call ptr @__work_group_reserve_read_pipe(ptr %{{.*}}, i32 {{.*}}, i32 4, i32 4)
reserve_id_t rid = work_group_reserve_read_pipe(p, 2);
// CHECK-SPIR: call spir_func void @__work_group_commit_read_pipe(target("spirv.Pipe", 0) %{{.*}}, target("spirv.ReserveId") %{{.*}}, i32 4, i32 4)
// CHECK: call void @__work_group_commit_read_pipe(ptr %{{.*}}, ptr %{{.*}}, i32 4, i32 4)
work_group_commit_read_pipe(p, rid);
}

void test4(write_only pipe int p, global int *ptr) {
// CHECK-SPIR: call spir_func target("spirv.ReserveId") @__work_group_reserve_write_pipe(target("spirv.Pipe", 1) %{{.*}}, i32 {{.*}}, i32 4, i32 4)
// CHECK: call ptr @__work_group_reserve_write_pipe(ptr %{{.*}}, i32 {{.*}}, i32 4, i32 4)
reserve_id_t rid = work_group_reserve_write_pipe(p, 2);
// CHECK-SPIR: call spir_func void @__work_group_commit_write_pipe(target("spirv.Pipe", 1) %{{.*}}, target("spirv.ReserveId") %{{.*}}, i32 4, i32 4)
// CHECK: call void @__work_group_commit_write_pipe(ptr %{{.*}}, ptr %{{.*}}, i32 4, i32 4)
work_group_commit_write_pipe(p, rid);
}

void test5(read_only pipe int p, global int *ptr) {
// CHECK-SPIR: call spir_func target("spirv.ReserveId") @__sub_group_reserve_read_pipe(target("spirv.Pipe", 0) %{{.*}}, i32 {{.*}}, i32 4, i32 4)
// CHECK: call ptr @__sub_group_reserve_read_pipe(ptr %{{.*}}, i32 {{.*}}, i32 4, i32 4)
reserve_id_t rid = sub_group_reserve_read_pipe(p, 2);
// CHECK-SPIR: call spir_func void @__sub_group_commit_read_pipe(target("spirv.Pipe", 0) %{{.*}}, target("spirv.ReserveId") %{{.*}}, i32 4, i32 4)
// CHECK: call void @__sub_group_commit_read_pipe(ptr %{{.*}}, ptr %{{.*}}, i32 4, i32 4)
sub_group_commit_read_pipe(p, rid);
}

void test6(write_only pipe int p, global int *ptr) {
// CHECK-SPIR: call spir_func target("spirv.ReserveId") @__sub_group_reserve_write_pipe(target("spirv.Pipe", 1) %{{.*}}, i32 {{.*}}, i32 4, i32 4)
// CHECK: call ptr @__sub_group_reserve_write_pipe(ptr %{{.*}}, i32 {{.*}}, i32 4, i32 4)
reserve_id_t rid = sub_group_reserve_write_pipe(p, 2);
// CHECK-SPIR: call spir_func void @__sub_group_commit_write_pipe(target("spirv.Pipe", 1) %{{.*}}, target("spirv.ReserveId") %{{.*}}, i32 4, i32 4)
// CHECK: call void @__sub_group_commit_write_pipe(ptr %{{.*}}, ptr %{{.*}}, i32 4, i32 4)
sub_group_commit_write_pipe(p, rid);
}

void test7(read_only pipe int p, global int *ptr) {
// CHECK-SPIR: call spir_func i32 @__get_pipe_num_packets_ro(target("spirv.Pipe", 0) %{{.*}}, i32 4, i32 4)
// CHECK: call i32 @__get_pipe_num_packets_ro(ptr %{{.*}}, i32 4, i32 4)
*ptr = get_pipe_num_packets(p);
// CHECK-SPIR: call spir_func i32 @__get_pipe_max_packets_ro(target("spirv.Pipe", 0) %{{.*}}, i32 4, i32 4)
// CHECK: call i32 @__get_pipe_max_packets_ro(ptr %{{.*}}, i32 4, i32 4)
*ptr = get_pipe_max_packets(p);
}

void test8(write_only pipe int p, global int *ptr) {
// CHECK-SPIR: call spir_func i32 @__get_pipe_num_packets_wo(target("spirv.Pipe", 1) %{{.*}}, i32 4, i32 4)
// CHECK: call i32 @__get_pipe_num_packets_wo(ptr %{{.*}}, i32 4, i32 4)
*ptr = get_pipe_num_packets(p);
// CHECK-SPIR: call spir_func i32 @__get_pipe_max_packets_wo(target("spirv.Pipe", 1) %{{.*}}, i32 4, i32 4)
// CHECK: call i32 @__get_pipe_max_packets_wo(ptr %{{.*}}, i32 4, i32 4)
*ptr = get_pipe_max_packets(p);
}
3 changes: 3 additions & 0 deletions clang/test/Driver/cl-options.c
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,9 @@
// RUN: %clang_cl -fmsc-version=1900 -TP -std:c++20 -### -- %s 2>&1 | FileCheck -check-prefix=STDCXX20 %s
// STDCXX20: -std=c++20

// RUN: %clang_cl -fmsc-version=1900 -TP -std:c++23preview -### -- %s 2>&1 | FileCheck -check-prefix=STDCXX23PREVIEW %s
// STDCXX23PREVIEW: -std=c++23

// RUN: %clang_cl -fmsc-version=1900 -TP -std:c++latest -### -- %s 2>&1 | FileCheck -check-prefix=STDCXXLATEST %s
// STDCXXLATEST: -std=c++26

Expand Down
44 changes: 30 additions & 14 deletions clang/test/ExtractAPI/anonymous_record_no_typedef.c
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
// RUN: rm -rf %t
// RUN: %clang_cc1 -extract-api --pretty-sgf --emit-sgf-symbol-labels-for-testing \
// RUN: -triple arm64-apple-macosx -isystem %S -fretain-comments-from-system-headers \
// RUN: -x c-header %s -o %t/output.symbols.json -verify
// RUN: -x c-header %s -o %t/output-c.symbols.json -verify
//
// RUN: %clang_cc1 -extract-api --pretty-sgf --emit-sgf-symbol-labels-for-testing \
// RUN: -triple arm64-apple-macosx -isystem %S -fretain-comments-from-system-headers \
// RUN: -x c++-header %s -o %t/output-cxx.symbols.json -verify

// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix GLOBAL
// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix PREFIX
// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix CONTENT
// RUN: FileCheck %s --input-file %t/output-c.symbols.json --check-prefix GLOBAL
// RUN: FileCheck %s --input-file %t/output-c.symbols.json --check-prefix PREFIX
// RUN: FileCheck %s --input-file %t/output-c.symbols.json --check-prefix CONTENT
// RUN: FileCheck %s --input-file %t/output-cxx.symbols.json --check-prefix GLOBAL
// RUN: FileCheck %s --input-file %t/output-cxx.symbols.json --check-prefix PREFIX
// RUN: FileCheck %s --input-file %t/output-cxx.symbols.json --check-prefix CONTENT
/// A global variable with an anonymous struct type.
struct { char *prefix; char *content; } global;
// GLOBAL-LABEL: "!testLabel": "c:@global"
Expand All @@ -30,7 +37,7 @@ struct { char *prefix; char *content; } global;
// GLOBAL: "text": "A global variable with an anonymous struct type."
// GLOBAL: "kind": {
// GLOBAL-NEXT: "displayName": "Global Variable",
// GLOBAL-NEXT: "identifier": "c.var"
// GLOBAL-NEXT: "identifier": "c{{(\+\+)?}}.var"
// GLOBAL: "title": "global"
// GLOBAL: "pathComponents": [
// GLOBAL-NEXT: "global"
Expand All @@ -54,9 +61,12 @@ struct { char *prefix; char *content; } global;

/// A Vehicle
struct Vehicle {
// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix TYPE
// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix BICYCLE
// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix CAR
// RUN: FileCheck %s --input-file %t/output-c.symbols.json --check-prefix TYPE
// RUN: FileCheck %s --input-file %t/output-c.symbols.json --check-prefix BICYCLE
// RUN: FileCheck %s --input-file %t/output-c.symbols.json --check-prefix CAR
// RUN: FileCheck %s --input-file %t/output-cxx.symbols.json --check-prefix TYPE
// RUN: FileCheck %s --input-file %t/output-cxx.symbols.json --check-prefix BICYCLE
// RUN: FileCheck %s --input-file %t/output-cxx.symbols.json --check-prefix CAR
/// The type of vehicle.
enum {
Bicycle,
Expand Down Expand Up @@ -96,9 +106,12 @@ struct Vehicle {
// CAR-NEXT: "Car"
// CAR-NEXT: ]

// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix INFORMATION
// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix WHEELS
// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix NAME
// RUN: FileCheck %s --input-file %t/output-c.symbols.json --check-prefix INFORMATION
// RUN: FileCheck %s --input-file %t/output-c.symbols.json --check-prefix WHEELS
// RUN: FileCheck %s --input-file %t/output-c.symbols.json --check-prefix NAME
// RUN: FileCheck %s --input-file %t/output-cxx.symbols.json --check-prefix INFORMATION
// RUN: FileCheck %s --input-file %t/output-cxx.symbols.json --check-prefix WHEELS
// RUN: FileCheck %s --input-file %t/output-cxx.symbols.json --check-prefix NAME
/// The information about the vehicle.
union {
int wheels;
Expand Down Expand Up @@ -145,8 +158,10 @@ struct Vehicle {
// NAME-NEXT: ]
};

// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix GLOBALCASE
// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix GLOBALOTHERCASE
// RUN: FileCheck %s --input-file %t/output-c.symbols.json --check-prefix GLOBALCASE
// RUN: FileCheck %s --input-file %t/output-c.symbols.json --check-prefix GLOBALOTHERCASE
// RUN: FileCheck %s --input-file %t/output-cxx.symbols.json --check-prefix GLOBALCASE
// RUN: FileCheck %s --input-file %t/output-cxx.symbols.json --check-prefix GLOBALOTHERCASE
enum {
GlobalCase,
GlobalOtherCase
Expand All @@ -163,7 +178,8 @@ enum {
// GLOBALOTHERCASE-NEXT: "GlobalOtherCase"
// GLOBALOTHERCASE-NEXT: ]

// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix VEC
// RUN: FileCheck %s --input-file %t/output-c.symbols.json --check-prefix VEC
// RUN: FileCheck %s --input-file %t/output-cxx.symbols.json --check-prefix VEC
union Vector {
struct {
float X;
Expand Down
27 changes: 17 additions & 10 deletions clang/test/ExtractAPI/typedef_anonymous_record.c
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
// RUN: rm -rf %t
// RUN: %clang_cc1 -extract-api --pretty-sgf --emit-sgf-symbol-labels-for-testing \
// RUN: --product-name=TypedefChain -triple arm64-apple-macosx -x c-header %s -o %t/typedefchain.symbols.json -verify
// RUN: --product-name=TypedefChain -triple arm64-apple-macosx -x c-header %s -o %t/typedefchain-c.symbols.json -verify
// RUN: %clang_cc1 -extract-api --pretty-sgf --emit-sgf-symbol-labels-for-testing \
// RUN: --product-name=TypedefChain -triple arm64-apple-macosx -x c++-header %s -o %t/typedefchain-cxx.symbols.json -verify

// RUN: FileCheck %s --input-file %t/typedefchain.symbols.json --check-prefix MYSTRUCT
// RUN: FileCheck %s --input-file %t/typedefchain-c.symbols.json --check-prefix MYSTRUCT
// RUN: FileCheck %s --input-file %t/typedefchain-cxx.symbols.json --check-prefix MYSTRUCT
typedef struct { } MyStruct;
// MYSTRUCT-LABEL: "!testLabel": "c:@SA@MyStruct"
// MYSTRUCT: "accessLevel": "public",
Expand Down Expand Up @@ -34,7 +37,7 @@ typedef struct { } MyStruct;
// MYSTRUCT-NEXT: ]
// MYSTRUCT: "kind": {
// MYSTRUCT-NEXT: "displayName": "Structure",
// MYSTRUCT-NEXT: "identifier": "c.struct"
// MYSTRUCT-NEXT: "identifier": "c{{(\+\+)?}}.struct"
// MYSTRUCT: "names": {
// MYSTRUCT-NEXT: "navigator": [
// MYSTRUCT-NEXT: {
Expand All @@ -54,7 +57,8 @@ typedef struct { } MyStruct;
// MYSTRUCT-NEXT: "MyStruct"
// MYSTRUCT-NEXT: ]

// RUN: FileCheck %s --input-file %t/typedefchain.symbols.json --check-prefix MYSTRUCTSTRUCT
// RUN: FileCheck %s --input-file %t/typedefchain-c.symbols.json --check-prefix MYSTRUCTSTRUCT
// RUN: FileCheck %s --input-file %t/typedefchain-cxx.symbols.json --check-prefix MYSTRUCTSTRUCT
typedef MyStruct MyStructStruct;
// MYSTRUCTSTRUCT-LABEL: "!testLabel": "c:typedef_anonymous_record.c@T@MyStructStruct"
// MYSTRUCTSTRUCT: "accessLevel": "public",
Expand Down Expand Up @@ -87,10 +91,12 @@ typedef MyStruct MyStructStruct;
// MYSTRUCTSTRUCT-NEXT:],
// MYSTRUCTSTRUCT: "kind": {
// MYSTRUCTSTRUCT-NEXT: "displayName": "Type Alias",
// MYSTRUCTSTRUCT-NEXT: "identifier": "c.typealias"
// MYSTRUCTSTRUCT-NEXT: "identifier": "c{{(\+\+)?}}.typealias"

// RUN: FileCheck %s --input-file %t/typedefchain.symbols.json --check-prefix MYENUM
// RUN: FileCheck %s --input-file %t/typedefchain.symbols.json --check-prefix CASE
// RUN: FileCheck %s --input-file %t/typedefchain-c.symbols.json --check-prefix MYENUM
// RUN: FileCheck %s --input-file %t/typedefchain-c.symbols.json --check-prefix CASE
// RUN: FileCheck %s --input-file %t/typedefchain-cxx.symbols.json --check-prefix MYENUM
// RUN: FileCheck %s --input-file %t/typedefchain-cxx.symbols.json --check-prefix CASE
typedef enum { Case } MyEnum;
// MYENUM: "source": "c:@EA@MyEnum@Case",
// MYENUM-NEXT: "target": "c:@EA@MyEnum",
Expand Down Expand Up @@ -124,7 +130,7 @@ typedef enum { Case } MyEnum;
// MYENUM-NEXT:],
// MYENUM: "kind": {
// MYENUM-NEXT: "displayName": "Enumeration",
// MYENUM-NEXT: "identifier": "c.enum"
// MYENUM-NEXT: "identifier": "c{{(\+\+)?}}.enum"
// MYENUM: "names": {
// MYENUM-NEXT: "navigator": [
// MYENUM-NEXT: {
Expand All @@ -147,7 +153,8 @@ typedef enum { Case } MyEnum;
// CASE-NEXT: "Case"
// CASE-NEXT: ]

// RUN: FileCheck %s --input-file %t/typedefchain.symbols.json --check-prefix MYENUMENUM
// RUN: FileCheck %s --input-file %t/typedefchain-c.symbols.json --check-prefix MYENUMENUM
// RUN: FileCheck %s --input-file %t/typedefchain-cxx.symbols.json --check-prefix MYENUMENUM
typedef MyEnum MyEnumEnum;
// MYENUMENUM-LABEL: "!testLabel": "c:typedef_anonymous_record.c@T@MyEnumEnum"
// MYENUMENUM: "declarationFragments": [
Expand Down Expand Up @@ -179,7 +186,7 @@ typedef MyEnum MyEnumEnum;
// MYENUMENUM-NEXT: ],
// MYENUMENUM: "kind": {
// MYENUMENUM-NEXT: "displayName": "Type Alias",
// MYENUMENUM-NEXT: "identifier": "c.typealias"
// MYENUMENUM-NEXT: "identifier": "c{{(\+\+)?}}.typealias"
// MYENUMENUM-NEXT: },
// MYENUMENUM: "title": "MyEnumEnum"

Expand Down
59 changes: 40 additions & 19 deletions clang/test/Modules/friend-definition-2.cpp
Original file line number Diff line number Diff line change
@@ -1,32 +1,53 @@
// RUN: %clang_cc1 -std=c++14 -fmodules %s -verify
// RUN: %clang_cc1 -std=c++14 -fmodules %s -verify -triple i686-windows
// expected-no-diagnostics
#pragma clang module build A
module A {}
#pragma clang module contents
#pragma clang module begin A
// RUN: split-file %s %t

// RUN: %clang_cc1 -std=c++14 -x c++ -fmodules -fmodule-name=A -emit-module %t/a.modulemap -o %t/a.pcm
// RUN: %clang_cc1 -std=c++14 -x c++ -fmodules -fmodule-name=B -emit-module %t/b.modulemap -o %t/b.pcm
// RUN: %clang_cc1 -std=c++14 -x c++ -fmodules -fmodule-map-file=%t/a.modulemap -fmodule-map-file=%t/b.modulemap \
// RUN: -fmodule-file=%t/a.pcm -fmodule-file=%t/b.pcm \
// RUN: %t/use.cc -verify

// RUN: rm -f %t/*.pcm

// RUN: %clang_cc1 -std=c++14 -x c++ -fmodules -fmodule-name=A -emit-module %t/a.modulemap -o %t/a.pcm -triple i686-windows
// RUN: %clang_cc1 -std=c++14 -x c++ -fmodules -fmodule-name=B -emit-module %t/b.modulemap -o %t/b.pcm -triple i686-windows
// RUN: %clang_cc1 -std=c++14 -x c++ -fmodules -fmodule-map-file=%t/a.modulemap -fmodule-map-file=%t/b.modulemap \
// RUN: -fmodule-file=%t/a.pcm -fmodule-file=%t/b.pcm \
// RUN: %t/use.cc -verify -triple i686-windows

//--- a.modulemap
module A {
header "a.h"
}

//--- a.h
#ifndef A_H
#define A_H
template<typename T> struct ct { friend auto operator-(ct, ct) { struct X {}; return X(); } void x(); };
#endif

//--- b.modulemap
module B {
header "b.h"
}

//--- b.h
#ifndef B_H
#define B_H
template<typename T> struct ct { friend auto operator-(ct, ct) { struct X {}; return X(); } void x(); };
#pragma clang module end
#pragma clang module endbuild

#pragma clang module build B
module B {}
#pragma clang module contents
#pragma clang module begin B
template<typename T> struct ct { friend auto operator-(ct, ct) { struct X{}; return X(); } void x(); };
inline auto f() { return ct<float>() - ct<float>(); }
#pragma clang module end
#pragma clang module endbuild
#endif

//--- use.cc
// expected-no-diagnostics
// Force the definition of ct in module A to be the primary definition.
#pragma clang module import A
#include "a.h"
template<typename T> void ct<T>::x() {}

// Attempt to cause the definition of operator- in the ct primary template in
// module B to be the primary definition of that function. If that happens,
// we'll be left with a class template ct that appears to not contain a
// definition of the inline friend function.
#pragma clang module import B
#include "b.h"
auto v = f();

ct<int> make();
Expand Down
7 changes: 6 additions & 1 deletion clang/test/Preprocessor/predefined-win-macros.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,12 @@
// RUN: %clang_cc1 %s -x c++ -E -dM -triple i686-pc-win32 -fms-extensions -fms-compatibility \
// RUN: -fms-compatibility-version=19.00 -std=c++23 -o - | FileCheck -match-full-lines %s --check-prefix=CHECK-MS-CPP2B
// CHECK-MS-CPP2B: #define _MSC_VER 1900
// CHECK-MS-CPP2B: #define _MSVC_LANG 202004L
// CHECK-MS-CPP2B: #define _MSVC_LANG 202302L

// RUN: %clang_cc1 %s -x c++ -E -dM -triple i686-pc-win32 -fms-extensions -fms-compatibility \
// RUN: -fms-compatibility-version=19.00 -std=c++26 -o - | FileCheck -match-full-lines %s --check-prefix=CHECK-MS-CPP2C
// CHECK-MS-CPP2C: #define _MSC_VER 1900
// CHECK-MS-CPP2C: #define _MSVC_LANG 202400L

// RUN: %clang_cc1 -triple i386-windows %s -E -dM -o - \
// RUN: | FileCheck -match-full-lines %s --check-prefix=CHECK-X86-WIN
Expand Down
16 changes: 16 additions & 0 deletions clang/test/SemaCXX/constexpr-builtin-bit-cast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -511,3 +511,19 @@ constexpr bool9 bad_short_to_bool9 = __builtin_bit_cast(bool9, static_cast<unsig
constexpr bool17 bad_int_to_bool17 = __builtin_bit_cast(bool17, 0x0001CAFEU);

}

namespace test_complex {
constexpr _Complex unsigned test_int_complex = { 0x0C05FEFE, 0xCAFEBABE };
static_assert(round_trip<_Complex unsigned>(0xCAFEBABE0C05FEFEULL), "");
static_assert(bit_cast<unsigned long long>(test_int_complex) == (LITTLE_END
? 0xCAFEBABE0C05FEFE
: 0x0C05FEFECAFEBABE), "");
static_assert(sizeof(double) == 2 * sizeof(float));
struct TwoFloats { float A; float B; };
constexpr _Complex float test_float_complex = {1.0f, 2.0f};
constexpr TwoFloats TF = __builtin_bit_cast(TwoFloats, test_float_complex);
static_assert(TF.A == 1.0f && TF.B == 2.0f);

constexpr double D = __builtin_bit_cast(double, test_float_complex);
constexpr int M = __builtin_bit_cast(int, test_int_complex); // expected-error {{__builtin_bit_cast source size does not equal destination size}}
}
6 changes: 6 additions & 0 deletions clang/test/SemaCXX/virtual-override.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@ struct b { };

class A {
virtual a* f(); // expected-note{{overridden virtual function is here}}
virtual int *g(); // expected-note{{overridden virtual function is here}}
};

class B : A {
virtual b* f(); // expected-error{{return type of virtual function 'f' is not covariant with the return type of the function it overrides ('b *' is not derived from 'a *')}}
virtual char *g(); // expected-error{{virtual function 'g' has a different return type ('char *') than the function it overrides (which has return type 'int *')}}
};

}
Expand Down Expand Up @@ -83,11 +85,15 @@ struct a { };
class A {
virtual const a* f();
virtual a* g(); // expected-note{{overridden virtual function is here}}
virtual const int* h(); // expected-note{{overridden virtual function is here}}
virtual int* i(); // expected-note{{overridden virtual function is here}}
};

class B : A {
virtual a* f();
virtual const a* g(); // expected-error{{return type of virtual function 'g' is not covariant with the return type of the function it overrides (class type 'const a *' is more qualified than class type 'a *'}}
virtual int* h(); // expected-error{{virtual function 'h' has a different return type ('int *') than the function it overrides (which has return type 'const int *')}}
virtual const int* i(); // expected-error{{virtual function 'i' has a different return type ('const int *') than the function it overrides (which has return type 'int *')}}
};

}
Expand Down
8 changes: 4 additions & 4 deletions clang/test/SemaHLSL/resource_binding_attr_error_udt.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,6 @@ struct Eg12{
MySRV s1;
MySRV s2;
};
// expected-warning@+3{{binding type 'u' only applies to types containing UAV resources}}
// expected-warning@+2{{binding type 'u' only applies to types containing UAV resources}}
// expected-error@+1{{binding type 'u' cannot be applied more than once}}
Eg12 e12 : register(u9) : register(u10);
Expand All @@ -115,12 +114,14 @@ struct Eg13{
MySRV s1;
MySRV s2;
};
// expected-warning@+4{{binding type 'u' only applies to types containing UAV resources}}
// expected-warning@+3{{binding type 'u' only applies to types containing UAV resources}}
// expected-warning@+2{{binding type 'u' only applies to types containing UAV resources}}
// expected-error@+2{{binding type 'u' cannot be applied more than once}}
// expected-error@+1{{binding type 'u' cannot be applied more than once}}
Eg13 e13 : register(u9) : register(u10) : register(u11);

// expected-error@+1{{binding type 't' cannot be applied more than once}}
Eg13 e13_2 : register(t11) : register(t12);

struct Eg14{
MyTemplatedUAV<int> r1;
};
Expand All @@ -132,4 +133,3 @@ struct Eg15 {
};
// expected no error
Eg15 e15 : register(c0);

1 change: 1 addition & 0 deletions clang/unittests/Analysis/FlowSensitive/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ add_clang_unittest(ClangAnalysisFlowSensitiveTests
ArenaTest.cpp
ASTOpsTest.cpp
CFGMatchSwitchTest.cpp
CachedConstAccessorsLatticeTest.cpp
ChromiumCheckModelTest.cpp
DataflowAnalysisContextTest.cpp
DataflowEnvironmentTest.cpp
Expand Down
Loading