aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Sema
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2022-07-03 14:10:23 +0000
committerDimitry Andric <dim@FreeBSD.org>2022-07-03 14:10:23 +0000
commit145449b1e420787bb99721a429341fa6be3adfb6 (patch)
tree1d56ae694a6de602e348dd80165cf881a36600ed /clang/lib/Sema
parentecbca9f5fb7d7613d2b94982c4825eb0d33d6842 (diff)
downloadsrc-145449b1e420787bb99721a429341fa6be3adfb6.tar.gz
src-145449b1e420787bb99721a429341fa6be3adfb6.zip
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r--clang/lib/Sema/AnalysisBasedWarnings.cpp9
-rw-r--r--clang/lib/Sema/CodeCompleteConsumer.cpp12
-rw-r--r--clang/lib/Sema/IdentifierResolver.cpp6
-rw-r--r--clang/lib/Sema/OpenCLBuiltins.td500
-rw-r--r--clang/lib/Sema/ParsedAttr.cpp64
-rw-r--r--clang/lib/Sema/Sema.cpp68
-rw-r--r--clang/lib/Sema/SemaAccess.cpp35
-rw-r--r--clang/lib/Sema/SemaAttr.cpp265
-rw-r--r--clang/lib/Sema/SemaAvailability.cpp2
-rw-r--r--clang/lib/Sema/SemaCUDA.cpp51
-rw-r--r--clang/lib/Sema/SemaCXXScopeSpec.cpp15
-rw-r--r--clang/lib/Sema/SemaCast.cpp21
-rw-r--r--clang/lib/Sema/SemaChecking.cpp749
-rw-r--r--clang/lib/Sema/SemaCodeComplete.cpp36
-rw-r--r--clang/lib/Sema/SemaConcept.cpp89
-rw-r--r--clang/lib/Sema/SemaCoroutine.cpp323
-rw-r--r--clang/lib/Sema/SemaDecl.cpp954
-rw-r--r--clang/lib/Sema/SemaDeclAttr.cpp574
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp297
-rw-r--r--clang/lib/Sema/SemaDeclObjC.cpp53
-rw-r--r--clang/lib/Sema/SemaExceptionSpec.cpp17
-rw-r--r--clang/lib/Sema/SemaExpr.cpp1044
-rw-r--r--clang/lib/Sema/SemaExprCXX.cpp272
-rw-r--r--clang/lib/Sema/SemaExprMember.cpp30
-rw-r--r--clang/lib/Sema/SemaExprObjC.cpp8
-rw-r--r--clang/lib/Sema/SemaInit.cpp97
-rw-r--r--clang/lib/Sema/SemaLambda.cpp35
-rw-r--r--clang/lib/Sema/SemaLookup.cpp426
-rw-r--r--clang/lib/Sema/SemaModule.cpp327
-rw-r--r--clang/lib/Sema/SemaOpenMP.cpp2119
-rw-r--r--clang/lib/Sema/SemaOverload.cpp488
-rw-r--r--clang/lib/Sema/SemaStmt.cpp51
-rw-r--r--clang/lib/Sema/SemaStmtAsm.cpp27
-rw-r--r--clang/lib/Sema/SemaStmtAttr.cpp78
-rw-r--r--clang/lib/Sema/SemaTemplate.cpp119
-rw-r--r--clang/lib/Sema/SemaTemplateDeduction.cpp51
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiate.cpp99
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiateDecl.cpp198
-rw-r--r--clang/lib/Sema/SemaTemplateVariadic.cpp28
-rw-r--r--clang/lib/Sema/SemaType.cpp400
-rw-r--r--clang/lib/Sema/TreeTransform.h297
41 files changed, 7932 insertions, 2402 deletions
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index ac5ad52c0b1d..164fea6a449b 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -1272,7 +1272,7 @@ static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC,
for (const CFGBlock *B : llvm::reverse(*Cfg)) {
const Stmt *Label = B->getLabel();
- if (!Label || !isa<SwitchCase>(Label))
+ if (!isa_and_nonnull<SwitchCase>(Label))
continue;
int AnnotatedCnt;
@@ -1844,7 +1844,7 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler {
}
}
- void handleInvalidLockExp(StringRef Kind, SourceLocation Loc) override {
+ void handleInvalidLockExp(SourceLocation Loc) override {
PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_cannot_resolve_lock)
<< Loc);
Warnings.emplace_back(std::move(Warning), getNotes());
@@ -1922,9 +1922,8 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler {
Warnings.emplace_back(std::move(Warning), getNotes(Note));
}
- void handleNoMutexHeld(StringRef Kind, const NamedDecl *D,
- ProtectedOperationKind POK, AccessKind AK,
- SourceLocation Loc) override {
+ void handleNoMutexHeld(const NamedDecl *D, ProtectedOperationKind POK,
+ AccessKind AK, SourceLocation Loc) override {
assert((POK == POK_VarAccess || POK == POK_VarDereference) &&
"Only works for variables");
unsigned DiagID = POK == POK_VarAccess?
diff --git a/clang/lib/Sema/CodeCompleteConsumer.cpp b/clang/lib/Sema/CodeCompleteConsumer.cpp
index fefe20941f17..8e8a1be38c0f 100644
--- a/clang/lib/Sema/CodeCompleteConsumer.cpp
+++ b/clang/lib/Sema/CodeCompleteConsumer.cpp
@@ -346,6 +346,15 @@ const char *CodeCompletionString::getTypedText() const {
return nullptr;
}
+std::string CodeCompletionString::getAllTypedText() const {
+ std::string Res;
+ for (const Chunk &C : *this)
+ if (C.Kind == CK_TypedText)
+ Res += C.Text;
+
+ return Res;
+}
+
const char *CodeCompletionAllocator::CopyString(const Twine &String) {
SmallString<128> Data;
StringRef Ref = String.toStringRef(Data);
@@ -621,8 +630,7 @@ void PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(
std::stable_sort(Results, Results + NumResults);
if (!Context.getPreferredType().isNull())
- OS << "PREFERRED-TYPE: " << Context.getPreferredType().getAsString()
- << "\n";
+ OS << "PREFERRED-TYPE: " << Context.getPreferredType() << '\n';
StringRef Filter = SemaRef.getPreprocessor().getCodeCompletionFilter();
// Print the completions.
diff --git a/clang/lib/Sema/IdentifierResolver.cpp b/clang/lib/Sema/IdentifierResolver.cpp
index 333f4d70986a..9081714c893f 100644
--- a/clang/lib/Sema/IdentifierResolver.cpp
+++ b/clang/lib/Sema/IdentifierResolver.cpp
@@ -121,12 +121,14 @@ bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx, Scope *S,
// of the controlled statement.
//
assert(S->getParent() && "No TUScope?");
- if (S->getParent()->getFlags() & Scope::ControlScope) {
+ // If the current decl is in a lambda, we shouldn't consider this is a
+ // redefinition as lambda has its own scope.
+ if (S->getParent()->isControlScope() && !S->isFunctionScope()) {
S = S->getParent();
if (S->isDeclScope(D))
return true;
}
- if (S->getFlags() & Scope::FnTryCatchScope)
+ if (S->isFnTryCatchScope())
return S->getParent()->isDeclScope(D);
}
return false;
diff --git a/clang/lib/Sema/OpenCLBuiltins.td b/clang/lib/Sema/OpenCLBuiltins.td
index cd704ba2df13..dc158454556a 100644
--- a/clang/lib/Sema/OpenCLBuiltins.td
+++ b/clang/lib/Sema/OpenCLBuiltins.td
@@ -57,14 +57,33 @@ class FunctionExtension<string _Ext> : AbstractExtension<_Ext>;
// disabled.
class TypeExtension<string _Ext> : AbstractExtension<_Ext>;
+// Concatenate zero or more space-separated extensions in NewExts to Base and
+// return the resulting FunctionExtension in ret.
+class concatExtension<FunctionExtension Base, string NewExts> {
+ FunctionExtension ret = FunctionExtension<
+ !cond(
+ // Return Base extension if NewExts is empty,
+ !empty(NewExts) : Base.ExtName,
+
+ // otherwise, return NewExts if Base extension is empty,
+ !empty(Base.ExtName) : NewExts,
+
+ // otherwise, concatenate NewExts to Base.
+ true : Base.ExtName # " " # NewExts
+ )
+ >;
+}
+
// TypeExtension definitions.
def NoTypeExt : TypeExtension<"">;
def Fp16TypeExt : TypeExtension<"cl_khr_fp16">;
def Fp64TypeExt : TypeExtension<"cl_khr_fp64">;
+def Atomic64TypeExt : TypeExtension<"cl_khr_int64_base_atomics cl_khr_int64_extended_atomics">;
+def AtomicFp64TypeExt : TypeExtension<"cl_khr_int64_base_atomics cl_khr_int64_extended_atomics cl_khr_fp64">;
// FunctionExtension definitions.
def FuncExtNone : FunctionExtension<"">;
-def FuncExtKhrSubgroups : FunctionExtension<"cl_khr_subgroups">;
+def FuncExtKhrSubgroups : FunctionExtension<"__opencl_subgroup_builtins">;
def FuncExtKhrSubgroupExtendedTypes : FunctionExtension<"cl_khr_subgroup_extended_types">;
def FuncExtKhrSubgroupNonUniformVote : FunctionExtension<"cl_khr_subgroup_non_uniform_vote">;
def FuncExtKhrSubgroupBallot : FunctionExtension<"cl_khr_subgroup_ballot">;
@@ -80,44 +99,40 @@ def FuncExtKhrLocalInt32ExtendedAtomics : FunctionExtension<"cl_khr_local_int32
def FuncExtKhrInt64BaseAtomics : FunctionExtension<"cl_khr_int64_base_atomics">;
def FuncExtKhrInt64ExtendedAtomics : FunctionExtension<"cl_khr_int64_extended_atomics">;
def FuncExtKhrMipmapImage : FunctionExtension<"cl_khr_mipmap_image">;
-def FuncExtKhrMipmapImageReadWrite : FunctionExtension<"cl_khr_mipmap_image __opencl_c_read_write_images">;
def FuncExtKhrMipmapImageWrites : FunctionExtension<"cl_khr_mipmap_image_writes">;
def FuncExtKhrGlMsaaSharing : FunctionExtension<"cl_khr_gl_msaa_sharing">;
-def FuncExtKhrGlMsaaSharingReadWrite : FunctionExtension<"cl_khr_gl_msaa_sharing __opencl_c_read_write_images">;
+def FuncExtOpenCLCDeviceEnqueue : FunctionExtension<"__opencl_c_device_enqueue">;
def FuncExtOpenCLCGenericAddressSpace : FunctionExtension<"__opencl_c_generic_address_space">;
def FuncExtOpenCLCNamedAddressSpaceBuiltins : FunctionExtension<"__opencl_c_named_address_space_builtins">;
def FuncExtOpenCLCPipes : FunctionExtension<"__opencl_c_pipes">;
def FuncExtOpenCLCWGCollectiveFunctions : FunctionExtension<"__opencl_c_work_group_collective_functions">;
def FuncExtOpenCLCReadWriteImages : FunctionExtension<"__opencl_c_read_write_images">;
-def FuncExtFloatAtomicsFp16GlobalLoadStore : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp16_global_atomic_load_store">;
-def FuncExtFloatAtomicsFp16LocalLoadStore : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp16_local_atomic_load_store">;
-def FuncExtFloatAtomicsFp16GenericLoadStore : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp16_global_atomic_load_store __opencl_c_ext_fp16_local_atomic_load_store">;
-def FuncExtFloatAtomicsFp16GlobalAdd : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp16_global_atomic_add">;
-def FuncExtFloatAtomicsFp32GlobalAdd : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp32_global_atomic_add">;
-def FuncExtFloatAtomicsFp64GlobalAdd : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp64_global_atomic_add">;
-def FuncExtFloatAtomicsFp16LocalAdd : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp16_local_atomic_add">;
-def FuncExtFloatAtomicsFp32LocalAdd : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp32_local_atomic_add">;
-def FuncExtFloatAtomicsFp64LocalAdd : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp64_local_atomic_add">;
-def FuncExtFloatAtomicsFp16GenericAdd : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp16_local_atomic_add __opencl_c_ext_fp16_global_atomic_add">;
-def FuncExtFloatAtomicsFp32GenericAdd : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp32_local_atomic_add __opencl_c_ext_fp32_global_atomic_add">;
-def FuncExtFloatAtomicsFp64GenericAdd : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp64_local_atomic_add __opencl_c_ext_fp64_global_atomic_add">;
-def FuncExtFloatAtomicsFp16GlobalMinMax : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp16_global_atomic_min_max">;
-def FuncExtFloatAtomicsFp32GlobalMinMax : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp32_global_atomic_min_max">;
-def FuncExtFloatAtomicsFp64GlobalMinMax : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp64_global_atomic_min_max">;
-def FuncExtFloatAtomicsFp16LocalMinMax : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp16_local_atomic_min_max">;
-def FuncExtFloatAtomicsFp32LocalMinMax : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp32_local_atomic_min_max">;
-def FuncExtFloatAtomicsFp64LocalMinMax : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp64_local_atomic_min_max">;
-def FuncExtFloatAtomicsFp16GenericMinMax : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp16_local_atomic_min_max __opencl_c_ext_fp16_global_atomic_min_max">;
-def FuncExtFloatAtomicsFp32GenericMinMax : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp32_local_atomic_min_max __opencl_c_ext_fp32_global_atomic_min_max">;
-def FuncExtFloatAtomicsFp64GenericMinMax : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp64_local_atomic_min_max __opencl_c_ext_fp64_global_atomic_min_max">;
+def FuncExtFloatAtomicsFp16GlobalASLoadStore : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp16_global_atomic_load_store">;
+def FuncExtFloatAtomicsFp16LocalASLoadStore : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp16_local_atomic_load_store">;
+def FuncExtFloatAtomicsFp16GenericASLoadStore : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp16_global_atomic_load_store __opencl_c_ext_fp16_local_atomic_load_store">;
+def FuncExtFloatAtomicsFp16GlobalASAdd : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp16_global_atomic_add">;
+def FuncExtFloatAtomicsFp32GlobalASAdd : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp32_global_atomic_add">;
+def FuncExtFloatAtomicsFp64GlobalASAdd : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp64_global_atomic_add">;
+def FuncExtFloatAtomicsFp16LocalASAdd : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp16_local_atomic_add">;
+def FuncExtFloatAtomicsFp32LocalASAdd : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp32_local_atomic_add">;
+def FuncExtFloatAtomicsFp64LocalASAdd : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp64_local_atomic_add">;
+def FuncExtFloatAtomicsFp16GenericASAdd : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp16_local_atomic_add __opencl_c_ext_fp16_global_atomic_add">;
+def FuncExtFloatAtomicsFp32GenericASAdd : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp32_local_atomic_add __opencl_c_ext_fp32_global_atomic_add">;
+def FuncExtFloatAtomicsFp64GenericASAdd : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp64_local_atomic_add __opencl_c_ext_fp64_global_atomic_add">;
+def FuncExtFloatAtomicsFp16GlobalASMinMax : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp16_global_atomic_min_max">;
+def FuncExtFloatAtomicsFp32GlobalASMinMax : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp32_global_atomic_min_max">;
+def FuncExtFloatAtomicsFp64GlobalASMinMax : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp64_global_atomic_min_max">;
+def FuncExtFloatAtomicsFp16LocalASMinMax : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp16_local_atomic_min_max">;
+def FuncExtFloatAtomicsFp32LocalASMinMax : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp32_local_atomic_min_max">;
+def FuncExtFloatAtomicsFp64LocalASMinMax : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp64_local_atomic_min_max">;
+def FuncExtFloatAtomicsFp16GenericASMinMax : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp16_local_atomic_min_max __opencl_c_ext_fp16_global_atomic_min_max">;
+def FuncExtFloatAtomicsFp32GenericASMinMax : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp32_local_atomic_min_max __opencl_c_ext_fp32_global_atomic_min_max">;
+def FuncExtFloatAtomicsFp64GenericASMinMax : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp64_local_atomic_min_max __opencl_c_ext_fp64_global_atomic_min_max">;
// Not a real extension, but a workaround to add C++ for OpenCL specific builtins.
def FuncExtOpenCLCxx : FunctionExtension<"__cplusplus">;
-// Multiple extensions
-def FuncExtKhrMipmapWritesAndWrite3d : FunctionExtension<"cl_khr_mipmap_image_writes cl_khr_3d_image_writes">;
-
// Arm extensions.
def ArmIntegerDotProductInt8 : FunctionExtension<"cl_arm_integer_dot_product_int8">;
def ArmIntegerDotProductAccumulateInt8 : FunctionExtension<"cl_arm_integer_dot_product_accumulate_int8">;
@@ -227,7 +242,12 @@ class ImageType<Type _Ty, string _AccessQualifier> :
let IsConst = _Ty.IsConst;
let IsVolatile = _Ty.IsVolatile;
let AddrSpace = _Ty.AddrSpace;
- let Extension = _Ty.Extension;
+ // Add TypeExtensions for writable "image3d_t" and "read_write" image types.
+ let Extension = !cond(
+ !and(!eq(_Ty.Name, "image3d_t"), !eq(_AccessQualifier, "WO")) : TypeExtension<"cl_khr_3d_image_writes">,
+ !and(!eq(_Ty.Name, "image3d_t"), !eq(_AccessQualifier, "RW")) : TypeExtension<"cl_khr_3d_image_writes __opencl_c_read_write_images">,
+ !eq(_AccessQualifier, "RW") : TypeExtension<"__opencl_c_read_write_images">,
+ true : _Ty.Extension);
}
// OpenCL enum type (e.g. memory_scope).
@@ -332,9 +352,22 @@ def Float : Type<"float", QualType<"Context.FloatTy">>;
let Extension = Fp64TypeExt in {
def Double : Type<"double", QualType<"Context.DoubleTy">>;
}
+
+// The half type for builtins that require the cl_khr_fp16 extension.
let Extension = Fp16TypeExt in {
def Half : Type<"half", QualType<"Context.HalfTy">>;
}
+
+// Without the cl_khr_fp16 extension, the half type can only be used to declare
+// a pointer. Define const and non-const pointer types in all address spaces.
+// Use the "__half" alias to allow the TableGen emitter to distinguish the
+// (extensionless) pointee type of these pointer-to-half types from the "half"
+// type defined above that already carries the cl_khr_fp16 extension.
+foreach AS = [PrivateAS, GlobalAS, ConstantAS, LocalAS, GenericAS] in {
+ def "HalfPtr" # AS : PointerType<Type<"__half", QualType<"Context.HalfTy">>, AS>;
+ def "HalfPtrConst" # AS : PointerType<ConstType<Type<"__half", QualType<"Context.HalfTy">>>, AS>;
+}
+
def Size : Type<"size_t", QualType<"Context.getSizeType()">>;
def PtrDiff : Type<"ptrdiff_t", QualType<"Context.getPointerDiffType()">>;
def IntPtr : Type<"intptr_t", QualType<"Context.getIntPtrType()">>;
@@ -372,10 +405,14 @@ def NDRange : TypedefType<"ndrange_t">;
// OpenCL v2.0 s6.13.11: Atomic integer and floating-point types.
def AtomicInt : Type<"atomic_int", QualType<"Context.getAtomicType(Context.IntTy)">>;
def AtomicUInt : Type<"atomic_uint", QualType<"Context.getAtomicType(Context.UnsignedIntTy)">>;
-def AtomicLong : Type<"atomic_long", QualType<"Context.getAtomicType(Context.LongTy)">>;
-def AtomicULong : Type<"atomic_ulong", QualType<"Context.getAtomicType(Context.UnsignedLongTy)">>;
+let Extension = Atomic64TypeExt in {
+ def AtomicLong : Type<"atomic_long", QualType<"Context.getAtomicType(Context.LongTy)">>;
+ def AtomicULong : Type<"atomic_ulong", QualType<"Context.getAtomicType(Context.UnsignedLongTy)">>;
+}
def AtomicFloat : Type<"atomic_float", QualType<"Context.getAtomicType(Context.FloatTy)">>;
-def AtomicDouble : Type<"atomic_double", QualType<"Context.getAtomicType(Context.DoubleTy)">>;
+let Extension = AtomicFp64TypeExt in {
+ def AtomicDouble : Type<"atomic_double", QualType<"Context.getAtomicType(Context.DoubleTy)">>;
+}
def AtomicHalf : Type<"atomic_half", QualType<"Context.getAtomicType(Context.HalfTy)">>;
def AtomicIntPtr : Type<"atomic_intptr_t", QualType<"Context.getAtomicType(Context.getIntPtrType())">>;
def AtomicUIntPtr : Type<"atomic_uintptr_t", QualType<"Context.getAtomicType(Context.getUIntPtrType())">>;
@@ -853,22 +890,22 @@ defm : VloadVstore<[ConstantAS], 0>;
multiclass VloadVstoreHalf<list<AddressSpace> addrspaces, bit defStores> {
foreach AS = addrspaces in {
- def : Builtin<"vload_half", [Float, Size, PointerType<ConstType<Half>, AS>], Attr.Pure>;
+ def : Builtin<"vload_half", [Float, Size, !cast<Type>("HalfPtrConst" # AS)], Attr.Pure>;
foreach VSize = [2, 3, 4, 8, 16] in {
foreach name = ["vload_half" # VSize, "vloada_half" # VSize] in {
- def : Builtin<name, [VectorType<Float, VSize>, Size, PointerType<ConstType<Half>, AS>], Attr.Pure>;
+ def : Builtin<name, [VectorType<Float, VSize>, Size, !cast<Type>("HalfPtrConst" # AS)], Attr.Pure>;
}
}
if defStores then {
foreach rnd = ["", "_rte", "_rtz", "_rtp", "_rtn"] in {
foreach name = ["vstore_half" # rnd] in {
- def : Builtin<name, [Void, Float, Size, PointerType<Half, AS>]>;
- def : Builtin<name, [Void, Double, Size, PointerType<Half, AS>]>;
+ def : Builtin<name, [Void, Float, Size, !cast<Type>("HalfPtr" # AS)]>;
+ def : Builtin<name, [Void, Double, Size, !cast<Type>("HalfPtr" # AS)]>;
}
foreach VSize = [2, 3, 4, 8, 16] in {
foreach name = ["vstore_half" # VSize # rnd, "vstorea_half" # VSize # rnd] in {
- def : Builtin<name, [Void, VectorType<Float, VSize>, Size, PointerType<Half, AS>]>;
- def : Builtin<name, [Void, VectorType<Double, VSize>, Size, PointerType<Half, AS>]>;
+ def : Builtin<name, [Void, VectorType<Float, VSize>, Size, !cast<Type>("HalfPtr" # AS)]>;
+ def : Builtin<name, [Void, VectorType<Double, VSize>, Size, !cast<Type>("HalfPtr" # AS)]>;
}
}
}
@@ -900,7 +937,7 @@ def : Builtin<"write_mem_fence", [Void, MemFenceFlags]>;
// OpenCL v3.0 s6.15.10 - Address Space Qualifier Functions.
// to_global, to_local, to_private are declared in Builtins.def.
-let MinVersion = CL20 in {
+let Extension = FuncExtOpenCLCGenericAddressSpace in {
// The OpenCL 3.0 specification defines these with a "gentype" argument indicating any builtin
// type or user-defined type, which cannot be represented currently. Hence we slightly diverge
// by providing only the following overloads with a void pointer.
@@ -1041,42 +1078,61 @@ let Extension = FuncExtOpenCLCxx in {
}
// OpenCL v2.0 s6.13.11 - Atomic Functions.
-let MinVersion = CL20 in {
- def : Builtin<"atomic_work_item_fence", [Void, MemFenceFlags, MemoryOrder, MemoryScope]>;
+// An atomic builtin with 2 additional _explicit variants.
+multiclass BuiltinAtomicExplicit<string Name, list<Type> Types, FunctionExtension BaseExt> {
+ // Without explicit MemoryOrder or MemoryScope.
+ let Extension = concatExtension<BaseExt, "__opencl_c_atomic_order_seq_cst __opencl_c_atomic_scope_device">.ret in {
+ def : Builtin<Name, Types>;
+ }
+
+ // With an explicit MemoryOrder argument.
+ let Extension = concatExtension<BaseExt, "__opencl_c_atomic_scope_device">.ret in {
+ def : Builtin<Name # "_explicit", !listconcat(Types, [MemoryOrder])>;
+ }
+
+ // With explicit MemoryOrder and MemoryScope arguments.
+ let Extension = BaseExt in {
+ def : Builtin<Name # "_explicit", !listconcat(Types, [MemoryOrder, MemoryScope])>;
+ }
+}
+
+// OpenCL 2.0 atomic functions that have a pointer argument in a given address space.
+multiclass OpenCL2Atomics<AddressSpace addrspace, FunctionExtension BaseExt> {
foreach TypePair = [[AtomicInt, Int], [AtomicUInt, UInt],
[AtomicLong, Long], [AtomicULong, ULong],
[AtomicFloat, Float], [AtomicDouble, Double]] in {
- def : Builtin<"atomic_init",
- [Void, PointerType<VolatileType<TypePair[0]>, GenericAS>, TypePair[1]]>;
- def : Builtin<"atomic_store",
- [Void, PointerType<VolatileType<TypePair[0]>, GenericAS>, TypePair[1]]>;
- def : Builtin<"atomic_store_explicit",
- [Void, PointerType<VolatileType<TypePair[0]>, GenericAS>, TypePair[1], MemoryOrder]>;
- def : Builtin<"atomic_store_explicit",
- [Void, PointerType<VolatileType<TypePair[0]>, GenericAS>, TypePair[1], MemoryOrder, MemoryScope]>;
- def : Builtin<"atomic_load",
- [TypePair[1], PointerType<VolatileType<TypePair[0]>, GenericAS>]>;
- def : Builtin<"atomic_load_explicit",
- [TypePair[1], PointerType<VolatileType<TypePair[0]>, GenericAS>, MemoryOrder]>;
- def : Builtin<"atomic_load_explicit",
- [TypePair[1], PointerType<VolatileType<TypePair[0]>, GenericAS>, MemoryOrder, MemoryScope]>;
- def : Builtin<"atomic_exchange",
- [TypePair[1], PointerType<VolatileType<TypePair[0]>, GenericAS>, TypePair[1]]>;
- def : Builtin<"atomic_exchange_explicit",
- [TypePair[1], PointerType<VolatileType<TypePair[0]>, GenericAS>, TypePair[1], MemoryOrder]>;
- def : Builtin<"atomic_exchange_explicit",
- [TypePair[1], PointerType<VolatileType<TypePair[0]>, GenericAS>, TypePair[1], MemoryOrder, MemoryScope]>;
+ let Extension = BaseExt in {
+ def : Builtin<"atomic_init",
+ [Void, PointerType<VolatileType<TypePair[0]>, addrspace>, TypePair[1]]>;
+ }
+ defm : BuiltinAtomicExplicit<"atomic_store",
+ [Void, PointerType<VolatileType<TypePair[0]>, addrspace>, TypePair[1]], BaseExt>;
+ defm : BuiltinAtomicExplicit<"atomic_load",
+ [TypePair[1], PointerType<VolatileType<TypePair[0]>, addrspace>], BaseExt>;
+ defm : BuiltinAtomicExplicit<"atomic_exchange",
+ [TypePair[1], PointerType<VolatileType<TypePair[0]>, addrspace>, TypePair[1]], BaseExt>;
foreach Variant = ["weak", "strong"] in {
- def : Builtin<"atomic_compare_exchange_" # Variant,
- [Bool, PointerType<VolatileType<TypePair[0]>, GenericAS>,
- PointerType<TypePair[1], GenericAS>, TypePair[1]]>;
- def : Builtin<"atomic_compare_exchange_" # Variant # "_explicit",
- [Bool, PointerType<VolatileType<TypePair[0]>, GenericAS>,
- PointerType<TypePair[1], GenericAS>, TypePair[1], MemoryOrder, MemoryOrder]>;
- def : Builtin<"atomic_compare_exchange_" # Variant # "_explicit",
- [Bool, PointerType<VolatileType<TypePair[0]>, GenericAS>,
- PointerType<TypePair[1], GenericAS>, TypePair[1], MemoryOrder, MemoryOrder, MemoryScope]>;
+ foreach exp_ptr_addrspace = !cond(
+ !eq(BaseExt, FuncExtOpenCLCGenericAddressSpace): [GenericAS],
+ !eq(BaseExt, FuncExtOpenCLCNamedAddressSpaceBuiltins): [GlobalAS, LocalAS, PrivateAS])
+ in {
+ let Extension = concatExtension<BaseExt, "__opencl_c_atomic_order_seq_cst __opencl_c_atomic_scope_device">.ret in {
+ def : Builtin<"atomic_compare_exchange_" # Variant,
+ [Bool, PointerType<VolatileType<TypePair[0]>, addrspace>,
+ PointerType<TypePair[1], exp_ptr_addrspace>, TypePair[1]]>;
+ }
+ let Extension = concatExtension<BaseExt, "__opencl_c_atomic_scope_device">.ret in {
+ def : Builtin<"atomic_compare_exchange_" # Variant # "_explicit",
+ [Bool, PointerType<VolatileType<TypePair[0]>, addrspace>,
+ PointerType<TypePair[1], exp_ptr_addrspace>, TypePair[1], MemoryOrder, MemoryOrder]>;
+ }
+ let Extension = BaseExt in {
+ def : Builtin<"atomic_compare_exchange_" # Variant # "_explicit",
+ [Bool, PointerType<VolatileType<TypePair[0]>, addrspace>,
+ PointerType<TypePair[1], exp_ptr_addrspace>, TypePair[1], MemoryOrder, MemoryOrder, MemoryScope]>;
+ }
+ }
}
}
@@ -1084,249 +1140,69 @@ let MinVersion = CL20 in {
[AtomicLong, Long, Long], [AtomicULong, ULong, ULong],
[AtomicUIntPtr, UIntPtr, PtrDiff]] in {
foreach ModOp = ["add", "sub"] in {
- def : Builtin<"atomic_fetch_" # ModOp,
- [TypePair[1], PointerType<VolatileType<TypePair[0]>, GenericAS>, TypePair[2]]>;
- def : Builtin<"atomic_fetch_" # ModOp # "_explicit",
- [TypePair[1], PointerType<VolatileType<TypePair[0]>, GenericAS>, TypePair[2], MemoryOrder]>;
- def : Builtin<"atomic_fetch_" # ModOp # "_explicit",
- [TypePair[1], PointerType<VolatileType<TypePair[0]>, GenericAS>, TypePair[2], MemoryOrder, MemoryScope]>;
+ defm : BuiltinAtomicExplicit<"atomic_fetch_" # ModOp,
+ [TypePair[1], PointerType<VolatileType<TypePair[0]>, addrspace>, TypePair[2]], BaseExt>;
}
}
foreach TypePair = [[AtomicInt, Int, Int], [AtomicUInt, UInt, UInt],
[AtomicLong, Long, Long], [AtomicULong, ULong, ULong]] in {
foreach ModOp = ["or", "xor", "and", "min", "max"] in {
- def : Builtin<"atomic_fetch_" # ModOp,
- [TypePair[1], PointerType<VolatileType<TypePair[0]>, GenericAS>, TypePair[2]]>;
- def : Builtin<"atomic_fetch_" # ModOp # "_explicit",
- [TypePair[1], PointerType<VolatileType<TypePair[0]>, GenericAS>, TypePair[2], MemoryOrder]>;
- def : Builtin<"atomic_fetch_" # ModOp # "_explicit",
- [TypePair[1], PointerType<VolatileType<TypePair[0]>, GenericAS>, TypePair[2], MemoryOrder, MemoryScope]>;
+ defm : BuiltinAtomicExplicit<"atomic_fetch_" # ModOp,
+ [TypePair[1], PointerType<VolatileType<TypePair[0]>, addrspace>, TypePair[2]], BaseExt>;
}
}
- def : Builtin<"atomic_flag_clear",
- [Void, PointerType<VolatileType<AtomicFlag>, GenericAS>]>;
- def : Builtin<"atomic_flag_clear_explicit",
- [Void, PointerType<VolatileType<AtomicFlag>, GenericAS>, MemoryOrder]>;
- def : Builtin<"atomic_flag_clear_explicit",
- [Void, PointerType<VolatileType<AtomicFlag>, GenericAS>, MemoryOrder, MemoryScope]>;
+ defm : BuiltinAtomicExplicit<"atomic_flag_clear",
+ [Void, PointerType<VolatileType<AtomicFlag>, addrspace>], BaseExt>;
- def : Builtin<"atomic_flag_test_and_set",
- [Bool, PointerType<VolatileType<AtomicFlag>, GenericAS>]>;
- def : Builtin<"atomic_flag_test_and_set_explicit",
- [Bool, PointerType<VolatileType<AtomicFlag>, GenericAS>, MemoryOrder]>;
- def : Builtin<"atomic_flag_test_and_set_explicit",
- [Bool, PointerType<VolatileType<AtomicFlag>, GenericAS>, MemoryOrder, MemoryScope]>;
+ defm : BuiltinAtomicExplicit<"atomic_flag_test_and_set",
+ [Bool, PointerType<VolatileType<AtomicFlag>, addrspace>], BaseExt>;
+}
+
+let MinVersion = CL20 in {
+ def : Builtin<"atomic_work_item_fence", [Void, MemFenceFlags, MemoryOrder, MemoryScope]>;
+
+ defm : OpenCL2Atomics<GenericAS, FuncExtOpenCLCGenericAddressSpace>;
+ defm : OpenCL2Atomics<GlobalAS, FuncExtOpenCLCNamedAddressSpaceBuiltins>;
+ defm : OpenCL2Atomics<LocalAS, FuncExtOpenCLCNamedAddressSpaceBuiltins>;
}
// The functionality added by cl_ext_float_atomics extension
let MinVersion = CL20 in {
- let Extension = FuncExtFloatAtomicsFp16GlobalLoadStore in {
- def : Builtin<"atomic_store",
- [Void, PointerType<VolatileType<AtomicHalf>, GlobalAS>, AtomicHalf]>;
- def : Builtin<"atomic_store_explicit",
- [Void, PointerType<VolatileType<AtomicHalf>, GlobalAS>, AtomicHalf, MemoryOrder]>;
- def : Builtin<"atomic_store_explicit",
- [Void, PointerType<VolatileType<AtomicHalf>, GlobalAS>, AtomicHalf, MemoryOrder, MemoryScope]>;
- def : Builtin<"atomic_load",
- [Half, PointerType<VolatileType<AtomicHalf>, GlobalAS>]>;
- def : Builtin<"atomic_load_explicit",
- [Half, PointerType<VolatileType<AtomicHalf>, GlobalAS>, MemoryOrder]>;
- def : Builtin<"atomic_load_explicit",
- [Half, PointerType<VolatileType<AtomicHalf>, GlobalAS>, MemoryOrder, MemoryScope]>;
- def : Builtin<"atomic_exchange",
- [Half, PointerType<VolatileType<AtomicHalf>, GlobalAS>, Half]>;
- def : Builtin<"atomic_exchange_explicit",
- [Half, PointerType<VolatileType<AtomicHalf>, GlobalAS>, Half, MemoryOrder]>;
- def : Builtin<"atomic_exchange_explicit",
- [Half, PointerType<VolatileType<AtomicHalf>, GlobalAS>, Half, MemoryOrder, MemoryScope]>;
- }
- let Extension = FuncExtFloatAtomicsFp16LocalLoadStore in {
- def : Builtin<"atomic_store",
- [Void, PointerType<VolatileType<AtomicHalf>, LocalAS>, AtomicHalf]>;
- def : Builtin<"atomic_store_explicit",
- [Void, PointerType<VolatileType<AtomicHalf>, LocalAS>, AtomicHalf, MemoryOrder]>;
- def : Builtin<"atomic_store_explicit",
- [Void, PointerType<VolatileType<AtomicHalf>, LocalAS>, AtomicHalf, MemoryOrder, MemoryScope]>;
- def : Builtin<"atomic_load",
- [Half, PointerType<VolatileType<AtomicHalf>, LocalAS>]>;
- def : Builtin<"atomic_load_explicit",
- [Half, PointerType<VolatileType<AtomicHalf>, LocalAS>, MemoryOrder]>;
- def : Builtin<"atomic_load_explicit",
- [Half, PointerType<VolatileType<AtomicHalf>, LocalAS>, MemoryOrder, MemoryScope]>;
- def : Builtin<"atomic_exchange",
- [Half, PointerType<VolatileType<AtomicHalf>, LocalAS>, Half]>;
- def : Builtin<"atomic_exchange_explicit",
- [Half, PointerType<VolatileType<AtomicHalf>, LocalAS>, Half, MemoryOrder]>;
- def : Builtin<"atomic_exchange_explicit",
- [Half, PointerType<VolatileType<AtomicHalf>, LocalAS>, Half, MemoryOrder, MemoryScope]>;
- }
- let Extension = FuncExtFloatAtomicsFp16GenericLoadStore in {
- def : Builtin<"atomic_store",
- [Void, PointerType<VolatileType<AtomicHalf>, GenericAS>, AtomicHalf]>;
- def : Builtin<"atomic_store_explicit",
- [Void, PointerType<VolatileType<AtomicHalf>, GenericAS>, AtomicHalf, MemoryOrder]>;
- def : Builtin<"atomic_store_explicit",
- [Void, PointerType<VolatileType<AtomicHalf>, GenericAS>, AtomicHalf, MemoryOrder, MemoryScope]>;
- def : Builtin<"atomic_load",
- [Half, PointerType<VolatileType<AtomicHalf>, GenericAS>]>;
- def : Builtin<"atomic_load_explicit",
- [Half, PointerType<VolatileType<AtomicHalf>, GenericAS>, MemoryOrder]>;
- def : Builtin<"atomic_load_explicit",
- [Half, PointerType<VolatileType<AtomicHalf>, GenericAS>, MemoryOrder, MemoryScope]>;
- def : Builtin<"atomic_exchange",
- [Half, PointerType<VolatileType<AtomicHalf>, GenericAS>, Half]>;
- def : Builtin<"atomic_exchange_explicit",
- [Half, PointerType<VolatileType<AtomicHalf>, GenericAS>, Half, MemoryOrder]>;
- def : Builtin<"atomic_exchange_explicit",
- [Half, PointerType<VolatileType<AtomicHalf>, GenericAS>, Half, MemoryOrder, MemoryScope]>;
- }
- foreach ModOp = ["add", "sub"] in {
- let Extension = FuncExtFloatAtomicsFp16GlobalAdd in {
- def : Builtin<"atomic_fetch_" # ModOp,
- [Half, PointerType<VolatileType<AtomicFloat>, GlobalAS>, Half]>;
- def : Builtin<"atomic_fetch_" # ModOp # "_explicit",
- [Half, PointerType<VolatileType<AtomicFloat>, GlobalAS>, Half, MemoryOrder]>;
- def : Builtin<"atomic_fetch_" # ModOp # "_explicit",
- [Half, PointerType<VolatileType<AtomicFloat>, GlobalAS>, Half, MemoryOrder, MemoryScope]>;
- }
- let Extension = FuncExtFloatAtomicsFp32GlobalAdd in {
- def : Builtin<"atomic_fetch_" # ModOp,
- [Float, PointerType<VolatileType<AtomicFloat>, GlobalAS>, Float]>;
- def : Builtin<"atomic_fetch_" # ModOp # "_explicit",
- [Float, PointerType<VolatileType<AtomicFloat>, GlobalAS>, Float, MemoryOrder]>;
- def : Builtin<"atomic_fetch_" # ModOp # "_explicit",
- [Float, PointerType<VolatileType<AtomicFloat>, GlobalAS>, Float, MemoryOrder, MemoryScope]>;
- }
- let Extension = FuncExtFloatAtomicsFp64GlobalAdd in {
- def : Builtin<"atomic_fetch_" # ModOp,
- [Double, PointerType<VolatileType<AtomicDouble>, GlobalAS>, Double]>;
- def : Builtin<"atomic_fetch_" # ModOp # "_explicit",
- [Double, PointerType<VolatileType<AtomicDouble>, GlobalAS>, Double, MemoryOrder]>;
- def : Builtin<"atomic_fetch_" # ModOp # "_explicit",
- [Double, PointerType<VolatileType<AtomicDouble>, GlobalAS>, Double, MemoryOrder, MemoryScope]>;
- }
- let Extension = FuncExtFloatAtomicsFp16LocalAdd in {
- def : Builtin<"atomic_fetch_" # ModOp,
- [Half, PointerType<VolatileType<AtomicFloat>, LocalAS>, Half]>;
- def : Builtin<"atomic_fetch_" # ModOp # "_explicit",
- [Half, PointerType<VolatileType<AtomicFloat>, LocalAS>, Half, MemoryOrder]>;
- def : Builtin<"atomic_fetch_" # ModOp # "_explicit",
- [Half, PointerType<VolatileType<AtomicFloat>, LocalAS>, Half, MemoryOrder, MemoryScope]>;
- }
- let Extension = FuncExtFloatAtomicsFp32LocalAdd in {
- def : Builtin<"atomic_fetch_" # ModOp,
- [Float, PointerType<VolatileType<AtomicFloat>, LocalAS>, Float]>;
- def : Builtin<"atomic_fetch_" # ModOp # "_explicit",
- [Float, PointerType<VolatileType<AtomicFloat>, LocalAS>, Float, MemoryOrder]>;
- def : Builtin<"atomic_fetch_" # ModOp # "_explicit",
- [Float, PointerType<VolatileType<AtomicFloat>, LocalAS>, Float, MemoryOrder, MemoryScope]>;
- }
- let Extension = FuncExtFloatAtomicsFp64LocalAdd in {
- def : Builtin<"atomic_fetch_" # ModOp,
- [Double, PointerType<VolatileType<AtomicDouble>, LocalAS>, Double]>;
- def : Builtin<"atomic_fetch_" # ModOp # "_explicit",
- [Double, PointerType<VolatileType<AtomicDouble>, LocalAS>, Double, MemoryOrder]>;
- def : Builtin<"atomic_fetch_" # ModOp # "_explicit",
- [Double, PointerType<VolatileType<AtomicDouble>, LocalAS>, Double, MemoryOrder, MemoryScope]>;
- }
- let Extension = FuncExtFloatAtomicsFp16GenericAdd in {
- def : Builtin<"atomic_fetch_" # ModOp,
- [Half, PointerType<VolatileType<AtomicFloat>, GenericAS>, Half]>;
- def : Builtin<"atomic_fetch_" # ModOp # "_explicit",
- [Half, PointerType<VolatileType<AtomicFloat>, GenericAS>, Half, MemoryOrder]>;
- def : Builtin<"atomic_fetch_" # ModOp # "_explicit",
- [Half, PointerType<VolatileType<AtomicFloat>, GenericAS>, Half, MemoryOrder, MemoryScope]>;
- }
- let Extension = FuncExtFloatAtomicsFp32GenericAdd in {
- def : Builtin<"atomic_fetch_" # ModOp,
- [Float, PointerType<VolatileType<AtomicFloat>, GenericAS>, Float]>;
- def : Builtin<"atomic_fetch_" # ModOp # "_explicit",
- [Float, PointerType<VolatileType<AtomicFloat>, GenericAS>, Float, MemoryOrder]>;
- def : Builtin<"atomic_fetch_" # ModOp # "_explicit",
- [Float, PointerType<VolatileType<AtomicFloat>, GenericAS>, Float, MemoryOrder, MemoryScope]>;
- }
- let Extension = FuncExtFloatAtomicsFp64GenericAdd in {
- def : Builtin<"atomic_fetch_" # ModOp,
- [Double, PointerType<VolatileType<AtomicDouble>, GenericAS>, Double]>;
- def : Builtin<"atomic_fetch_" # ModOp # "_explicit",
- [Double, PointerType<VolatileType<AtomicDouble>, GenericAS>, Double, MemoryOrder]>;
- def : Builtin<"atomic_fetch_" # ModOp # "_explicit",
- [Double, PointerType<VolatileType<AtomicDouble>, GenericAS>, Double, MemoryOrder, MemoryScope]>;
- }
- }
- foreach ModOp = ["min", "max"] in {
- let Extension = FuncExtFloatAtomicsFp16GlobalMinMax in {
- def : Builtin<"atomic_fetch_" # ModOp,
- [Half, PointerType<VolatileType<AtomicHalf>, GlobalAS>, Half]>;
- def : Builtin<"atomic_fetch_" # ModOp # "_explicit",
- [Half, PointerType<VolatileType<AtomicHalf>, GlobalAS>, Half, MemoryOrder]>;
- def : Builtin<"atomic_fetch_" # ModOp # "_explicit",
- [Half, PointerType<VolatileType<AtomicHalf>, GlobalAS>, Half, MemoryOrder, MemoryScope]>;
- }
- let Extension = FuncExtFloatAtomicsFp32GlobalMinMax in {
- def : Builtin<"atomic_fetch_" # ModOp,
- [Float, PointerType<VolatileType<AtomicFloat>, GlobalAS>, Float]>;
- def : Builtin<"atomic_fetch_" # ModOp # "_explicit",
- [Float, PointerType<VolatileType<AtomicFloat>, GlobalAS>, Float, MemoryOrder]>;
- def : Builtin<"atomic_fetch_" # ModOp # "_explicit",
- [Float, PointerType<VolatileType<AtomicFloat>, GlobalAS>, Float, MemoryOrder, MemoryScope]>;
- }
- let Extension = FuncExtFloatAtomicsFp64GlobalMinMax in {
- def : Builtin<"atomic_fetch_" # ModOp,
- [Double, PointerType<VolatileType<AtomicDouble>, GlobalAS>, Double]>;
- def : Builtin<"atomic_fetch_" # ModOp # "_explicit",
- [Double, PointerType<VolatileType<AtomicDouble>, GlobalAS>, Double, MemoryOrder]>;
- def : Builtin<"atomic_fetch_" # ModOp # "_explicit",
- [Double, PointerType<VolatileType<AtomicDouble>, GlobalAS>, Double, MemoryOrder, MemoryScope]>;
- }
- let Extension = FuncExtFloatAtomicsFp16LocalMinMax in {
- def : Builtin<"atomic_fetch_" # ModOp,
- [Half, PointerType<VolatileType<AtomicHalf>, LocalAS>, Half]>;
- def : Builtin<"atomic_fetch_" # ModOp # "_explicit",
- [Half, PointerType<VolatileType<AtomicHalf>, LocalAS>, Half, MemoryOrder]>;
- def : Builtin<"atomic_fetch_" # ModOp # "_explicit",
- [Half, PointerType<VolatileType<AtomicHalf>, LocalAS>, Half, MemoryOrder, MemoryScope]>;
- }
- let Extension = FuncExtFloatAtomicsFp32LocalMinMax in {
- def : Builtin<"atomic_fetch_" # ModOp,
- [Float, PointerType<VolatileType<AtomicFloat>, LocalAS>, Float]>;
- def : Builtin<"atomic_fetch_" # ModOp # "_explicit",
- [Float, PointerType<VolatileType<AtomicFloat>, LocalAS>, Float, MemoryOrder]>;
- def : Builtin<"atomic_fetch_" # ModOp # "_explicit",
- [Float, PointerType<VolatileType<AtomicFloat>, LocalAS>, Float, MemoryOrder, MemoryScope]>;
- }
- let Extension = FuncExtFloatAtomicsFp64LocalMinMax in {
- def : Builtin<"atomic_fetch_" # ModOp,
- [Double, PointerType<VolatileType<AtomicDouble>, LocalAS>, Double]>;
- def : Builtin<"atomic_fetch_" # ModOp # "_explicit",
- [Double, PointerType<VolatileType<AtomicDouble>, LocalAS>, Double, MemoryOrder]>;
- def : Builtin<"atomic_fetch_" # ModOp # "_explicit",
- [Double, PointerType<VolatileType<AtomicDouble>, LocalAS>, Double, MemoryOrder, MemoryScope]>;
- }
- let Extension = FuncExtFloatAtomicsFp16GenericMinMax in {
- def : Builtin<"atomic_fetch_" # ModOp,
- [Half, PointerType<VolatileType<AtomicHalf>, GenericAS>, Half]>;
- def : Builtin<"atomic_fetch_" # ModOp # "_explicit",
- [Half, PointerType<VolatileType<AtomicHalf>, GenericAS>, Half, MemoryOrder]>;
- def : Builtin<"atomic_fetch_" # ModOp # "_explicit",
- [Half, PointerType<VolatileType<AtomicHalf>, GenericAS>, Half, MemoryOrder, MemoryScope]>;
- }
- let Extension = FuncExtFloatAtomicsFp32GenericMinMax in {
- def : Builtin<"atomic_fetch_" # ModOp,
- [Float, PointerType<VolatileType<AtomicFloat>, GenericAS>, Float]>;
- def : Builtin<"atomic_fetch_" # ModOp # "_explicit",
- [Float, PointerType<VolatileType<AtomicFloat>, GenericAS>, Float, MemoryOrder]>;
- def : Builtin<"atomic_fetch_" # ModOp # "_explicit",
- [Float, PointerType<VolatileType<AtomicFloat>, GenericAS>, Float, MemoryOrder, MemoryScope]>;
+ foreach addrspace = [GlobalAS, LocalAS, GenericAS] in {
+ defvar extension_fp16 = !cast<FunctionExtension>("FuncExtFloatAtomicsFp16" # addrspace # "LoadStore");
+
+ defm : BuiltinAtomicExplicit<"atomic_store",
+ [Void, PointerType<VolatileType<AtomicHalf>, addrspace>, AtomicHalf], extension_fp16>;
+ defm : BuiltinAtomicExplicit<"atomic_load",
+ [Half, PointerType<VolatileType<AtomicHalf>, addrspace>], extension_fp16>;
+ defm : BuiltinAtomicExplicit<"atomic_exchange",
+ [Half, PointerType<VolatileType<AtomicHalf>, addrspace>, Half], extension_fp16>;
+
+ foreach ModOp = ["add", "sub"] in {
+ defvar extension_fp16 = !cast<FunctionExtension>("FuncExtFloatAtomicsFp16" # addrspace # "Add");
+ defvar extension_fp32 = !cast<FunctionExtension>("FuncExtFloatAtomicsFp32" # addrspace # "Add");
+ defvar extension_fp64 = !cast<FunctionExtension>("FuncExtFloatAtomicsFp64" # addrspace # "Add");
+
+ defm : BuiltinAtomicExplicit<"atomic_fetch_" # ModOp,
+ [Half, PointerType<VolatileType<AtomicHalf>, addrspace>, Half], extension_fp16>;
+ defm : BuiltinAtomicExplicit<"atomic_fetch_" # ModOp,
+ [Float, PointerType<VolatileType<AtomicFloat>, addrspace>, Float], extension_fp32>;
+ defm : BuiltinAtomicExplicit<"atomic_fetch_" # ModOp,
+ [Double, PointerType<VolatileType<AtomicDouble>, addrspace>, Double], extension_fp64>;
}
- let Extension = FuncExtFloatAtomicsFp64GenericMinMax in {
- def : Builtin<"atomic_fetch_" # ModOp,
- [Double, PointerType<VolatileType<AtomicDouble>, GenericAS>, Double]>;
- def : Builtin<"atomic_fetch_" # ModOp # "_explicit",
- [Double, PointerType<VolatileType<AtomicDouble>, GenericAS>, Double, MemoryOrder]>;
- def : Builtin<"atomic_fetch_" # ModOp # "_explicit",
- [Double, PointerType<VolatileType<AtomicDouble>, GenericAS>, Double, MemoryOrder, MemoryScope]>;
+
+ foreach ModOp = ["min", "max"] in {
+ defvar extension_fp16 = !cast<FunctionExtension>("FuncExtFloatAtomicsFp16" # addrspace # "MinMax");
+ defvar extension_fp32 = !cast<FunctionExtension>("FuncExtFloatAtomicsFp32" # addrspace # "MinMax");
+ defvar extension_fp64 = !cast<FunctionExtension>("FuncExtFloatAtomicsFp64" # addrspace # "MinMax");
+
+ defm : BuiltinAtomicExplicit<"atomic_fetch_" # ModOp,
+ [Half, PointerType<VolatileType<AtomicHalf>, addrspace>, Half], extension_fp16>;
+ defm : BuiltinAtomicExplicit<"atomic_fetch_" # ModOp,
+ [Float, PointerType<VolatileType<AtomicFloat>, addrspace>, Float], extension_fp32>;
+ defm : BuiltinAtomicExplicit<"atomic_fetch_" # ModOp,
+ [Double, PointerType<VolatileType<AtomicDouble>, addrspace>, Double], extension_fp64>;
}
}
}
@@ -1592,7 +1468,7 @@ let Extension = FuncExtOpenCLCPipes in {
// Defined in Builtins.def
// --- Table 33 ---
-let MinVersion = CL20 in {
+let Extension = FuncExtOpenCLCDeviceEnqueue in {
def : Builtin<"enqueue_marker",
[Int, Queue, UInt, PointerType<ConstType<ClkEvent>, GenericAS>, PointerType<ClkEvent, GenericAS>]>;
@@ -1731,9 +1607,6 @@ multiclass ImageQueryNumMipLevels<string aQual> {
let Extension = FuncExtKhrMipmapImage in {
defm : ImageQueryNumMipLevels<"RO">;
defm : ImageQueryNumMipLevels<"WO">;
-}
-
-let Extension = FuncExtKhrMipmapImageReadWrite in {
defm : ImageQueryNumMipLevels<"RW">;
}
@@ -1763,12 +1636,10 @@ let Extension = FuncExtKhrMipmapImageWrites in {
def : Builtin<"write_imageui", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, Int, VectorType<UInt, 4>]>;
}
def : Builtin<"write_imagef", [Void, ImageType<Image2dArrayDepth, aQual>, VectorType<Int, 4>, Int, Float]>;
- let Extension = FuncExtKhrMipmapWritesAndWrite3d in {
- foreach imgTy = [Image3d] in {
- def : Builtin<"write_imagef", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, Int, VectorType<Float, 4>]>;
- def : Builtin<"write_imagei", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, Int, VectorType<Int, 4>]>;
- def : Builtin<"write_imageui", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, Int, VectorType<UInt, 4>]>;
- }
+ foreach imgTy = [Image3d] in {
+ def : Builtin<"write_imagef", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, Int, VectorType<Float, 4>]>;
+ def : Builtin<"write_imagei", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, Int, VectorType<Int, 4>]>;
+ def : Builtin<"write_imageui", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, Int, VectorType<UInt, 4>]>;
}
}
}
@@ -1812,9 +1683,6 @@ let Extension = FuncExtKhrGlMsaaSharing in {
defm : ImageReadMsaa<"RO">;
defm : ImageQueryMsaa<"RO">;
defm : ImageQueryMsaa<"WO">;
-}
-
-let Extension = FuncExtKhrGlMsaaSharingReadWrite in {
defm : ImageReadMsaa<"RW">;
defm : ImageQueryMsaa<"RW">;
}
@@ -1838,7 +1706,9 @@ let Extension = FuncExtKhrSubgroups in {
// --- Table 28.2.2 ---
let Extension = FuncExtKhrSubgroups in {
def : Builtin<"sub_group_barrier", [Void, MemFenceFlags], Attr.Convergent>;
- def : Builtin<"sub_group_barrier", [Void, MemFenceFlags, MemoryScope], Attr.Convergent>;
+ let MinVersion = CL20 in {
+ def : Builtin<"sub_group_barrier", [Void, MemFenceFlags, MemoryScope], Attr.Convergent>;
+ }
}
// --- Table 28.2.4 ---
@@ -1975,6 +1845,12 @@ let Extension = FunctionExtension<"__opencl_c_integer_dot_product_input_4x8bit_p
def : Builtin<"dot_acc_sat_4x8packed_su_int", [Int, UInt, UInt, Int], Attr.Const>;
}
+// Section 48.3 - cl_khr_subgroup_rotate
+let Extension = FunctionExtension<"cl_khr_subgroup_rotate"> in {
+ def : Builtin<"sub_group_rotate", [AGenType1, AGenType1, Int], Attr.Convergent>;
+ def : Builtin<"sub_group_clustered_rotate", [AGenType1, AGenType1, Int, UInt], Attr.Convergent>;
+}
+
//--------------------------------------------------------------------
// Arm extensions.
let Extension = ArmIntegerDotProductInt8 in {
diff --git a/clang/lib/Sema/ParsedAttr.cpp b/clang/lib/Sema/ParsedAttr.cpp
index 045847d0ce0f..4b9a694270c5 100644
--- a/clang/lib/Sema/ParsedAttr.cpp
+++ b/clang/lib/Sema/ParsedAttr.cpp
@@ -155,6 +155,10 @@ unsigned ParsedAttr::getMaxArgs() const {
return getMinArgs() + getInfo().OptArgs;
}
+unsigned ParsedAttr::getNumArgMembers() const {
+ return getInfo().NumArgMembers;
+}
+
bool ParsedAttr::hasCustomParsing() const {
return getInfo().HasCustomParsing;
}
@@ -208,6 +212,41 @@ bool ParsedAttr::isSupportedByPragmaAttribute() const {
return getInfo().IsSupportedByPragmaAttribute;
}
+bool ParsedAttr::slidesFromDeclToDeclSpecLegacyBehavior() const {
+ assert(isStandardAttributeSyntax());
+
+ // We have historically allowed some type attributes with standard attribute
+ // syntax to slide to the decl-specifier-seq, so we have to keep supporting
+ // it. This property is consciously not defined as a flag in Attr.td because
+ // we don't want new attributes to specify it.
+ //
+ // Note: No new entries should be added to this list. Entries should be
+ // removed from this list after a suitable deprecation period, provided that
+ // there are no compatibility considerations with other compilers. If
+ // possible, we would like this list to go away entirely.
+ switch (getParsedKind()) {
+ case AT_AddressSpace:
+ case AT_OpenCLPrivateAddressSpace:
+ case AT_OpenCLGlobalAddressSpace:
+ case AT_OpenCLGlobalDeviceAddressSpace:
+ case AT_OpenCLGlobalHostAddressSpace:
+ case AT_OpenCLLocalAddressSpace:
+ case AT_OpenCLConstantAddressSpace:
+ case AT_OpenCLGenericAddressSpace:
+ case AT_NeonPolyVectorType:
+ case AT_NeonVectorType:
+ case AT_ArmMveStrictPolymorphism:
+ case AT_BTFTypeTag:
+ case AT_ObjCGC:
+ case AT_MatrixType:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool ParsedAttr::acceptsExprPack() const { return getInfo().AcceptsExprPack; }
+
unsigned ParsedAttr::getSemanticSpelling() const {
return getInfo().spellingIndexToSemanticSpelling(*this);
}
@@ -220,6 +259,14 @@ bool ParsedAttr::hasVariadicArg() const {
return getInfo().OptArgs == 15;
}
+bool ParsedAttr::isParamExpr(size_t N) const {
+ return getInfo().isParamExpr(N);
+}
+
+void ParsedAttr::handleAttrWithDelayedArgs(Sema &S, Decl *D) const {
+ ::handleAttrWithDelayedArgs(S, D, *this);
+}
+
static unsigned getNumAttributeArgs(const ParsedAttr &AL) {
// FIXME: Include the type in the argument list.
return AL.getNumArgs() + AL.hasParsedType();
@@ -251,3 +298,20 @@ bool ParsedAttr::checkAtMostNumArgs(Sema &S, unsigned Num) const {
diag::err_attribute_too_many_arguments,
std::greater<unsigned>());
}
+
+void clang::takeAndConcatenateAttrs(ParsedAttributes &First,
+ ParsedAttributes &Second,
+ ParsedAttributes &Result) {
+ // Note that takeAllFrom() puts the attributes at the beginning of the list,
+ // so to obtain the correct ordering, we add `Second`, then `First`.
+ Result.takeAllFrom(Second);
+ Result.takeAllFrom(First);
+ if (First.Range.getBegin().isValid())
+ Result.Range.setBegin(First.Range.getBegin());
+ else
+ Result.Range.setBegin(Second.Range.getBegin());
+ if (Second.Range.getEnd().isValid())
+ Result.Range.setEnd(Second.Range.getEnd());
+ else
+ Result.Range.setEnd(First.Range.getEnd());
+}
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 7b57c8da4e9c..326010d4d93f 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -114,6 +114,9 @@ PrintingPolicy Sema::getPrintingPolicy(const ASTContext &Context,
}
}
+ // Shorten the data output if needed
+ Policy.EntireContentsOfLargeArray = false;
+
return Policy;
}
@@ -199,8 +202,9 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
LateTemplateParserCleanup(nullptr), OpaqueParser(nullptr), IdResolver(pp),
StdExperimentalNamespaceCache(nullptr), StdInitializerList(nullptr),
StdCoroutineTraitsCache(nullptr), CXXTypeInfoDecl(nullptr),
- MSVCGuidDecl(nullptr), NSNumberDecl(nullptr), NSValueDecl(nullptr),
- NSStringDecl(nullptr), StringWithUTF8StringMethod(nullptr),
+ MSVCGuidDecl(nullptr), StdSourceLocationImplDecl(nullptr),
+ NSNumberDecl(nullptr), NSValueDecl(nullptr), NSStringDecl(nullptr),
+ StringWithUTF8StringMethod(nullptr),
ValueWithBytesObjCTypeMethod(nullptr), NSArrayDecl(nullptr),
ArrayWithObjectsMethod(nullptr), NSDictionaryDecl(nullptr),
DictionaryWithObjectsMethod(nullptr), GlobalNewDeleteDeclared(false),
@@ -230,6 +234,9 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
// Tell diagnostics how to render things from the AST library.
Diags.SetArgToStringFn(&FormatASTNodeDiagnosticArgument, &Context);
+ // This evaluation context exists to ensure that there's always at least one
+ // valid evaluation context available. It is never removed from the
+ // evaluation stack.
ExprEvalContexts.emplace_back(
ExpressionEvaluationContext::PotentiallyEvaluated, 0, CleanupInfo{},
nullptr, ExpressionEvaluationContextRecord::EK_Other);
@@ -242,6 +249,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
SemaPPCallbackHandler = Callbacks.get();
PP.addPPCallbacks(std::move(Callbacks));
SemaPPCallbackHandler->set(*this);
+
+ CurFPFeatures.setFPEvalMethod(PP.getCurrentFPEvalMethod());
}
// Anchor Sema's type info to this TU.
@@ -908,7 +917,7 @@ void Sema::LoadExternalWeakUndeclaredIdentifiers() {
SmallVector<std::pair<IdentifierInfo *, WeakInfo>, 4> WeakIDs;
ExternalSource->ReadWeakUndeclaredIdentifiers(WeakIDs);
for (auto &WeakID : WeakIDs)
- WeakUndeclaredIdentifiers.insert(WeakID);
+ (void)WeakUndeclaredIdentifiers[WeakID.first].insert(WeakID.second);
}
@@ -1009,9 +1018,13 @@ void Sema::emitAndClearUnusedLocalTypedefWarnings() {
/// is parsed. Note that the ASTContext may have already injected some
/// declarations.
void Sema::ActOnStartOfTranslationUnit() {
- if (getLangOpts().ModulesTS &&
- (getLangOpts().getCompilingModule() == LangOptions::CMK_ModuleInterface ||
- getLangOpts().getCompilingModule() == LangOptions::CMK_None)) {
+ if (getLangOpts().CPlusPlusModules &&
+ getLangOpts().getCompilingModule() == LangOptions::CMK_HeaderUnit)
+ HandleStartOfHeaderUnit();
+ else if (getLangOpts().ModulesTS &&
+ (getLangOpts().getCompilingModule() ==
+ LangOptions::CMK_ModuleInterface ||
+ getLangOpts().getCompilingModule() == LangOptions::CMK_None)) {
// We start in an implied global module fragment.
SourceLocation StartOfTU =
SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID());
@@ -1131,6 +1144,7 @@ void Sema::ActOnEndOfTranslationUnit() {
DiagnoseUnterminatedPragmaAlignPack();
DiagnoseUnterminatedPragmaAttribute();
+ DiagnoseUnterminatedOpenMPDeclareTarget();
// All delayed member exception specs should be checked or we end up accepting
// incompatible declarations.
@@ -1159,19 +1173,21 @@ void Sema::ActOnEndOfTranslationUnit() {
// Check for #pragma weak identifiers that were never declared
LoadExternalWeakUndeclaredIdentifiers();
- for (auto WeakID : WeakUndeclaredIdentifiers) {
- if (WeakID.second.getUsed())
+ for (const auto &WeakIDs : WeakUndeclaredIdentifiers) {
+ if (WeakIDs.second.empty())
continue;
- Decl *PrevDecl = LookupSingleName(TUScope, WeakID.first, SourceLocation(),
+ Decl *PrevDecl = LookupSingleName(TUScope, WeakIDs.first, SourceLocation(),
LookupOrdinaryName);
if (PrevDecl != nullptr &&
!(isa<FunctionDecl>(PrevDecl) || isa<VarDecl>(PrevDecl)))
- Diag(WeakID.second.getLocation(), diag::warn_attribute_wrong_decl_type)
- << "'weak'" << ExpectedVariableOrFunction;
+ for (const auto &WI : WeakIDs.second)
+ Diag(WI.getLocation(), diag::warn_attribute_wrong_decl_type)
+ << "'weak'" << ExpectedVariableOrFunction;
else
- Diag(WeakID.second.getLocation(), diag::warn_weak_identifier_undeclared)
- << WeakID.first;
+ for (const auto &WI : WeakIDs.second)
+ Diag(WI.getLocation(), diag::warn_weak_identifier_undeclared)
+ << WeakIDs.first;
}
if (LangOpts.CPlusPlus11 &&
@@ -1400,19 +1416,18 @@ void Sema::ActOnEndOfTranslationUnit() {
// Helper functions.
//===----------------------------------------------------------------------===//
-DeclContext *Sema::getFunctionLevelDeclContext() {
+DeclContext *Sema::getFunctionLevelDeclContext(bool AllowLambda) {
DeclContext *DC = CurContext;
while (true) {
if (isa<BlockDecl>(DC) || isa<EnumDecl>(DC) || isa<CapturedDecl>(DC) ||
isa<RequiresExprBodyDecl>(DC)) {
DC = DC->getParent();
- } else if (isa<CXXMethodDecl>(DC) &&
+ } else if (!AllowLambda && isa<CXXMethodDecl>(DC) &&
cast<CXXMethodDecl>(DC)->getOverloadedOperator() == OO_Call &&
cast<CXXRecordDecl>(DC->getParent())->isLambda()) {
DC = DC->getParent()->getParent();
- }
- else break;
+ } else break;
}
return DC;
@@ -1421,8 +1436,8 @@ DeclContext *Sema::getFunctionLevelDeclContext() {
/// getCurFunctionDecl - If inside of a function body, this returns a pointer
/// to the function decl for the function being parsed. If we're currently
/// in a 'block', this returns the containing context.
-FunctionDecl *Sema::getCurFunctionDecl() {
- DeclContext *DC = getFunctionLevelDeclContext();
+FunctionDecl *Sema::getCurFunctionDecl(bool AllowLambda) {
+ DeclContext *DC = getFunctionLevelDeclContext(AllowLambda);
return dyn_cast<FunctionDecl>(DC);
}
@@ -2204,7 +2219,8 @@ operator()(sema::FunctionScopeInfo *Scope) const {
}
void Sema::PushCompoundScope(bool IsStmtExpr) {
- getCurFunction()->CompoundScopes.push_back(CompoundScopeInfo(IsStmtExpr));
+ getCurFunction()->CompoundScopes.push_back(
+ CompoundScopeInfo(IsStmtExpr, getCurFPFeatures()));
}
void Sema::PopCompoundScope() {
@@ -2630,3 +2646,15 @@ const llvm::MapVector<FieldDecl *, Sema::DeleteLocs> &
Sema::getMismatchingDeleteExpressions() const {
return DeleteExprs;
}
+
+Sema::FPFeaturesStateRAII::FPFeaturesStateRAII(Sema &S)
+ : S(S), OldFPFeaturesState(S.CurFPFeatures),
+ OldOverrides(S.FpPragmaStack.CurrentValue),
+ OldEvalMethod(S.PP.getCurrentFPEvalMethod()),
+ OldFPPragmaLocation(S.PP.getLastFPEvalPragmaLocation()) {}
+
+Sema::FPFeaturesStateRAII::~FPFeaturesStateRAII() {
+ S.CurFPFeatures = OldFPFeaturesState;
+ S.FpPragmaStack.CurrentValue = OldOverrides;
+ S.PP.setCurrentFPEvalMethod(OldFPPragmaLocation, OldEvalMethod);
+}
diff --git a/clang/lib/Sema/SemaAccess.cpp b/clang/lib/Sema/SemaAccess.cpp
index 3f7b387ec925..00d3efd19d7a 100644
--- a/clang/lib/Sema/SemaAccess.cpp
+++ b/clang/lib/Sema/SemaAccess.cpp
@@ -1761,14 +1761,11 @@ Sema::CheckStructuredBindingMemberAccess(SourceLocation UseLoc,
return CheckAccess(*this, UseLoc, Entity);
}
-/// Checks access to an overloaded member operator, including
-/// conversion operators.
Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
Expr *ObjectExpr,
- Expr *ArgExpr,
+ const SourceRange &Range,
DeclAccessPair Found) {
- if (!getLangOpts().AccessControl ||
- Found.getAccess() == AS_public)
+ if (!getLangOpts().AccessControl || Found.getAccess() == AS_public)
return AR_accessible;
const RecordType *RT = ObjectExpr->getType()->castAs<RecordType>();
@@ -1776,13 +1773,35 @@ Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found,
ObjectExpr->getType());
- Entity.setDiag(diag::err_access)
- << ObjectExpr->getSourceRange()
- << (ArgExpr ? ArgExpr->getSourceRange() : SourceRange());
+ Entity.setDiag(diag::err_access) << ObjectExpr->getSourceRange() << Range;
return CheckAccess(*this, OpLoc, Entity);
}
+/// Checks access to an overloaded member operator, including
+/// conversion operators.
+Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
+ Expr *ObjectExpr,
+ Expr *ArgExpr,
+ DeclAccessPair Found) {
+ return CheckMemberOperatorAccess(
+ OpLoc, ObjectExpr, ArgExpr ? ArgExpr->getSourceRange() : SourceRange(),
+ Found);
+}
+
+Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
+ Expr *ObjectExpr,
+ ArrayRef<Expr *> ArgExprs,
+ DeclAccessPair FoundDecl) {
+ SourceRange R;
+ if (!ArgExprs.empty()) {
+ R = SourceRange(ArgExprs.front()->getBeginLoc(),
+ ArgExprs.back()->getEndLoc());
+ }
+
+ return CheckMemberOperatorAccess(OpLoc, ObjectExpr, R, FoundDecl);
+}
+
/// Checks access to the target of a friend declaration.
Sema::AccessResult Sema::CheckFriendAccess(NamedDecl *target) {
assert(isa<CXXMethodDecl>(target->getAsFunction()));
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index b69492768848..c997d018a406 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -384,6 +384,54 @@ void Sema::ActOnPragmaPack(SourceLocation PragmaLoc, PragmaMsStackAction Action,
AlignPackStack.Act(PragmaLoc, Action, SlotLabel, Info);
}
+bool Sema::ConstantFoldAttrArgs(const AttributeCommonInfo &CI,
+ MutableArrayRef<Expr *> Args) {
+ llvm::SmallVector<PartialDiagnosticAt, 8> Notes;
+ for (unsigned Idx = 0; Idx < Args.size(); Idx++) {
+ Expr *&E = Args.begin()[Idx];
+ assert(E && "error are handled before");
+ if (E->isValueDependent() || E->isTypeDependent())
+ continue;
+
+ // FIXME: Use DefaultFunctionArrayLValueConversion() in place of the logic
+ // that adds implicit casts here.
+ if (E->getType()->isArrayType())
+ E = ImpCastExprToType(E, Context.getPointerType(E->getType()),
+ clang::CK_ArrayToPointerDecay)
+ .get();
+ if (E->getType()->isFunctionType())
+ E = ImplicitCastExpr::Create(Context,
+ Context.getPointerType(E->getType()),
+ clang::CK_FunctionToPointerDecay, E, nullptr,
+ VK_PRValue, FPOptionsOverride());
+ if (E->isLValue())
+ E = ImplicitCastExpr::Create(Context, E->getType().getNonReferenceType(),
+ clang::CK_LValueToRValue, E, nullptr,
+ VK_PRValue, FPOptionsOverride());
+
+ Expr::EvalResult Eval;
+ Notes.clear();
+ Eval.Diag = &Notes;
+
+ bool Result = E->EvaluateAsConstantExpr(Eval, Context);
+
+ /// Result means the expression can be folded to a constant.
+ /// Note.empty() means the expression is a valid constant expression in the
+ /// current language mode.
+ if (!Result || !Notes.empty()) {
+ Diag(E->getBeginLoc(), diag::err_attribute_argument_n_type)
+ << CI << (Idx + 1) << AANT_ArgumentConstantExpr;
+ for (auto &Note : Notes)
+ Diag(Note.first, Note.second);
+ return false;
+ }
+ assert(Eval.Val.hasValue());
+ E = ConstantExpr::Create(Context, E, Eval.Val);
+ }
+
+ return true;
+}
+
void Sema::DiagnoseNonDefaultPragmaAlignPack(PragmaAlignPackDiagnoseKind Kind,
SourceLocation IncludeLoc) {
if (Kind == PragmaAlignPackDiagnoseKind::NonDefaultStateAtInclude) {
@@ -470,6 +518,33 @@ void Sema::ActOnPragmaDetectMismatch(SourceLocation Loc, StringRef Name,
Consumer.HandleTopLevelDecl(DeclGroupRef(PDMD));
}
+void Sema::ActOnPragmaFPEvalMethod(SourceLocation Loc,
+ LangOptions::FPEvalMethodKind Value) {
+ FPOptionsOverride NewFPFeatures = CurFPFeatureOverrides();
+ switch (Value) {
+ default:
+ llvm_unreachable("invalid pragma eval_method kind");
+ case LangOptions::FEM_Source:
+ NewFPFeatures.setFPEvalMethodOverride(LangOptions::FEM_Source);
+ break;
+ case LangOptions::FEM_Double:
+ NewFPFeatures.setFPEvalMethodOverride(LangOptions::FEM_Double);
+ break;
+ case LangOptions::FEM_Extended:
+ NewFPFeatures.setFPEvalMethodOverride(LangOptions::FEM_Extended);
+ break;
+ }
+ if (getLangOpts().ApproxFunc)
+ Diag(Loc, diag::err_setting_eval_method_used_in_unsafe_context) << 0 << 0;
+ if (getLangOpts().AllowFPReassoc)
+ Diag(Loc, diag::err_setting_eval_method_used_in_unsafe_context) << 0 << 1;
+ if (getLangOpts().AllowRecip)
+ Diag(Loc, diag::err_setting_eval_method_used_in_unsafe_context) << 0 << 2;
+ FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewFPFeatures);
+ CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts());
+ PP.setCurrentFPEvalMethod(Loc, Value);
+}
+
void Sema::ActOnPragmaFloatControl(SourceLocation Loc,
PragmaMsStackAction Action,
PragmaFloatControlKind Value) {
@@ -487,25 +562,36 @@ void Sema::ActOnPragmaFloatControl(SourceLocation Loc,
case PFC_Precise:
NewFPFeatures.setFPPreciseEnabled(true);
FpPragmaStack.Act(Loc, Action, StringRef(), NewFPFeatures);
+ if (PP.getCurrentFPEvalMethod() ==
+ LangOptions::FPEvalMethodKind::FEM_Indeterminable &&
+ PP.getLastFPEvalPragmaLocation().isValid())
+ // A preceding `pragma float_control(precise,off)` has changed
+ // the value of the evaluation method.
+ // Set it back to its old value.
+ PP.setCurrentFPEvalMethod(SourceLocation(), PP.getLastFPEvalMethod());
break;
case PFC_NoPrecise:
- if (CurFPFeatures.getFPExceptionMode() == LangOptions::FPE_Strict)
+ if (CurFPFeatures.getExceptionMode() == LangOptions::FPE_Strict)
Diag(Loc, diag::err_pragma_fc_noprecise_requires_noexcept);
else if (CurFPFeatures.getAllowFEnvAccess())
Diag(Loc, diag::err_pragma_fc_noprecise_requires_nofenv);
else
NewFPFeatures.setFPPreciseEnabled(false);
FpPragmaStack.Act(Loc, Action, StringRef(), NewFPFeatures);
+ PP.setLastFPEvalMethod(PP.getCurrentFPEvalMethod());
+ // `AllowFPReassoc` or `AllowReciprocal` option is enabled.
+ PP.setCurrentFPEvalMethod(
+ Loc, LangOptions::FPEvalMethodKind::FEM_Indeterminable);
break;
case PFC_Except:
if (!isPreciseFPEnabled())
Diag(Loc, diag::err_pragma_fc_except_requires_precise);
else
- NewFPFeatures.setFPExceptionModeOverride(LangOptions::FPE_Strict);
+ NewFPFeatures.setSpecifiedExceptionModeOverride(LangOptions::FPE_Strict);
FpPragmaStack.Act(Loc, Action, StringRef(), NewFPFeatures);
break;
case PFC_NoExcept:
- NewFPFeatures.setFPExceptionModeOverride(LangOptions::FPE_Ignore);
+ NewFPFeatures.setSpecifiedExceptionModeOverride(LangOptions::FPE_Ignore);
FpPragmaStack.Act(Loc, Action, StringRef(), NewFPFeatures);
break;
case PFC_Push:
@@ -519,6 +605,12 @@ void Sema::ActOnPragmaFloatControl(SourceLocation Loc,
}
FpPragmaStack.Act(Loc, Action, StringRef(), NewFPFeatures);
NewFPFeatures = FpPragmaStack.CurrentValue;
+ if (CurFPFeatures.getAllowFPReassociate() ||
+ CurFPFeatures.getAllowReciprocal())
+ // Since we are popping the pragma, we don't want to be passing
+ // a location here.
+ PP.setCurrentFPEvalMethod(SourceLocation(),
+ CurFPFeatures.getFPEvalMethod());
break;
}
CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts());
@@ -697,6 +789,42 @@ void Sema::ActOnPragmaMSInitSeg(SourceLocation PragmaLocation,
CurInitSegLoc = PragmaLocation;
}
+void Sema::ActOnPragmaMSAllocText(
+ SourceLocation PragmaLocation, StringRef Section,
+ const SmallVector<std::tuple<IdentifierInfo *, SourceLocation>>
+ &Functions) {
+ if (!CurContext->getRedeclContext()->isFileContext()) {
+ Diag(PragmaLocation, diag::err_pragma_expected_file_scope) << "alloc_text";
+ return;
+ }
+
+ for (auto &Function : Functions) {
+ IdentifierInfo *II;
+ SourceLocation Loc;
+ std::tie(II, Loc) = Function;
+
+ DeclarationName DN(II);
+ NamedDecl *ND = LookupSingleName(TUScope, DN, Loc, LookupOrdinaryName);
+ if (!ND) {
+ Diag(Loc, diag::err_undeclared_use) << II->getName();
+ return;
+ }
+
+ auto *FD = dyn_cast<FunctionDecl>(ND->getCanonicalDecl());
+ if (!FD) {
+ Diag(Loc, diag::err_pragma_alloc_text_not_function);
+ return;
+ }
+
+ if (getLangOpts().CPlusPlus && !FD->isInExternCContext()) {
+ Diag(Loc, diag::err_pragma_alloc_text_c_linkage);
+ return;
+ }
+
+ FunctionToSectionMap[II->getName()] = std::make_tuple(Section, Loc);
+ }
+}
+
void Sema::ActOnPragmaUnused(const Token &IdTok, Scope *curScope,
SourceLocation PragmaLoc) {
@@ -1021,6 +1149,25 @@ void Sema::ActOnPragmaOptimize(bool On, SourceLocation PragmaLoc) {
OptimizeOffPragmaLocation = PragmaLoc;
}
+void Sema::ActOnPragmaMSOptimize(SourceLocation Loc, bool IsOn) {
+ if (!CurContext->getRedeclContext()->isFileContext()) {
+ Diag(Loc, diag::err_pragma_expected_file_scope) << "optimize";
+ return;
+ }
+
+ MSPragmaOptimizeIsOn = IsOn;
+}
+
+void Sema::ActOnPragmaMSFunction(
+ SourceLocation Loc, const llvm::SmallVectorImpl<StringRef> &NoBuiltins) {
+ if (!CurContext->getRedeclContext()->isFileContext()) {
+ Diag(Loc, diag::err_pragma_expected_file_scope) << "function";
+ return;
+ }
+
+ MSFunctionNoBuiltins.insert(NoBuiltins.begin(), NoBuiltins.end());
+}
+
void Sema::AddRangeBasedOptnone(FunctionDecl *FD) {
// In the future, check other pragmas if they're implemented (e.g. pragma
// optimize 0 will probably map to this functionality too).
@@ -1028,6 +1175,29 @@ void Sema::AddRangeBasedOptnone(FunctionDecl *FD) {
AddOptnoneAttributeIfNoConflicts(FD, OptimizeOffPragmaLocation);
}
+void Sema::AddSectionMSAllocText(FunctionDecl *FD) {
+ if (!FD->getIdentifier())
+ return;
+
+ StringRef Name = FD->getName();
+ auto It = FunctionToSectionMap.find(Name);
+ if (It != FunctionToSectionMap.end()) {
+ StringRef Section;
+ SourceLocation Loc;
+ std::tie(Section, Loc) = It->second;
+
+ if (!FD->hasAttr<SectionAttr>())
+ FD->addAttr(SectionAttr::CreateImplicit(Context, Section));
+ }
+}
+
+void Sema::ModifyFnAttributesMSPragmaOptimize(FunctionDecl *FD) {
+ // Don't modify the function attributes if it's "on". "on" resets the
+ // optimizations to the ones listed on the command line
+ if (!MSPragmaOptimizeIsOn)
+ AddOptnoneAttributeIfNoConflicts(FD, FD->getBeginLoc());
+}
+
void Sema::AddOptnoneAttributeIfNoConflicts(FunctionDecl *FD,
SourceLocation Loc) {
// Don't add a conflicting attribute. No diagnostic is needed.
@@ -1042,6 +1212,13 @@ void Sema::AddOptnoneAttributeIfNoConflicts(FunctionDecl *FD,
FD->addAttr(NoInlineAttr::CreateImplicit(Context, Loc));
}
+void Sema::AddImplicitMSFunctionNoBuiltinAttr(FunctionDecl *FD) {
+ SmallVector<StringRef> V(MSFunctionNoBuiltins.begin(),
+ MSFunctionNoBuiltins.end());
+ if (!MSFunctionNoBuiltins.empty())
+ FD->addAttr(NoBuiltinAttr::CreateImplicit(Context, V.data(), V.size()));
+}
+
typedef std::vector<std::pair<unsigned, SourceLocation> > VisStack;
enum : unsigned { NoVisibility = ~0U };
@@ -1115,22 +1292,32 @@ void Sema::ActOnPragmaFPContract(SourceLocation Loc,
}
void Sema::ActOnPragmaFPReassociate(SourceLocation Loc, bool IsEnabled) {
+ if (IsEnabled) {
+ // For value unsafe context, combining this pragma with eval method
+ // setting is not recommended. See comment in function FixupInvocation#506.
+ int Reason = -1;
+ if (getLangOpts().getFPEvalMethod() != LangOptions::FEM_UnsetOnCommandLine)
+ // Eval method set using the option 'ffp-eval-method'.
+ Reason = 1;
+ if (PP.getLastFPEvalPragmaLocation().isValid())
+ // Eval method set using the '#pragma clang fp eval_method'.
+ // We could have both an option and a pragma used to the set the eval
+ // method. The pragma overrides the option in the command line. The Reason
+ // of the diagnostic is overriden too.
+ Reason = 0;
+ if (Reason != -1)
+ Diag(Loc, diag::err_setting_eval_method_used_in_unsafe_context)
+ << Reason << 4;
+ }
FPOptionsOverride NewFPFeatures = CurFPFeatureOverrides();
NewFPFeatures.setAllowFPReassociateOverride(IsEnabled);
FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewFPFeatures);
CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts());
}
-void Sema::setRoundingMode(SourceLocation Loc, llvm::RoundingMode FPR) {
- // C2x: 7.6.2p3 If the FE_DYNAMIC mode is specified and FENV_ACCESS is "off",
- // the translator may assume that the default rounding mode is in effect.
- if (FPR == llvm::RoundingMode::Dynamic &&
- !CurFPFeatures.getAllowFEnvAccess() &&
- CurFPFeatures.getFPExceptionMode() == LangOptions::FPE_Ignore)
- FPR = llvm::RoundingMode::NearestTiesToEven;
-
+void Sema::ActOnPragmaFEnvRound(SourceLocation Loc, llvm::RoundingMode FPR) {
FPOptionsOverride NewFPFeatures = CurFPFeatureOverrides();
- NewFPFeatures.setRoundingModeOverride(FPR);
+ NewFPFeatures.setConstRoundingModeOverride(FPR);
FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewFPFeatures);
CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts());
}
@@ -1138,14 +1325,13 @@ void Sema::setRoundingMode(SourceLocation Loc, llvm::RoundingMode FPR) {
void Sema::setExceptionMode(SourceLocation Loc,
LangOptions::FPExceptionModeKind FPE) {
FPOptionsOverride NewFPFeatures = CurFPFeatureOverrides();
- NewFPFeatures.setFPExceptionModeOverride(FPE);
+ NewFPFeatures.setSpecifiedExceptionModeOverride(FPE);
FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewFPFeatures);
CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts());
}
void Sema::ActOnPragmaFEnvAccess(SourceLocation Loc, bool IsEnabled) {
FPOptionsOverride NewFPFeatures = CurFPFeatureOverrides();
- auto LO = getLangOpts();
if (IsEnabled) {
// Verify Microsoft restriction:
// You can't enable fenv_access unless precise semantics are enabled.
@@ -1153,16 +1339,10 @@ void Sema::ActOnPragmaFEnvAccess(SourceLocation Loc, bool IsEnabled) {
// pragma, or by using the /fp:precise or /fp:strict compiler options
if (!isPreciseFPEnabled())
Diag(Loc, diag::err_pragma_fenv_requires_precise);
- NewFPFeatures.setAllowFEnvAccessOverride(true);
- // Enabling FENV access sets the RoundingMode to Dynamic.
- // and ExceptionBehavior to Strict
- NewFPFeatures.setRoundingModeOverride(llvm::RoundingMode::Dynamic);
- NewFPFeatures.setFPExceptionModeOverride(LangOptions::FPE_Strict);
- } else {
- NewFPFeatures.setAllowFEnvAccessOverride(false);
}
+ NewFPFeatures.setAllowFEnvAccessOverride(IsEnabled);
FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewFPFeatures);
- CurFPFeatures = NewFPFeatures.applyOverrides(LO);
+ CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts());
}
void Sema::ActOnPragmaFPExceptions(SourceLocation Loc,
@@ -1213,8 +1393,9 @@ void Sema::PopPragmaVisibility(bool IsNamespaceEnd, SourceLocation EndLoc) {
}
template <typename Ty>
-static bool checkCommonAttributeFeatures(Sema& S, const Ty *Node,
- const ParsedAttr& A) {
+static bool checkCommonAttributeFeatures(Sema &S, const Ty *Node,
+ const ParsedAttr &A,
+ bool SkipArgCountCheck) {
// Several attributes carry different semantics than the parsing requires, so
// those are opted out of the common argument checks.
//
@@ -1240,26 +1421,30 @@ static bool checkCommonAttributeFeatures(Sema& S, const Ty *Node,
if (A.hasCustomParsing())
return false;
- if (A.getMinArgs() == A.getMaxArgs()) {
- // If there are no optional arguments, then checking for the argument count
- // is trivial.
- if (!A.checkExactlyNumArgs(S, A.getMinArgs()))
- return true;
- } else {
- // There are optional arguments, so checking is slightly more involved.
- if (A.getMinArgs() && !A.checkAtLeastNumArgs(S, A.getMinArgs()))
- return true;
- else if (!A.hasVariadicArg() && A.getMaxArgs() &&
- !A.checkAtMostNumArgs(S, A.getMaxArgs()))
- return true;
+ if (!SkipArgCountCheck) {
+ if (A.getMinArgs() == A.getMaxArgs()) {
+ // If there are no optional arguments, then checking for the argument
+ // count is trivial.
+ if (!A.checkExactlyNumArgs(S, A.getMinArgs()))
+ return true;
+ } else {
+ // There are optional arguments, so checking is slightly more involved.
+ if (A.getMinArgs() && !A.checkAtLeastNumArgs(S, A.getMinArgs()))
+ return true;
+ else if (!A.hasVariadicArg() && A.getMaxArgs() &&
+ !A.checkAtMostNumArgs(S, A.getMaxArgs()))
+ return true;
+ }
}
return false;
}
-bool Sema::checkCommonAttributeFeatures(const Decl *D, const ParsedAttr &A) {
- return ::checkCommonAttributeFeatures(*this, D, A);
+bool Sema::checkCommonAttributeFeatures(const Decl *D, const ParsedAttr &A,
+ bool SkipArgCountCheck) {
+ return ::checkCommonAttributeFeatures(*this, D, A, SkipArgCountCheck);
}
-bool Sema::checkCommonAttributeFeatures(const Stmt *S, const ParsedAttr &A) {
- return ::checkCommonAttributeFeatures(*this, S, A);
+bool Sema::checkCommonAttributeFeatures(const Stmt *S, const ParsedAttr &A,
+ bool SkipArgCountCheck) {
+ return ::checkCommonAttributeFeatures(*this, S, A, SkipArgCountCheck);
}
diff --git a/clang/lib/Sema/SemaAvailability.cpp b/clang/lib/Sema/SemaAvailability.cpp
index dc15c87cb717..bf4a226668f7 100644
--- a/clang/lib/Sema/SemaAvailability.cpp
+++ b/clang/lib/Sema/SemaAvailability.cpp
@@ -501,7 +501,7 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
SmallVector<StringRef, 12> SelectorSlotNames;
Optional<unsigned> NumParams = tryParseObjCMethodName(
Replacement, SelectorSlotNames, S.getLangOpts());
- if (NumParams && NumParams.getValue() == Sel.getNumArgs()) {
+ if (NumParams && *NumParams == Sel.getNumArgs()) {
assert(SelectorSlotNames.size() == Locs.size());
for (unsigned I = 0; I < Locs.size(); ++I) {
if (!Sel.getNameForSlot(I).empty()) {
diff --git a/clang/lib/Sema/SemaCUDA.cpp b/clang/lib/Sema/SemaCUDA.cpp
index efa38554bc83..8f8144d658d8 100644
--- a/clang/lib/Sema/SemaCUDA.cpp
+++ b/clang/lib/Sema/SemaCUDA.cpp
@@ -145,9 +145,11 @@ Sema::CUDAFunctionTarget Sema::IdentifyCUDATarget(const FunctionDecl *D,
Sema::CUDAVariableTarget Sema::IdentifyCUDATarget(const VarDecl *Var) {
if (Var->hasAttr<HIPManagedAttr>())
return CVT_Unified;
- if (Var->isConstexpr() && !hasExplicitAttr<CUDAConstantAttr>(Var))
- return CVT_Both;
- if (Var->getType().isConstQualified() && Var->hasAttr<CUDAConstantAttr>() &&
+ // Only constexpr and const variabless with implicit constant attribute
+ // are emitted on both sides. Such variables are promoted to device side
+ // only if they have static constant intializers on device side.
+ if ((Var->isConstexpr() || Var->getType().isConstQualified()) &&
+ Var->hasAttr<CUDAConstantAttr>() &&
!hasExplicitAttr<CUDAConstantAttr>(Var))
return CVT_Both;
if (Var->hasAttr<CUDADeviceAttr>() || Var->hasAttr<CUDAConstantAttr>() ||
@@ -353,9 +355,7 @@ bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl,
}
if (!ClassDecl->isAbstract()) {
- for (const auto &VB : ClassDecl->vbases()) {
- Bases.push_back(&VB);
- }
+ llvm::append_range(Bases, llvm::make_pointer_range(ClassDecl->vbases()));
}
for (const auto *B : Bases) {
@@ -377,7 +377,7 @@ bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl,
continue;
CUDAFunctionTarget BaseMethodTarget = IdentifyCUDATarget(SMOR.getMethod());
- if (!InferredTarget.hasValue()) {
+ if (!InferredTarget) {
InferredTarget = BaseMethodTarget;
} else {
bool ResolutionError = resolveCalleeCUDATargetConflict(
@@ -421,7 +421,7 @@ bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl,
CUDAFunctionTarget FieldMethodTarget =
IdentifyCUDATarget(SMOR.getMethod());
- if (!InferredTarget.hasValue()) {
+ if (!InferredTarget) {
InferredTarget = FieldMethodTarget;
} else {
bool ResolutionError = resolveCalleeCUDATargetConflict(
@@ -444,7 +444,7 @@ bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl,
// If no target was inferred, mark this member as __host__ __device__;
// it's the least restrictive option that can be invoked from any target.
bool NeedsH = true, NeedsD = true;
- if (InferredTarget.hasValue()) {
+ if (InferredTarget) {
if (InferredTarget.getValue() == CFT_Device)
NeedsH = false;
else if (InferredTarget.getValue() == CFT_Host)
@@ -718,9 +718,9 @@ void Sema::MaybeAddCUDAConstantAttr(VarDecl *VD) {
!VD->hasAttr<CUDAConstantAttr>() && !VD->hasAttr<CUDASharedAttr>() &&
(VD->isFileVarDecl() || VD->isStaticDataMember()) &&
!IsDependentVar(VD) &&
- (VD->isConstexpr() || (VD->getType().isConstQualified() &&
- HasAllowedCUDADeviceStaticInitializer(
- *this, VD, CICK_DeviceOrConstant)))) {
+ ((VD->isConstexpr() || VD->getType().isConstQualified()) &&
+ HasAllowedCUDADeviceStaticInitializer(*this, VD,
+ CICK_DeviceOrConstant))) {
VD->addAttr(CUDAConstantAttr::CreateImplicit(getASTContext()));
}
}
@@ -728,8 +728,9 @@ void Sema::MaybeAddCUDAConstantAttr(VarDecl *VD) {
Sema::SemaDiagnosticBuilder Sema::CUDADiagIfDeviceCode(SourceLocation Loc,
unsigned DiagID) {
assert(getLangOpts().CUDA && "Should only be called during CUDA compilation");
+ FunctionDecl *CurFunContext = getCurFunctionDecl(/*AllowLambda=*/true);
SemaDiagnosticBuilder::Kind DiagKind = [&] {
- if (!isa<FunctionDecl>(CurContext))
+ if (!CurFunContext)
return SemaDiagnosticBuilder::K_Nop;
switch (CurrentCUDATarget()) {
case CFT_Global:
@@ -743,7 +744,7 @@ Sema::SemaDiagnosticBuilder Sema::CUDADiagIfDeviceCode(SourceLocation Loc,
return SemaDiagnosticBuilder::K_Nop;
if (IsLastErrorImmediate && Diags.getDiagnosticIDs()->isBuiltinNote(DiagID))
return SemaDiagnosticBuilder::K_Immediate;
- return (getEmissionStatus(cast<FunctionDecl>(CurContext)) ==
+ return (getEmissionStatus(CurFunContext) ==
FunctionEmissionStatus::Emitted)
? SemaDiagnosticBuilder::K_ImmediateWithCallStack
: SemaDiagnosticBuilder::K_Deferred;
@@ -751,15 +752,15 @@ Sema::SemaDiagnosticBuilder Sema::CUDADiagIfDeviceCode(SourceLocation Loc,
return SemaDiagnosticBuilder::K_Nop;
}
}();
- return SemaDiagnosticBuilder(DiagKind, Loc, DiagID,
- dyn_cast<FunctionDecl>(CurContext), *this);
+ return SemaDiagnosticBuilder(DiagKind, Loc, DiagID, CurFunContext, *this);
}
Sema::SemaDiagnosticBuilder Sema::CUDADiagIfHostCode(SourceLocation Loc,
unsigned DiagID) {
assert(getLangOpts().CUDA && "Should only be called during CUDA compilation");
+ FunctionDecl *CurFunContext = getCurFunctionDecl(/*AllowLambda=*/true);
SemaDiagnosticBuilder::Kind DiagKind = [&] {
- if (!isa<FunctionDecl>(CurContext))
+ if (!CurFunContext)
return SemaDiagnosticBuilder::K_Nop;
switch (CurrentCUDATarget()) {
case CFT_Host:
@@ -772,7 +773,7 @@ Sema::SemaDiagnosticBuilder Sema::CUDADiagIfHostCode(SourceLocation Loc,
return SemaDiagnosticBuilder::K_Nop;
if (IsLastErrorImmediate && Diags.getDiagnosticIDs()->isBuiltinNote(DiagID))
return SemaDiagnosticBuilder::K_Immediate;
- return (getEmissionStatus(cast<FunctionDecl>(CurContext)) ==
+ return (getEmissionStatus(CurFunContext) ==
FunctionEmissionStatus::Emitted)
? SemaDiagnosticBuilder::K_ImmediateWithCallStack
: SemaDiagnosticBuilder::K_Deferred;
@@ -780,8 +781,7 @@ Sema::SemaDiagnosticBuilder Sema::CUDADiagIfHostCode(SourceLocation Loc,
return SemaDiagnosticBuilder::K_Nop;
}
}();
- return SemaDiagnosticBuilder(DiagKind, Loc, DiagID,
- dyn_cast<FunctionDecl>(CurContext), *this);
+ return SemaDiagnosticBuilder(DiagKind, Loc, DiagID, CurFunContext, *this);
}
bool Sema::CheckCUDACall(SourceLocation Loc, FunctionDecl *Callee) {
@@ -794,7 +794,7 @@ bool Sema::CheckCUDACall(SourceLocation Loc, FunctionDecl *Callee) {
// FIXME: Is bailing out early correct here? Should we instead assume that
// the caller is a global initializer?
- FunctionDecl *Caller = dyn_cast<FunctionDecl>(CurContext);
+ FunctionDecl *Caller = getCurFunctionDecl(/*AllowLambda=*/true);
if (!Caller)
return true;
@@ -819,8 +819,13 @@ bool Sema::CheckCUDACall(SourceLocation Loc, FunctionDecl *Callee) {
}
}();
- if (DiagKind == SemaDiagnosticBuilder::K_Nop)
+ if (DiagKind == SemaDiagnosticBuilder::K_Nop) {
+ // For -fgpu-rdc, keep track of external kernels used by host functions.
+ if (LangOpts.CUDAIsDevice && LangOpts.GPURelocatableDeviceCode &&
+ Callee->hasAttr<CUDAGlobalAttr>() && !Callee->isDefined())
+ getASTContext().CUDAExternalDeviceDeclODRUsedByHost.insert(Callee);
return true;
+ }
// Avoid emitting this error twice for the same location. Using a hashtable
// like this is unfortunate, but because we must continue parsing as normal
@@ -860,7 +865,7 @@ void Sema::CUDACheckLambdaCapture(CXXMethodDecl *Callee,
// File-scope lambda can only do init captures for global variables, which
// results in passing by value for these global variables.
- FunctionDecl *Caller = dyn_cast<FunctionDecl>(CurContext);
+ FunctionDecl *Caller = getCurFunctionDecl(/*AllowLambda=*/true);
if (!Caller)
return;
diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp
index 4781d71080c9..3f8fedda7174 100644
--- a/clang/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp
@@ -121,7 +121,7 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS,
// entering the context, and that can't happen in a SFINAE context.
assert(!isSFINAEContext() &&
"partial specialization scope specifier in SFINAE context?");
- if (!hasVisibleDeclaration(PartialSpec))
+ if (!hasReachableDefinition(PartialSpec))
diagnoseMissingImport(SS.getLastQualifierNameLoc(), PartialSpec,
MissingImportKind::PartialSpecialization,
/*Recover*/true);
@@ -243,8 +243,8 @@ bool Sema::RequireCompleteEnumDecl(EnumDecl *EnumD, SourceLocation L,
if (EnumD->isCompleteDefinition()) {
// If we know about the definition but it is not visible, complain.
NamedDecl *SuggestedDef = nullptr;
- if (!hasVisibleDefinition(EnumD, &SuggestedDef,
- /*OnlyNeedComplete*/false)) {
+ if (!hasReachableDefinition(EnumD, &SuggestedDef,
+ /*OnlyNeedComplete*/ false)) {
// If the user is going to see an error here, recover by making the
// definition visible.
bool TreatAsComplete = !isSFINAEContext();
@@ -828,10 +828,14 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo,
}
if (!Found.empty()) {
- if (TypeDecl *TD = Found.getAsSingle<TypeDecl>())
+ if (TypeDecl *TD = Found.getAsSingle<TypeDecl>()) {
Diag(IdInfo.IdentifierLoc, diag::err_expected_class_or_namespace)
<< Context.getTypeDeclType(TD) << getLangOpts().CPlusPlus;
- else {
+ } else if (Found.getAsSingle<TemplateDecl>()) {
+ ParsedType SuggestedType;
+ DiagnoseUnknownTypeName(IdInfo.Identifier, IdInfo.IdentifierLoc, S, &SS,
+ SuggestedType);
+ } else {
Diag(IdInfo.IdentifierLoc, diag::err_expected_class_or_namespace)
<< IdInfo.Identifier << getLangOpts().CPlusPlus;
if (NamedDecl *ND = Found.getAsSingle<NamedDecl>())
@@ -850,7 +854,6 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo,
bool Sema::ActOnCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo,
bool EnteringContext, CXXScopeSpec &SS,
- bool ErrorRecoveryLookup,
bool *IsCorrectedToColon,
bool OnlyNamespace) {
if (SS.isInvalid())
diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp
index 7ef1732496c2..7b5bc7ca80b1 100644
--- a/clang/lib/Sema/SemaCast.cpp
+++ b/clang/lib/Sema/SemaCast.cpp
@@ -1356,7 +1356,7 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
if (SrcType->isIntegralOrEnumerationType()) {
// [expr.static.cast]p10 If the enumeration type has a fixed underlying
// type, the value is first converted to that type by integral conversion
- const EnumType *Enum = DestType->getAs<EnumType>();
+ const EnumType *Enum = DestType->castAs<EnumType>();
Kind = Enum->getDecl()->isFixed() &&
Enum->getDecl()->getIntegerType()->isBooleanType()
? CK_IntegralToBoolean
@@ -2545,7 +2545,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
static TryCastResult TryAddressSpaceCast(Sema &Self, ExprResult &SrcExpr,
QualType DestType, bool CStyle,
unsigned &msg, CastKind &Kind) {
- if (!Self.getLangOpts().OpenCL)
+ if (!Self.getLangOpts().OpenCL && !Self.getLangOpts().SYCLIsDevice)
// FIXME: As compiler doesn't have any information about overlapping addr
// spaces at the moment we have to be permissive here.
return TC_NotApplicable;
@@ -3129,6 +3129,23 @@ void CastOperation::CheckCStyleCast() {
Self.Diag(OpRange.getBegin(), diag::warn_cast_function_type)
<< SrcType << DestType << OpRange;
+ if (isa<PointerType>(SrcType) && isa<PointerType>(DestType)) {
+ QualType SrcTy = cast<PointerType>(SrcType)->getPointeeType();
+ QualType DestTy = cast<PointerType>(DestType)->getPointeeType();
+
+ const RecordDecl *SrcRD = SrcTy->getAsRecordDecl();
+ const RecordDecl *DestRD = DestTy->getAsRecordDecl();
+
+ if (SrcRD && DestRD && SrcRD->hasAttr<RandomizeLayoutAttr>() &&
+ SrcRD != DestRD) {
+ // The struct we are casting the pointer from was randomized.
+ Self.Diag(OpRange.getBegin(), diag::err_cast_from_randomized_struct)
+ << SrcType << DestType;
+ SrcExpr = ExprError();
+ return;
+ }
+ }
+
DiagnoseCastOfObjCSEL(Self, SrcExpr, DestType);
DiagnoseCallingConvCast(Self, SrcExpr, DestType, OpRange);
DiagnoseBadFunctionCast(Self, SrcExpr, DestType);
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index dfbf4cdc89cb..79420cc27699 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -109,24 +109,38 @@ SourceLocation Sema::getLocationOfStringLiteralByte(const StringLiteral *SL,
Context.getTargetInfo());
}
+/// Checks that a call expression's argument count is at least the desired
+/// number. This is useful when doing custom type-checking on a variadic
+/// function. Returns true on error.
+static bool checkArgCountAtLeast(Sema &S, CallExpr *Call,
+ unsigned MinArgCount) {
+ unsigned ArgCount = Call->getNumArgs();
+ if (ArgCount >= MinArgCount)
+ return false;
+
+ return S.Diag(Call->getEndLoc(), diag::err_typecheck_call_too_few_args)
+ << 0 /*function call*/ << MinArgCount << ArgCount
+ << Call->getSourceRange();
+}
+
/// Checks that a call expression's argument count is the desired number.
/// This is useful when doing custom type-checking. Returns true on error.
-static bool checkArgCount(Sema &S, CallExpr *call, unsigned desiredArgCount) {
- unsigned argCount = call->getNumArgs();
- if (argCount == desiredArgCount) return false;
+static bool checkArgCount(Sema &S, CallExpr *Call, unsigned DesiredArgCount) {
+ unsigned ArgCount = Call->getNumArgs();
+ if (ArgCount == DesiredArgCount)
+ return false;
- if (argCount < desiredArgCount)
- return S.Diag(call->getEndLoc(), diag::err_typecheck_call_too_few_args)
- << 0 /*function call*/ << desiredArgCount << argCount
- << call->getSourceRange();
+ if (checkArgCountAtLeast(S, Call, DesiredArgCount))
+ return true;
+ assert(ArgCount > DesiredArgCount && "should have diagnosed this");
// Highlight all the excess arguments.
- SourceRange range(call->getArg(desiredArgCount)->getBeginLoc(),
- call->getArg(argCount - 1)->getEndLoc());
+ SourceRange Range(Call->getArg(DesiredArgCount)->getBeginLoc(),
+ Call->getArg(ArgCount - 1)->getEndLoc());
- return S.Diag(range.getBegin(), diag::err_typecheck_call_too_many_args)
- << 0 /*function call*/ << desiredArgCount << argCount
- << call->getArg(1)->getSourceRange();
+ return S.Diag(Range.getBegin(), diag::err_typecheck_call_too_many_args)
+ << 0 /*function call*/ << DesiredArgCount << ArgCount
+ << Call->getArg(1)->getSourceRange();
}
/// Check that the first argument to __builtin_annotation is an integer
@@ -147,7 +161,7 @@ static bool SemaBuiltinAnnotation(Sema &S, CallExpr *TheCall) {
// Second argument should be a constant string.
Expr *StrArg = TheCall->getArg(1)->IgnoreParenCasts();
StringLiteral *Literal = dyn_cast<StringLiteral>(StrArg);
- if (!Literal || !Literal->isAscii()) {
+ if (!Literal || !Literal->isOrdinary()) {
S.Diag(StrArg->getBeginLoc(), diag::err_builtin_annotation_second_arg)
<< StrArg->getSourceRange();
return true;
@@ -366,6 +380,311 @@ static bool SemaBuiltinOverflow(Sema &S, CallExpr *TheCall,
return false;
}
+namespace {
+struct BuiltinDumpStructGenerator {
+ Sema &S;
+ CallExpr *TheCall;
+ SourceLocation Loc = TheCall->getBeginLoc();
+ SmallVector<Expr *, 32> Actions;
+ DiagnosticErrorTrap ErrorTracker;
+ PrintingPolicy Policy;
+
+ BuiltinDumpStructGenerator(Sema &S, CallExpr *TheCall)
+ : S(S), TheCall(TheCall), ErrorTracker(S.getDiagnostics()),
+ Policy(S.Context.getPrintingPolicy()) {
+ Policy.AnonymousTagLocations = false;
+ }
+
+ Expr *makeOpaqueValueExpr(Expr *Inner) {
+ auto *OVE = new (S.Context)
+ OpaqueValueExpr(Loc, Inner->getType(), Inner->getValueKind(),
+ Inner->getObjectKind(), Inner);
+ Actions.push_back(OVE);
+ return OVE;
+ }
+
+ Expr *getStringLiteral(llvm::StringRef Str) {
+ Expr *Lit = S.Context.getPredefinedStringLiteralFromCache(Str);
+ // Wrap the literal in parentheses to attach a source location.
+ return new (S.Context) ParenExpr(Loc, Loc, Lit);
+ }
+
+ bool callPrintFunction(llvm::StringRef Format,
+ llvm::ArrayRef<Expr *> Exprs = {}) {
+ SmallVector<Expr *, 8> Args;
+ assert(TheCall->getNumArgs() >= 2);
+ Args.reserve((TheCall->getNumArgs() - 2) + /*Format*/ 1 + Exprs.size());
+ Args.assign(TheCall->arg_begin() + 2, TheCall->arg_end());
+ Args.push_back(getStringLiteral(Format));
+ Args.insert(Args.end(), Exprs.begin(), Exprs.end());
+
+ // Register a note to explain why we're performing the call.
+ Sema::CodeSynthesisContext Ctx;
+ Ctx.Kind = Sema::CodeSynthesisContext::BuildingBuiltinDumpStructCall;
+ Ctx.PointOfInstantiation = Loc;
+ Ctx.CallArgs = Args.data();
+ Ctx.NumCallArgs = Args.size();
+ S.pushCodeSynthesisContext(Ctx);
+
+ ExprResult RealCall =
+ S.BuildCallExpr(/*Scope=*/nullptr, TheCall->getArg(1),
+ TheCall->getBeginLoc(), Args, TheCall->getRParenLoc());
+
+ S.popCodeSynthesisContext();
+ if (!RealCall.isInvalid())
+ Actions.push_back(RealCall.get());
+ // Bail out if we've hit any errors, even if we managed to build the
+ // call. We don't want to produce more than one error.
+ return RealCall.isInvalid() || ErrorTracker.hasErrorOccurred();
+ }
+
+ Expr *getIndentString(unsigned Depth) {
+ if (!Depth)
+ return nullptr;
+
+ llvm::SmallString<32> Indent;
+ Indent.resize(Depth * Policy.Indentation, ' ');
+ return getStringLiteral(Indent);
+ }
+
+ Expr *getTypeString(QualType T) {
+ return getStringLiteral(T.getAsString(Policy));
+ }
+
+ bool appendFormatSpecifier(QualType T, llvm::SmallVectorImpl<char> &Str) {
+ llvm::raw_svector_ostream OS(Str);
+
+ // Format 'bool', 'char', 'signed char', 'unsigned char' as numbers, rather
+ // than trying to print a single character.
+ if (auto *BT = T->getAs<BuiltinType>()) {
+ switch (BT->getKind()) {
+ case BuiltinType::Bool:
+ OS << "%d";
+ return true;
+ case BuiltinType::Char_U:
+ case BuiltinType::UChar:
+ OS << "%hhu";
+ return true;
+ case BuiltinType::Char_S:
+ case BuiltinType::SChar:
+ OS << "%hhd";
+ return true;
+ default:
+ break;
+ }
+ }
+
+ analyze_printf::PrintfSpecifier Specifier;
+ if (Specifier.fixType(T, S.getLangOpts(), S.Context, /*IsObjCLiteral=*/false)) {
+ // We were able to guess how to format this.
+ if (Specifier.getConversionSpecifier().getKind() ==
+ analyze_printf::PrintfConversionSpecifier::sArg) {
+ // Wrap double-quotes around a '%s' specifier and limit its maximum
+ // length. Ideally we'd also somehow escape special characters in the
+ // contents but printf doesn't support that.
+ // FIXME: '%s' formatting is not safe in general.
+ OS << '"';
+ Specifier.setPrecision(analyze_printf::OptionalAmount(32u));
+ Specifier.toString(OS);
+ OS << '"';
+ // FIXME: It would be nice to include a '...' if the string doesn't fit
+ // in the length limit.
+ } else {
+ Specifier.toString(OS);
+ }
+ return true;
+ }
+
+ if (T->isPointerType()) {
+ // Format all pointers with '%p'.
+ OS << "%p";
+ return true;
+ }
+
+ return false;
+ }
+
+ bool dumpUnnamedRecord(const RecordDecl *RD, Expr *E, unsigned Depth) {
+ Expr *IndentLit = getIndentString(Depth);
+ Expr *TypeLit = getTypeString(S.Context.getRecordType(RD));
+ if (IndentLit ? callPrintFunction("%s%s", {IndentLit, TypeLit})
+ : callPrintFunction("%s", {TypeLit}))
+ return true;
+
+ return dumpRecordValue(RD, E, IndentLit, Depth);
+ }
+
+ // Dump a record value. E should be a pointer or lvalue referring to an RD.
+ bool dumpRecordValue(const RecordDecl *RD, Expr *E, Expr *RecordIndent,
+ unsigned Depth) {
+ // FIXME: Decide what to do if RD is a union. At least we should probably
+ // turn off printing `const char*` members with `%s`, because that is very
+ // likely to crash if that's not the active member. Whatever we decide, we
+ // should document it.
+
+ // Build an OpaqueValueExpr so we can refer to E more than once without
+ // triggering re-evaluation.
+ Expr *RecordArg = makeOpaqueValueExpr(E);
+ bool RecordArgIsPtr = RecordArg->getType()->isPointerType();
+
+ if (callPrintFunction(" {\n"))
+ return true;
+
+ // Dump each base class, regardless of whether they're aggregates.
+ if (const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
+ for (const auto &Base : CXXRD->bases()) {
+ QualType BaseType =
+ RecordArgIsPtr ? S.Context.getPointerType(Base.getType())
+ : S.Context.getLValueReferenceType(Base.getType());
+ ExprResult BasePtr = S.BuildCStyleCastExpr(
+ Loc, S.Context.getTrivialTypeSourceInfo(BaseType, Loc), Loc,
+ RecordArg);
+ if (BasePtr.isInvalid() ||
+ dumpUnnamedRecord(Base.getType()->getAsRecordDecl(), BasePtr.get(),
+ Depth + 1))
+ return true;
+ }
+ }
+
+ Expr *FieldIndentArg = getIndentString(Depth + 1);
+
+ // Dump each field.
+ for (auto *D : RD->decls()) {
+ auto *IFD = dyn_cast<IndirectFieldDecl>(D);
+ auto *FD = IFD ? IFD->getAnonField() : dyn_cast<FieldDecl>(D);
+ if (!FD || FD->isUnnamedBitfield() || FD->isAnonymousStructOrUnion())
+ continue;
+
+ llvm::SmallString<20> Format = llvm::StringRef("%s%s %s ");
+ llvm::SmallVector<Expr *, 5> Args = {FieldIndentArg,
+ getTypeString(FD->getType()),
+ getStringLiteral(FD->getName())};
+
+ if (FD->isBitField()) {
+ Format += ": %zu ";
+ QualType SizeT = S.Context.getSizeType();
+ llvm::APInt BitWidth(S.Context.getIntWidth(SizeT),
+ FD->getBitWidthValue(S.Context));
+ Args.push_back(IntegerLiteral::Create(S.Context, BitWidth, SizeT, Loc));
+ }
+
+ Format += "=";
+
+ ExprResult Field =
+ IFD ? S.BuildAnonymousStructUnionMemberReference(
+ CXXScopeSpec(), Loc, IFD,
+ DeclAccessPair::make(IFD, AS_public), RecordArg, Loc)
+ : S.BuildFieldReferenceExpr(
+ RecordArg, RecordArgIsPtr, Loc, CXXScopeSpec(), FD,
+ DeclAccessPair::make(FD, AS_public),
+ DeclarationNameInfo(FD->getDeclName(), Loc));
+ if (Field.isInvalid())
+ return true;
+
+ auto *InnerRD = FD->getType()->getAsRecordDecl();
+ auto *InnerCXXRD = dyn_cast_or_null<CXXRecordDecl>(InnerRD);
+ if (InnerRD && (!InnerCXXRD || InnerCXXRD->isAggregate())) {
+ // Recursively print the values of members of aggregate record type.
+ if (callPrintFunction(Format, Args) ||
+ dumpRecordValue(InnerRD, Field.get(), FieldIndentArg, Depth + 1))
+ return true;
+ } else {
+ Format += " ";
+ if (appendFormatSpecifier(FD->getType(), Format)) {
+ // We know how to print this field.
+ Args.push_back(Field.get());
+ } else {
+ // We don't know how to print this field. Print out its address
+ // with a format specifier that a smart tool will be able to
+ // recognize and treat specially.
+ Format += "*%p";
+ ExprResult FieldAddr =
+ S.BuildUnaryOp(nullptr, Loc, UO_AddrOf, Field.get());
+ if (FieldAddr.isInvalid())
+ return true;
+ Args.push_back(FieldAddr.get());
+ }
+ Format += "\n";
+ if (callPrintFunction(Format, Args))
+ return true;
+ }
+ }
+
+ return RecordIndent ? callPrintFunction("%s}\n", RecordIndent)
+ : callPrintFunction("}\n");
+ }
+
+ Expr *buildWrapper() {
+ auto *Wrapper = PseudoObjectExpr::Create(S.Context, TheCall, Actions,
+ PseudoObjectExpr::NoResult);
+ TheCall->setType(Wrapper->getType());
+ TheCall->setValueKind(Wrapper->getValueKind());
+ return Wrapper;
+ }
+};
+} // namespace
+
+static ExprResult SemaBuiltinDumpStruct(Sema &S, CallExpr *TheCall) {
+ if (checkArgCountAtLeast(S, TheCall, 2))
+ return ExprError();
+
+ ExprResult PtrArgResult = S.DefaultLvalueConversion(TheCall->getArg(0));
+ if (PtrArgResult.isInvalid())
+ return ExprError();
+ TheCall->setArg(0, PtrArgResult.get());
+
+ // First argument should be a pointer to a struct.
+ QualType PtrArgType = PtrArgResult.get()->getType();
+ if (!PtrArgType->isPointerType() ||
+ !PtrArgType->getPointeeType()->isRecordType()) {
+ S.Diag(PtrArgResult.get()->getBeginLoc(),
+ diag::err_expected_struct_pointer_argument)
+ << 1 << TheCall->getDirectCallee() << PtrArgType;
+ return ExprError();
+ }
+ const RecordDecl *RD = PtrArgType->getPointeeType()->getAsRecordDecl();
+
+ // Second argument is a callable, but we can't fully validate it until we try
+ // calling it.
+ QualType FnArgType = TheCall->getArg(1)->getType();
+ if (!FnArgType->isFunctionType() && !FnArgType->isFunctionPointerType() &&
+ !FnArgType->isBlockPointerType() &&
+ !(S.getLangOpts().CPlusPlus && FnArgType->isRecordType())) {
+ auto *BT = FnArgType->getAs<BuiltinType>();
+ switch (BT ? BT->getKind() : BuiltinType::Void) {
+ case BuiltinType::Dependent:
+ case BuiltinType::Overload:
+ case BuiltinType::BoundMember:
+ case BuiltinType::PseudoObject:
+ case BuiltinType::UnknownAny:
+ case BuiltinType::BuiltinFn:
+ // This might be a callable.
+ break;
+
+ default:
+ S.Diag(TheCall->getArg(1)->getBeginLoc(),
+ diag::err_expected_callable_argument)
+ << 2 << TheCall->getDirectCallee() << FnArgType;
+ return ExprError();
+ }
+ }
+
+ BuiltinDumpStructGenerator Generator(S, TheCall);
+
+ // Wrap parentheses around the given pointer. This is not necessary for
+ // correct code generation, but it means that when we pretty-print the call
+ // arguments in our diagnostics we will produce '(&s)->n' instead of the
+ // incorrect '&s->n'.
+ Expr *PtrArg = PtrArgResult.get();
+ PtrArg = new (S.Context)
+ ParenExpr(PtrArg->getBeginLoc(),
+ S.getLocForEndOfToken(PtrArg->getEndLoc()), PtrArg);
+ if (Generator.dumpUnnamedRecord(RD, PtrArg, 0))
+ return ExprError();
+
+ return Generator.buildWrapper();
+}
+
static bool SemaBuiltinCallWithStaticChain(Sema &S, CallExpr *BuiltinCall) {
if (checkArgCount(S, BuiltinCall, 2))
return true;
@@ -715,7 +1034,7 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD,
Optional<unsigned> IndexOptional = TranslateIndex(Index);
if (!IndexOptional)
return llvm::None;
- unsigned NewIndex = IndexOptional.getValue();
+ unsigned NewIndex = *IndexOptional;
Expr::EvalResult Result;
Expr *SizeArg = TheCall->getArg(NewIndex);
if (!SizeArg->EvaluateAsInt(Result, getASTContext()))
@@ -740,7 +1059,7 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD,
Optional<unsigned> IndexOptional = TranslateIndex(Index);
if (!IndexOptional)
return llvm::None;
- unsigned NewIndex = IndexOptional.getValue();
+ unsigned NewIndex = *IndexOptional;
const Expr *ObjArg = TheCall->getArg(NewIndex);
uint64_t Result;
@@ -755,7 +1074,7 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD,
Optional<unsigned> IndexOptional = TranslateIndex(Index);
if (!IndexOptional)
return llvm::None;
- unsigned NewIndex = IndexOptional.getValue();
+ unsigned NewIndex = *IndexOptional;
const Expr *ObjArg = TheCall->getArg(NewIndex);
uint64_t Result;
@@ -820,7 +1139,7 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD,
if (!Format)
return;
- if (!Format->isAscii() && !Format->isUTF8())
+ if (!Format->isOrdinary() && !Format->isUTF8())
return;
auto Diagnose = [&](unsigned ArgIndex, unsigned DestSize,
@@ -865,7 +1184,7 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD,
if (auto *Format = dyn_cast<StringLiteral>(FormatExpr)) {
- if (!Format->isAscii() && !Format->isUTF8())
+ if (!Format->isOrdinary() && !Format->isUTF8())
return;
StringRef FormatStrRef = Format->getString();
@@ -965,8 +1284,7 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD,
}
if (!SourceSize || !DestinationSize ||
- llvm::APSInt::compareValues(SourceSize.getValue(),
- DestinationSize.getValue()) <= 0)
+ llvm::APSInt::compareValues(*SourceSize, *DestinationSize) <= 0)
return;
StringRef FunctionName = GetFunctionName();
@@ -1042,9 +1360,15 @@ static bool checkOpenCLBlockArgs(Sema &S, Expr *BlockArg) {
}
static bool checkOpenCLSubgroupExt(Sema &S, CallExpr *Call) {
- if (!S.getOpenCLOptions().isSupported("cl_khr_subgroups", S.getLangOpts())) {
+ // OpenCL device can support extension but not the feature as extension
+ // requires subgroup independent forward progress, but subgroup independent
+ // forward progress is optional in OpenCL C 3.0 __opencl_c_subgroups feature.
+ if (!S.getOpenCLOptions().isSupported("cl_khr_subgroups", S.getLangOpts()) &&
+ !S.getOpenCLOptions().isSupported("__opencl_c_subgroups",
+ S.getLangOpts())) {
S.Diag(Call->getBeginLoc(), diag::err_opencl_requires_extension)
- << 1 << Call->getDirectCallee() << "cl_khr_subgroups";
+ << 1 << Call->getDirectCallee()
+ << "cl_khr_subgroups or __opencl_c_subgroups";
return true;
}
return false;
@@ -1549,7 +1873,7 @@ static ExprResult SemaBuiltinLaunder(Sema &S, CallExpr *TheCall) {
return 2;
return llvm::Optional<unsigned>{};
}();
- if (DiagSelect.hasValue()) {
+ if (DiagSelect) {
S.Diag(TheCall->getBeginLoc(), diag::err_builtin_launder_invalid_arg)
<< DiagSelect.getValue() << TheCall->getSourceRange();
return ExprError();
@@ -1673,7 +1997,10 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
if ((ICEArguments & (1 << ArgNo)) == 0) continue;
llvm::APSInt Result;
- if (SemaBuiltinConstantArg(TheCall, ArgNo, Result))
+ // If we don't have enough arguments, continue so we can issue better
+ // diagnostic in checkArgCount(...)
+ if (ArgNo < TheCall->getNumArgs() &&
+ SemaBuiltinConstantArg(TheCall, ArgNo, Result))
return true;
ICEArguments &= ~(1 << ArgNo);
}
@@ -1949,6 +2276,17 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
}
break;
}
+ case Builtin::BI__builtin_memset_inline: {
+ clang::Expr *SizeOp = TheCall->getArg(2);
+ // We warn about filling to `nullptr` pointers when `size` is greater than
+ // 0. When `size` is value dependent we cannot evaluate its value so we bail
+ // out.
+ if (SizeOp->isValueDependent())
+ break;
+ if (!SizeOp->EvaluateKnownConstInt(Context).isZero())
+ CheckNonNullArgument(*this, TheCall->getArg(0), TheCall->getExprLoc());
+ break;
+ }
#define BUILTIN(ID, TYPE, ATTRS)
#define ATOMIC_BUILTIN(ID, TYPE, ATTRS) \
case Builtin::BI##ID: \
@@ -1991,62 +2329,8 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
CorrectDelayedTyposInExpr(TheCallResult.get());
return Res;
}
- case Builtin::BI__builtin_dump_struct: {
- // We first want to ensure we are called with 2 arguments
- if (checkArgCount(*this, TheCall, 2))
- return ExprError();
- // Ensure that the first argument is of type 'struct XX *'
- const Expr *PtrArg = TheCall->getArg(0)->IgnoreParenImpCasts();
- const QualType PtrArgType = PtrArg->getType();
- if (!PtrArgType->isPointerType() ||
- !PtrArgType->getPointeeType()->isRecordType()) {
- Diag(PtrArg->getBeginLoc(), diag::err_typecheck_convert_incompatible)
- << PtrArgType << "structure pointer" << 1 << 0 << 3 << 1 << PtrArgType
- << "structure pointer";
- return ExprError();
- }
-
- // Ensure that the second argument is of type 'FunctionType'
- const Expr *FnPtrArg = TheCall->getArg(1)->IgnoreImpCasts();
- const QualType FnPtrArgType = FnPtrArg->getType();
- if (!FnPtrArgType->isPointerType()) {
- Diag(FnPtrArg->getBeginLoc(), diag::err_typecheck_convert_incompatible)
- << FnPtrArgType << "'int (*)(const char *, ...)'" << 1 << 0 << 3 << 2
- << FnPtrArgType << "'int (*)(const char *, ...)'";
- return ExprError();
- }
-
- const auto *FuncType =
- FnPtrArgType->getPointeeType()->getAs<FunctionType>();
-
- if (!FuncType) {
- Diag(FnPtrArg->getBeginLoc(), diag::err_typecheck_convert_incompatible)
- << FnPtrArgType << "'int (*)(const char *, ...)'" << 1 << 0 << 3 << 2
- << FnPtrArgType << "'int (*)(const char *, ...)'";
- return ExprError();
- }
-
- if (const auto *FT = dyn_cast<FunctionProtoType>(FuncType)) {
- if (!FT->getNumParams()) {
- Diag(FnPtrArg->getBeginLoc(), diag::err_typecheck_convert_incompatible)
- << FnPtrArgType << "'int (*)(const char *, ...)'" << 1 << 0 << 3
- << 2 << FnPtrArgType << "'int (*)(const char *, ...)'";
- return ExprError();
- }
- QualType PT = FT->getParamType(0);
- if (!FT->isVariadic() || FT->getReturnType() != Context.IntTy ||
- !PT->isPointerType() || !PT->getPointeeType()->isCharType() ||
- !PT->getPointeeType().isConstQualified()) {
- Diag(FnPtrArg->getBeginLoc(), diag::err_typecheck_convert_incompatible)
- << FnPtrArgType << "'int (*)(const char *, ...)'" << 1 << 0 << 3
- << 2 << FnPtrArgType << "'int (*)(const char *, ...)'";
- return ExprError();
- }
- }
-
- TheCall->setType(Context.IntTy);
- break;
- }
+ case Builtin::BI__builtin_dump_struct:
+ return SemaBuiltinDumpStruct(*this, TheCall);
case Builtin::BI__builtin_expect_with_probability: {
// We first want to ensure we are called with 3 arguments
if (checkArgCount(*this, TheCall, 3))
@@ -2108,6 +2392,32 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
TheCall->setType(Context.VoidPtrTy);
break;
+ case Builtin::BIaddressof:
+ case Builtin::BI__addressof:
+ case Builtin::BIforward:
+ case Builtin::BImove:
+ case Builtin::BImove_if_noexcept:
+ case Builtin::BIas_const: {
+ // These are all expected to be of the form
+ // T &/&&/* f(U &/&&)
+ // where T and U only differ in qualification.
+ if (checkArgCount(*this, TheCall, 1))
+ return ExprError();
+ QualType Param = FDecl->getParamDecl(0)->getType();
+ QualType Result = FDecl->getReturnType();
+ bool ReturnsPointer = BuiltinID == Builtin::BIaddressof ||
+ BuiltinID == Builtin::BI__addressof;
+ if (!(Param->isReferenceType() &&
+ (ReturnsPointer ? Result->isPointerType()
+ : Result->isReferenceType()) &&
+ Context.hasSameUnqualifiedType(Param->getPointeeType(),
+ Result->getPointeeType()))) {
+ Diag(TheCall->getBeginLoc(), diag::err_builtin_move_forward_unsupported)
+ << FDecl;
+ return ExprError();
+ }
+ break;
+ }
// OpenCL v2.0, s6.13.16 - Pipe functions
case Builtin::BIread_pipe:
case Builtin::BIwrite_pipe:
@@ -2238,6 +2548,28 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
break;
}
+ // These builtins restrict the element type to integer
+ // types only.
+ case Builtin::BI__builtin_elementwise_add_sat:
+ case Builtin::BI__builtin_elementwise_sub_sat: {
+ if (SemaBuiltinElementwiseMath(TheCall))
+ return ExprError();
+
+ const Expr *Arg = TheCall->getArg(0);
+ QualType ArgTy = Arg->getType();
+ QualType EltTy = ArgTy;
+
+ if (auto *VecTy = EltTy->getAs<VectorType>())
+ EltTy = VecTy->getElementType();
+
+ if (!EltTy->isIntegerType()) {
+ Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
+ << 1 << /* integer ty */ 6 << ArgTy;
+ return ExprError();
+ }
+ break;
+ }
+
case Builtin::BI__builtin_elementwise_min:
case Builtin::BI__builtin_elementwise_max:
if (SemaBuiltinElementwiseMath(TheCall))
@@ -2261,6 +2593,9 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
}
// These builtins support vectors of integers only.
+ // TODO: ADD/MUL should support floating-point types.
+ case Builtin::BI__builtin_reduce_add:
+ case Builtin::BI__builtin_reduce_mul:
case Builtin::BI__builtin_reduce_xor:
case Builtin::BI__builtin_reduce_or:
case Builtin::BI__builtin_reduce_and: {
@@ -2878,6 +3213,9 @@ bool Sema::CheckAArch64BuiltinFunctionCall(const TargetInfo &TI,
if (BuiltinID == AArch64::BI__getReg)
return SemaBuiltinConstantArgRange(TheCall, 0, 0, 31);
+ if (BuiltinID == AArch64::BI__break)
+ return SemaBuiltinConstantArgRange(TheCall, 0, 0, 0xffff);
+
if (CheckNeonBuiltinFunctionCall(TI, BuiltinID, TheCall))
return true;
@@ -2911,23 +3249,12 @@ static bool isValidBPFPreserveFieldInfoArg(Expr *Arg) {
isa<ArraySubscriptExpr>(Arg->IgnoreParens()));
}
-static bool isEltOfVectorTy(ASTContext &Context, CallExpr *Call, Sema &S,
- QualType VectorTy, QualType EltTy) {
- QualType VectorEltTy = VectorTy->castAs<VectorType>()->getElementType();
- if (!Context.hasSameType(VectorEltTy, EltTy)) {
- S.Diag(Call->getBeginLoc(), diag::err_typecheck_call_different_arg_types)
- << Call->getSourceRange() << VectorEltTy << EltTy;
- return false;
- }
- return true;
-}
-
static bool isValidBPFPreserveTypeInfoArg(Expr *Arg) {
QualType ArgType = Arg->getType();
if (ArgType->getAsPlaceholderType())
return false;
- // for TYPE_EXISTENCE/TYPE_SIZEOF reloc type
+ // for TYPE_EXISTENCE/TYPE_MATCH/TYPE_SIZEOF reloc type
// format:
// 1. __builtin_preserve_type_info(*(<type> *)0, flag);
// 2. <type> var;
@@ -3576,6 +3903,8 @@ static bool isPPC_64Builtin(unsigned BuiltinID) {
case PPC::BI__builtin_divde:
case PPC::BI__builtin_divdeu:
case PPC::BI__builtin_bpermd:
+ case PPC::BI__builtin_pdepd:
+ case PPC::BI__builtin_pextd:
case PPC::BI__builtin_ppc_ldarx:
case PPC::BI__builtin_ppc_stdcx:
case PPC::BI__builtin_ppc_tdw:
@@ -3735,16 +4064,12 @@ bool Sema::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
case PPC::BI__builtin_pack_vector_int128:
return SemaFeatureCheck(*this, TheCall, "vsx",
diag::err_ppc_builtin_only_on_arch, "7");
+ case PPC::BI__builtin_pdepd:
+ case PPC::BI__builtin_pextd:
+ return SemaFeatureCheck(*this, TheCall, "isa-v31-instructions",
+ diag::err_ppc_builtin_only_on_arch, "10");
case PPC::BI__builtin_altivec_vgnb:
return SemaBuiltinConstantArgRange(TheCall, 1, 2, 7);
- case PPC::BI__builtin_altivec_vec_replace_elt:
- case PPC::BI__builtin_altivec_vec_replace_unaligned: {
- QualType VecTy = TheCall->getArg(0)->getType();
- QualType EltTy = TheCall->getArg(1)->getType();
- unsigned Width = Context.getIntWidth(EltTy);
- return SemaBuiltinConstantArgRange(TheCall, 2, 0, Width == 32 ? 12 : 8) ||
- !isEltOfVectorTy(Context, TheCall, *this, VecTy, EltTy);
- }
case PPC::BI__builtin_vsx_xxeval:
return SemaBuiltinConstantArgRange(TheCall, 3, 0, 255);
case PPC::BI__builtin_altivec_vsldbi:
@@ -3854,6 +4179,33 @@ bool Sema::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
diag::err_ppc_builtin_requires_vsx) ||
SemaBuiltinConstantArgRange(TheCall, 1, 0, 127);
}
+ case PPC::BI__builtin_ppc_maxfe:
+ case PPC::BI__builtin_ppc_minfe:
+ case PPC::BI__builtin_ppc_maxfl:
+ case PPC::BI__builtin_ppc_minfl:
+ case PPC::BI__builtin_ppc_maxfs:
+ case PPC::BI__builtin_ppc_minfs: {
+ if (Context.getTargetInfo().getTriple().isOSAIX() &&
+ (BuiltinID == PPC::BI__builtin_ppc_maxfe ||
+ BuiltinID == PPC::BI__builtin_ppc_minfe))
+ return Diag(TheCall->getBeginLoc(), diag::err_target_unsupported_type)
+ << "builtin" << true << 128 << QualType(Context.LongDoubleTy)
+ << false << Context.getTargetInfo().getTriple().str();
+ // Argument type should be exact.
+ QualType ArgType = QualType(Context.LongDoubleTy);
+ if (BuiltinID == PPC::BI__builtin_ppc_maxfl ||
+ BuiltinID == PPC::BI__builtin_ppc_minfl)
+ ArgType = QualType(Context.DoubleTy);
+ else if (BuiltinID == PPC::BI__builtin_ppc_maxfs ||
+ BuiltinID == PPC::BI__builtin_ppc_minfs)
+ ArgType = QualType(Context.FloatTy);
+ for (unsigned I = 0, E = TheCall->getNumArgs(); I < E; ++I)
+ if (TheCall->getArg(I)->getType() != ArgType)
+ return Diag(TheCall->getBeginLoc(),
+ diag::err_typecheck_convert_incompatible)
+ << TheCall->getArg(I)->getType() << ArgType << 1 << 0 << 0;
+ return false;
+ }
case PPC::BI__builtin_ppc_load8r:
case PPC::BI__builtin_ppc_store8r:
return SemaFeatureCheck(*this, TheCall, "isa-v206-instructions",
@@ -3964,6 +4316,27 @@ bool Sema::CheckRISCVLMUL(CallExpr *TheCall, unsigned ArgNum) {
<< Arg->getSourceRange();
}
+static bool isRISCV32Builtin(unsigned BuiltinID) {
+ // These builtins only work on riscv32 targets.
+ switch (BuiltinID) {
+ case RISCV::BI__builtin_riscv_zip_32:
+ case RISCV::BI__builtin_riscv_unzip_32:
+ case RISCV::BI__builtin_riscv_aes32dsi_32:
+ case RISCV::BI__builtin_riscv_aes32dsmi_32:
+ case RISCV::BI__builtin_riscv_aes32esi_32:
+ case RISCV::BI__builtin_riscv_aes32esmi_32:
+ case RISCV::BI__builtin_riscv_sha512sig0h_32:
+ case RISCV::BI__builtin_riscv_sha512sig0l_32:
+ case RISCV::BI__builtin_riscv_sha512sig1h_32:
+ case RISCV::BI__builtin_riscv_sha512sig1l_32:
+ case RISCV::BI__builtin_riscv_sha512sum0r_32:
+ case RISCV::BI__builtin_riscv_sha512sum1r_32:
+ return true;
+ }
+
+ return false;
+}
+
bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI,
unsigned BuiltinID,
CallExpr *TheCall) {
@@ -3974,6 +4347,12 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI,
StringRef Features = Context.BuiltinInfo.getRequiredFeatures(BuiltinID);
Features.split(ReqFeatures, ',');
+ // Check for 32-bit only builtins on a 64-bit target.
+ const llvm::Triple &TT = TI.getTriple();
+ if (TT.getArch() != llvm::Triple::riscv32 && isRISCV32Builtin(BuiltinID))
+ return Diag(TheCall->getCallee()->getBeginLoc(),
+ diag::err_32_bit_builtin_64_bit_tgt);
+
// Check if each required feature is included
for (StringRef F : ReqFeatures) {
SmallVector<StringRef> ReqOpFeatures;
@@ -4021,6 +4400,41 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI,
case RISCVVector::BI__builtin_rvv_vsetvlimax:
return SemaBuiltinConstantArgRange(TheCall, 0, 0, 3) ||
CheckRISCVLMUL(TheCall, 1);
+ case RISCVVector::BI__builtin_rvv_vget_v: {
+ ASTContext::BuiltinVectorTypeInfo ResVecInfo =
+ Context.getBuiltinVectorTypeInfo(cast<BuiltinType>(
+ TheCall->getType().getCanonicalType().getTypePtr()));
+ ASTContext::BuiltinVectorTypeInfo VecInfo =
+ Context.getBuiltinVectorTypeInfo(cast<BuiltinType>(
+ TheCall->getArg(0)->getType().getCanonicalType().getTypePtr()));
+ unsigned MaxIndex =
+ (VecInfo.EC.getKnownMinValue() * VecInfo.NumVectors) /
+ (ResVecInfo.EC.getKnownMinValue() * ResVecInfo.NumVectors);
+ return SemaBuiltinConstantArgRange(TheCall, 1, 0, MaxIndex - 1);
+ }
+ case RISCVVector::BI__builtin_rvv_vset_v: {
+ ASTContext::BuiltinVectorTypeInfo ResVecInfo =
+ Context.getBuiltinVectorTypeInfo(cast<BuiltinType>(
+ TheCall->getType().getCanonicalType().getTypePtr()));
+ ASTContext::BuiltinVectorTypeInfo VecInfo =
+ Context.getBuiltinVectorTypeInfo(cast<BuiltinType>(
+ TheCall->getArg(2)->getType().getCanonicalType().getTypePtr()));
+ unsigned MaxIndex =
+ (ResVecInfo.EC.getKnownMinValue() * ResVecInfo.NumVectors) /
+ (VecInfo.EC.getKnownMinValue() * VecInfo.NumVectors);
+ return SemaBuiltinConstantArgRange(TheCall, 1, 0, MaxIndex - 1);
+ }
+ // Check if byteselect is in [0, 3]
+ case RISCV::BI__builtin_riscv_aes32dsi_32:
+ case RISCV::BI__builtin_riscv_aes32dsmi_32:
+ case RISCV::BI__builtin_riscv_aes32esi_32:
+ case RISCV::BI__builtin_riscv_aes32esmi_32:
+ case RISCV::BI__builtin_riscv_sm4ks:
+ case RISCV::BI__builtin_riscv_sm4ed:
+ return SemaBuiltinConstantArgRange(TheCall, 2, 0, 3);
+ // Check if rnum is in [0, 10]
+ case RISCV::BI__builtin_riscv_aes64ks1i_64:
+ return SemaBuiltinConstantArgRange(TheCall, 1, 0, 10);
}
return false;
@@ -5409,7 +5823,9 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
if (!FnInfo)
return false;
- CheckTCBEnforcement(TheCall, FDecl);
+ // Enforce TCB except for builtin calls, which are always allowed.
+ if (FDecl->getBuiltinID() == 0)
+ CheckTCBEnforcement(TheCall->getExprLoc(), FDecl);
CheckAbsoluteValueFunction(TheCall, FDecl);
CheckMaxUnsignedZero(TheCall, FDecl);
@@ -5449,6 +5865,8 @@ bool Sema::CheckObjCMethodCall(ObjCMethodDecl *Method, SourceLocation lbrac,
/*IsMemberFunction=*/false, lbrac, Method->getSourceRange(),
CallType);
+ CheckTCBEnforcement(lbrac, Method);
+
return false;
}
@@ -6053,7 +6471,7 @@ static bool checkBuiltinArgument(Sema &S, CallExpr *E, unsigned ArgIndex) {
InitializedEntity Entity =
InitializedEntity::InitializeParameter(S.Context, Param);
- ExprResult Arg = E->getArg(0);
+ ExprResult Arg = E->getArg(ArgIndex);
Arg = S.PerformCopyInitialization(Entity, SourceLocation(), Arg);
if (Arg.isInvalid())
return true;
@@ -6520,7 +6938,7 @@ bool Sema::CheckObjCString(Expr *Arg) {
Arg = Arg->IgnoreParenCasts();
StringLiteral *Literal = dyn_cast<StringLiteral>(Arg);
- if (!Literal || !Literal->isAscii()) {
+ if (!Literal || !Literal->isOrdinary()) {
Diag(Arg->getBeginLoc(), diag::err_cfstring_literal_not_string_constant)
<< Arg->getSourceRange();
return true;
@@ -6555,7 +6973,7 @@ ExprResult Sema::CheckOSLogFormatStringArg(Expr *Arg) {
}
}
- if (!Literal || (!Literal->isAscii() && !Literal->isUTF8())) {
+ if (!Literal || (!Literal->isOrdinary() && !Literal->isUTF8())) {
return ExprError(
Diag(Arg->getBeginLoc(), diag::err_os_log_format_not_string_constant)
<< Arg->getSourceRange());
@@ -7972,7 +8390,7 @@ class FormatStringLiteral {
QualType getType() const { return FExpr->getType(); }
- bool isAscii() const { return FExpr->isAscii(); }
+ bool isAscii() const { return FExpr->isOrdinary(); }
bool isWide() const { return FExpr->isWide(); }
bool isUTF8() const { return FExpr->isUTF8(); }
bool isUTF16() const { return FExpr->isUTF16(); }
@@ -10760,7 +11178,10 @@ static void CheckMemaccessSize(Sema &S, unsigned BId, const CallExpr *Call) {
Call->getArg(BId == Builtin::BImemset ? 2 : 1)->IgnoreImpCasts();
auto isLiteralZero = [](const Expr *E) {
- return isa<IntegerLiteral>(E) && cast<IntegerLiteral>(E)->getValue() == 0;
+ return (isa<IntegerLiteral>(E) &&
+ cast<IntegerLiteral>(E)->getValue() == 0) ||
+ (isa<CharacterLiteral>(E) &&
+ cast<CharacterLiteral>(E)->getValue() == 0);
};
// If we're memsetting or bzeroing 0 bytes, then this is likely an error.
@@ -11282,7 +11703,7 @@ void CheckFreeArgumentsCast(Sema &S, const std::string &CalleeName,
/// Alerts the user that they are attempting to free a non-malloc'd object.
void Sema::CheckFreeArguments(const CallExpr *E) {
const std::string CalleeName =
- dyn_cast<FunctionDecl>(E->getCalleeDecl())->getQualifiedNameAsString();
+ cast<FunctionDecl>(E->getCalleeDecl())->getQualifiedNameAsString();
{ // Prefer something that doesn't involve a cast to make things simpler.
const Expr *Arg = E->getArg(0)->IgnoreParenCasts();
@@ -11353,12 +11774,40 @@ Sema::CheckReturnValExpr(Expr *RetValExp, QualType lhsType,
CheckPPCMMAType(RetValExp->getType(), ReturnLoc);
}
-//===--- CHECK: Floating-Point comparisons (-Wfloat-equal) ---------------===//
+/// Check for comparisons of floating-point values using == and !=. Issue a
+/// warning if the comparison is not likely to do what the programmer intended.
+void Sema::CheckFloatComparison(SourceLocation Loc, Expr *LHS, Expr *RHS,
+ BinaryOperatorKind Opcode) {
+ // Match and capture subexpressions such as "(float) X == 0.1".
+ FloatingLiteral *FPLiteral;
+ CastExpr *FPCast;
+ auto getCastAndLiteral = [&FPLiteral, &FPCast](Expr *L, Expr *R) {
+ FPLiteral = dyn_cast<FloatingLiteral>(L->IgnoreParens());
+ FPCast = dyn_cast<CastExpr>(R->IgnoreParens());
+ return FPLiteral && FPCast;
+ };
+
+ if (getCastAndLiteral(LHS, RHS) || getCastAndLiteral(RHS, LHS)) {
+ auto *SourceTy = FPCast->getSubExpr()->getType()->getAs<BuiltinType>();
+ auto *TargetTy = FPLiteral->getType()->getAs<BuiltinType>();
+ if (SourceTy && TargetTy && SourceTy->isFloatingPoint() &&
+ TargetTy->isFloatingPoint()) {
+ bool Lossy;
+ llvm::APFloat TargetC = FPLiteral->getValue();
+ TargetC.convert(Context.getFloatTypeSemantics(QualType(SourceTy, 0)),
+ llvm::APFloat::rmNearestTiesToEven, &Lossy);
+ if (Lossy) {
+ // If the literal cannot be represented in the source type, then a
+ // check for == is always false and check for != is always true.
+ Diag(Loc, diag::warn_float_compare_literal)
+ << (Opcode == BO_EQ) << QualType(SourceTy, 0)
+ << LHS->getSourceRange() << RHS->getSourceRange();
+ return;
+ }
+ }
+ }
-/// Check for comparisons of floating point operands using != and ==.
-/// Issue a warning if these are no self-comparisons, as they are not likely
-/// to do what the programmer intended.
-void Sema::CheckFloatComparison(SourceLocation Loc, Expr* LHS, Expr *RHS) {
+ // Match a more general floating-point equality comparison (-Wfloat-equal).
Expr* LeftExprSansParen = LHS->IgnoreParenImpCasts();
Expr* RightExprSansParen = RHS->IgnoreParenImpCasts();
@@ -13105,6 +13554,29 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
const BuiltinType *SourceBT = dyn_cast<BuiltinType>(Source);
const BuiltinType *TargetBT = dyn_cast<BuiltinType>(Target);
+ // Strip SVE vector types
+ if (SourceBT && SourceBT->isVLSTBuiltinType()) {
+ // Need the original target type for vector type checks
+ const Type *OriginalTarget = S.Context.getCanonicalType(T).getTypePtr();
+ // Handle conversion from scalable to fixed when msve-vector-bits is
+ // specified
+ if (S.Context.areCompatibleSveTypes(QualType(OriginalTarget, 0),
+ QualType(Source, 0)) ||
+ S.Context.areLaxCompatibleSveTypes(QualType(OriginalTarget, 0),
+ QualType(Source, 0)))
+ return;
+
+ // If the vector cast is cast between two vectors of the same size, it is
+ // a bitcast, not a conversion.
+ if (S.Context.getTypeSize(Source) == S.Context.getTypeSize(Target))
+ return;
+
+ Source = SourceBT->getSveEltType(S.Context).getTypePtr();
+ }
+
+ if (TargetBT && TargetBT->isVLSTBuiltinType())
+ Target = TargetBT->getSveEltType(S.Context).getTypePtr();
+
// If the source is floating point...
if (SourceBT && SourceBT->isFloatingPoint()) {
// ...and the target is floating point...
@@ -13390,9 +13862,10 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
// Fall through for non-constants to give a sign conversion warning.
}
- if ((TargetRange.NonNegative && !LikelySourceRange.NonNegative) ||
- (!TargetRange.NonNegative && LikelySourceRange.NonNegative &&
- LikelySourceRange.Width == TargetRange.Width)) {
+ if ((!isa<EnumType>(Target) || !isa<EnumType>(Source)) &&
+ ((TargetRange.NonNegative && !LikelySourceRange.NonNegative) ||
+ (!TargetRange.NonNegative && LikelySourceRange.NonNegative &&
+ LikelySourceRange.Width == TargetRange.Width))) {
if (S.SourceMgr.isInSystemMacro(CC))
return;
@@ -13623,6 +14096,13 @@ static void AnalyzeImplicitConversions(
if (!ChildExpr)
continue;
+ if (auto *CSE = dyn_cast<CoroutineSuspendExpr>(E))
+ if (ChildExpr == CSE->getOperand())
+ // Do not recurse over a CoroutineSuspendExpr's operand.
+ // The operand is also a subexpression of getCommonExpr(), and
+ // recursing into it directly would produce duplicate diagnostics.
+ continue;
+
if (IsLogicalAndOperator &&
isa<StringLiteral>(ChildExpr->IgnoreParenImpCasts()))
// Ignore checking string literals that are in logical and operators.
@@ -15324,6 +15804,8 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
ND = ME->getMemberDecl();
if (IsUnboundedArray) {
+ if (EffectiveType->isFunctionType())
+ return;
if (index.isUnsigned() || !index.isNegative()) {
const auto &ASTC = getASTContext();
unsigned AddrBits =
@@ -16191,7 +16673,7 @@ void Sema::DiagnoseEmptyLoopBody(const Stmt *S,
Body = FS->getBody();
DiagID = diag::warn_empty_for_body;
} else if (const WhileStmt *WS = dyn_cast<WhileStmt>(S)) {
- StmtLoc = WS->getCond()->getSourceRange().getEnd();
+ StmtLoc = WS->getRParenLoc();
Body = WS->getBody();
DiagID = diag::warn_empty_while_body;
} else
@@ -17243,33 +17725,28 @@ ExprResult Sema::SemaBuiltinMatrixColumnMajorStore(CallExpr *TheCall,
/// CheckTCBEnforcement - Enforces that every function in a named TCB only
/// directly calls other functions in the same TCB as marked by the enforce_tcb
/// and enforce_tcb_leaf attributes.
-void Sema::CheckTCBEnforcement(const CallExpr *TheCall,
- const FunctionDecl *Callee) {
- const FunctionDecl *Caller = getCurFunctionDecl();
+void Sema::CheckTCBEnforcement(const SourceLocation CallExprLoc,
+ const NamedDecl *Callee) {
+ const NamedDecl *Caller = getCurFunctionOrMethodDecl();
- // Calls to builtins are not enforced.
- if (!Caller || !Caller->hasAttr<EnforceTCBAttr>() ||
- Callee->getBuiltinID() != 0)
+ if (!Caller || !Caller->hasAttr<EnforceTCBAttr>())
return;
// Search through the enforce_tcb and enforce_tcb_leaf attributes to find
// all TCBs the callee is a part of.
llvm::StringSet<> CalleeTCBs;
- for_each(Callee->specific_attrs<EnforceTCBAttr>(),
- [&](const auto *A) { CalleeTCBs.insert(A->getTCBName()); });
- for_each(Callee->specific_attrs<EnforceTCBLeafAttr>(),
- [&](const auto *A) { CalleeTCBs.insert(A->getTCBName()); });
+ for (const auto *A : Callee->specific_attrs<EnforceTCBAttr>())
+ CalleeTCBs.insert(A->getTCBName());
+ for (const auto *A : Callee->specific_attrs<EnforceTCBLeafAttr>())
+ CalleeTCBs.insert(A->getTCBName());
// Go through the TCBs the caller is a part of and emit warnings if Caller
// is in a TCB that the Callee is not.
- for_each(
- Caller->specific_attrs<EnforceTCBAttr>(),
- [&](const auto *A) {
- StringRef CallerTCB = A->getTCBName();
- if (CalleeTCBs.count(CallerTCB) == 0) {
- this->Diag(TheCall->getExprLoc(),
- diag::warn_tcb_enforcement_violation) << Callee
- << CallerTCB;
- }
- });
+ for (const auto *A : Caller->specific_attrs<EnforceTCBAttr>()) {
+ StringRef CallerTCB = A->getTCBName();
+ if (CalleeTCBs.count(CallerTCB) == 0) {
+ this->Diag(CallExprLoc, diag::warn_tcb_enforcement_violation)
+ << Callee << CallerTCB;
+ }
+ }
}
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index 01fdf51c60c3..8c9ed5389488 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -1095,7 +1095,9 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
if (const UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(R.Declaration)) {
CodeCompletionResult Result(Using->getTargetDecl(),
getBasePriority(Using->getTargetDecl()),
- R.Qualifier);
+ R.Qualifier, false,
+ (R.Availability == CXAvailability_Available ||
+ R.Availability == CXAvailability_Deprecated));
Result.ShadowDecl = Using;
MaybeAddResult(Result, CurContext);
return;
@@ -1268,7 +1270,9 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext,
if (const auto *Using = dyn_cast<UsingShadowDecl>(R.Declaration)) {
CodeCompletionResult Result(Using->getTargetDecl(),
getBasePriority(Using->getTargetDecl()),
- R.Qualifier);
+ R.Qualifier, false,
+ (R.Availability == CXAvailability_Available ||
+ R.Availability == CXAvailability_Deprecated));
Result.ShadowDecl = Using;
AddResult(Result, CurContext, Hiding);
return;
@@ -2122,8 +2126,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S,
if (CCC == Sema::PCC_Class) {
AddTypedefResult(Results);
- bool IsNotInheritanceScope =
- !(S->getFlags() & Scope::ClassInheritanceScope);
+ bool IsNotInheritanceScope = !S->isClassInheritanceScope();
// public:
Builder.AddTypedTextChunk("public");
if (IsNotInheritanceScope && Results.includeCodePatterns())
@@ -4045,6 +4048,9 @@ CXCursorKind clang::getCursorKindForDecl(const Decl *D) {
case Decl::ObjCTypeParam:
return CXCursor_TemplateTypeParameter;
+ case Decl::Concept:
+ return CXCursor_ConceptDecl;
+
default:
if (const auto *TD = dyn_cast<TagDecl>(D)) {
switch (TD->getTagKind()) {
@@ -5048,7 +5054,7 @@ static void AddRecordMembersCompletionResults(
Results.allowNestedNameSpecifiers();
std::vector<FixItHint> FixIts;
if (AccessOpFixIt)
- FixIts.emplace_back(AccessOpFixIt.getValue());
+ FixIts.emplace_back(*AccessOpFixIt);
CodeCompletionDeclConsumer Consumer(Results, RD, BaseType, std::move(FixIts));
SemaRef.LookupVisibleDecls(RD, Sema::LookupMemberName, Consumer,
SemaRef.CodeCompleter->includeGlobals(),
@@ -5639,7 +5645,7 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base,
// Objective-C property reference. Bail if we're performing fix-it code
// completion since Objective-C properties are normally backed by ivars,
// most Objective-C fix-its here would have little value.
- if (AccessOpFixIt.hasValue()) {
+ if (AccessOpFixIt) {
return false;
}
AddedPropertiesSet AddedProperties;
@@ -5664,7 +5670,7 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base,
// Objective-C instance variable access. Bail if we're performing fix-it
// code completion since Objective-C properties are normally backed by
// ivars, most Objective-C fix-its here would have little value.
- if (AccessOpFixIt.hasValue()) {
+ if (AccessOpFixIt) {
return false;
}
ObjCInterfaceDecl *Class = nullptr;
@@ -9138,8 +9144,8 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
if (IsInstanceMethod &&
(ReturnType.isNull() ||
(ReturnType->isObjCObjectPointerType() &&
- ReturnType->getAs<ObjCObjectPointerType>()->getInterfaceDecl() &&
- ReturnType->getAs<ObjCObjectPointerType>()
+ ReturnType->castAs<ObjCObjectPointerType>()->getInterfaceDecl() &&
+ ReturnType->castAs<ObjCObjectPointerType>()
->getInterfaceDecl()
->getName() == "NSEnumerator"))) {
std::string SelectorName = (Twine("enumeratorOf") + UpperKey).str();
@@ -9505,8 +9511,7 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, Optional<bool> IsInstanceMethod,
IFace = Category->getClassInterface();
if (IFace)
- for (auto *Cat : IFace->visible_categories())
- Containers.push_back(Cat);
+ llvm::append_range(Containers, IFace->visible_categories());
if (IsInstanceMethod) {
for (unsigned I = 0, N = Containers.size(); I != N; ++I)
@@ -9787,7 +9792,7 @@ void Sema::CodeCompletePreprocessorMacroName(bool IsDefinition) {
CodeCompleter->getCodeCompletionTUInfo(),
IsDefinition ? CodeCompletionContext::CCC_MacroName
: CodeCompletionContext::CCC_MacroNameUse);
- if (!IsDefinition && (!CodeCompleter || CodeCompleter->includeMacros())) {
+ if (!IsDefinition && CodeCompleter->includeMacros()) {
// Add just the names of macros, not their arguments.
CodeCompletionBuilder Builder(Results.getAllocator(),
Results.getCodeCompletionTUInfo());
@@ -9814,9 +9819,8 @@ void Sema::CodeCompletePreprocessorExpression() {
CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_PreprocessorExpression);
- if (!CodeCompleter || CodeCompleter->includeMacros())
- AddMacroResults(PP, Results,
- !CodeCompleter || CodeCompleter->loadExternal(), true);
+ if (CodeCompleter->includeMacros())
+ AddMacroResults(PP, Results, CodeCompleter->loadExternal(), true);
// defined (<macro>)
Results.EnterNewScope();
@@ -9974,7 +9978,7 @@ void Sema::CodeCompleteIncludedFile(llvm::StringRef Dir, bool Angled) {
using llvm::make_range;
if (!Angled) {
// The current directory is on the include path for "quoted" includes.
- auto *CurFile = PP.getCurrentFileLexer()->getFileEntry();
+ const FileEntry *CurFile = PP.getCurrentFileLexer()->getFileEntry();
if (CurFile && CurFile->getDir())
AddFilesFromIncludeDir(CurFile->getDir()->getName(), false,
DirectoryLookup::LT_NormalDir);
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index ce99d4848cca..239e5dc4394c 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -317,36 +317,30 @@ bool Sema::CheckConstraintSatisfaction(
OutSatisfaction.IsSatisfied = true;
return false;
}
-
+ if (!Template) {
+ return ::CheckConstraintSatisfaction(*this, nullptr, ConstraintExprs,
+ TemplateArgs, TemplateIDRange,
+ OutSatisfaction);
+ }
llvm::FoldingSetNodeID ID;
+ ConstraintSatisfaction::Profile(ID, Context, Template, TemplateArgs);
void *InsertPos;
- ConstraintSatisfaction *Satisfaction = nullptr;
- bool ShouldCache = LangOpts.ConceptSatisfactionCaching && Template;
- if (ShouldCache) {
- ConstraintSatisfaction::Profile(ID, Context, Template, TemplateArgs);
- Satisfaction = SatisfactionCache.FindNodeOrInsertPos(ID, InsertPos);
- if (Satisfaction) {
- OutSatisfaction = *Satisfaction;
- return false;
- }
- Satisfaction = new ConstraintSatisfaction(Template, TemplateArgs);
- } else {
- Satisfaction = &OutSatisfaction;
+ if (auto *Cached = SatisfactionCache.FindNodeOrInsertPos(ID, InsertPos)) {
+ OutSatisfaction = *Cached;
+ return false;
}
+ auto Satisfaction =
+ std::make_unique<ConstraintSatisfaction>(Template, TemplateArgs);
if (::CheckConstraintSatisfaction(*this, Template, ConstraintExprs,
TemplateArgs, TemplateIDRange,
*Satisfaction)) {
- if (ShouldCache)
- delete Satisfaction;
return true;
}
-
- if (ShouldCache) {
- // We cannot use InsertNode here because CheckConstraintSatisfaction might
- // have invalidated it.
- SatisfactionCache.InsertNode(Satisfaction);
- OutSatisfaction = *Satisfaction;
- }
+ OutSatisfaction = *Satisfaction;
+ // We cannot use InsertPos here because CheckConstraintSatisfaction might have
+ // invalidated it.
+ // Note that entries of SatisfactionCache are deleted in Sema's destructor.
+ SatisfactionCache.InsertNode(Satisfaction.release());
return false;
}
@@ -354,8 +348,9 @@ bool Sema::CheckConstraintSatisfaction(const Expr *ConstraintExpr,
ConstraintSatisfaction &Satisfaction) {
return calculateConstraintSatisfaction(
*this, ConstraintExpr, Satisfaction,
- [](const Expr *AtomicExpr) -> ExprResult {
- return ExprResult(const_cast<Expr *>(AtomicExpr));
+ [this](const Expr *AtomicExpr) -> ExprResult {
+ // We only do this to immitate lvalue-to-rvalue conversion.
+ return PerformContextuallyConvertToBool(const_cast<Expr *>(AtomicExpr));
});
}
@@ -409,6 +404,52 @@ bool Sema::EnsureTemplateArgumentListConstraints(
return false;
}
+bool Sema::CheckInstantiatedFunctionTemplateConstraints(
+ SourceLocation PointOfInstantiation, FunctionDecl *Decl,
+ ArrayRef<TemplateArgument> TemplateArgs,
+ ConstraintSatisfaction &Satisfaction) {
+ // In most cases we're not going to have constraints, so check for that first.
+ FunctionTemplateDecl *Template = Decl->getPrimaryTemplate();
+ // Note - code synthesis context for the constraints check is created
+ // inside CheckConstraintsSatisfaction.
+ SmallVector<const Expr *, 3> TemplateAC;
+ Template->getAssociatedConstraints(TemplateAC);
+ if (TemplateAC.empty()) {
+ Satisfaction.IsSatisfied = true;
+ return false;
+ }
+
+ // Enter the scope of this instantiation. We don't use
+ // PushDeclContext because we don't have a scope.
+ Sema::ContextRAII savedContext(*this, Decl);
+ LocalInstantiationScope Scope(*this);
+
+ // If this is not an explicit specialization - we need to get the instantiated
+ // version of the template arguments and add them to scope for the
+ // substitution.
+ if (Decl->isTemplateInstantiation()) {
+ InstantiatingTemplate Inst(*this, Decl->getPointOfInstantiation(),
+ InstantiatingTemplate::ConstraintsCheck{}, Decl->getPrimaryTemplate(),
+ TemplateArgs, SourceRange());
+ if (Inst.isInvalid())
+ return true;
+ MultiLevelTemplateArgumentList MLTAL(
+ *Decl->getTemplateSpecializationArgs());
+ if (addInstantiatedParametersToScope(
+ Decl, Decl->getPrimaryTemplate()->getTemplatedDecl(), Scope, MLTAL))
+ return true;
+ }
+ Qualifiers ThisQuals;
+ CXXRecordDecl *Record = nullptr;
+ if (auto *Method = dyn_cast<CXXMethodDecl>(Decl)) {
+ ThisQuals = Method->getMethodQualifiers();
+ Record = Method->getParent();
+ }
+ CXXThisScopeRAII ThisScope(*this, Record, ThisQuals, Record != nullptr);
+ return CheckConstraintSatisfaction(Template, TemplateAC, TemplateArgs,
+ PointOfInstantiation, Satisfaction);
+}
+
static void diagnoseUnsatisfiedRequirement(Sema &S,
concepts::ExprRequirement *Req,
bool First) {
diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp
index cd3ae62ebbe2..a738befdd6ce 100644
--- a/clang/lib/Sema/SemaCoroutine.cpp
+++ b/clang/lib/Sema/SemaCoroutine.cpp
@@ -246,44 +246,22 @@ static bool isValidCoroutineContext(Sema &S, SourceLocation Loc,
return !Diagnosed;
}
-static ExprResult buildOperatorCoawaitLookupExpr(Sema &SemaRef, Scope *S,
- SourceLocation Loc) {
- DeclarationName OpName =
- SemaRef.Context.DeclarationNames.getCXXOperatorName(OO_Coawait);
- LookupResult Operators(SemaRef, OpName, SourceLocation(),
- Sema::LookupOperatorName);
- SemaRef.LookupName(Operators, S);
-
- assert(!Operators.isAmbiguous() && "Operator lookup cannot be ambiguous");
- const auto &Functions = Operators.asUnresolvedSet();
- bool IsOverloaded =
- Functions.size() > 1 ||
- (Functions.size() == 1 && isa<FunctionTemplateDecl>(*Functions.begin()));
- Expr *CoawaitOp = UnresolvedLookupExpr::Create(
- SemaRef.Context, /*NamingClass*/ nullptr, NestedNameSpecifierLoc(),
- DeclarationNameInfo(OpName, Loc), /*RequiresADL*/ true, IsOverloaded,
- Functions.begin(), Functions.end());
- assert(CoawaitOp);
- return CoawaitOp;
-}
-
/// Build a call to 'operator co_await' if there is a suitable operator for
/// the given expression.
-static ExprResult buildOperatorCoawaitCall(Sema &SemaRef, SourceLocation Loc,
- Expr *E,
- UnresolvedLookupExpr *Lookup) {
+ExprResult Sema::BuildOperatorCoawaitCall(SourceLocation Loc, Expr *E,
+ UnresolvedLookupExpr *Lookup) {
UnresolvedSet<16> Functions;
Functions.append(Lookup->decls_begin(), Lookup->decls_end());
- return SemaRef.CreateOverloadedUnaryOp(Loc, UO_Coawait, Functions, E);
+ return CreateOverloadedUnaryOp(Loc, UO_Coawait, Functions, E);
}
static ExprResult buildOperatorCoawaitCall(Sema &SemaRef, Scope *S,
SourceLocation Loc, Expr *E) {
- ExprResult R = buildOperatorCoawaitLookupExpr(SemaRef, S, Loc);
+ ExprResult R = SemaRef.BuildOperatorCoawaitLookupExpr(S, Loc);
if (R.isInvalid())
return ExprError();
- return buildOperatorCoawaitCall(SemaRef, Loc, E,
- cast<UnresolvedLookupExpr>(R.get()));
+ return SemaRef.BuildOperatorCoawaitCall(Loc, E,
+ cast<UnresolvedLookupExpr>(R.get()));
}
static ExprResult buildCoroutineHandle(Sema &S, QualType PromiseType,
@@ -680,7 +658,7 @@ static void checkNoThrow(Sema &S, const Stmt *E,
QualType::DestructionKind::DK_cxx_destructor) {
const auto *T =
cast<RecordType>(ReturnType.getCanonicalType().getTypePtr());
- checkDeclNoexcept(dyn_cast<CXXRecordDecl>(T->getDecl())->getDestructor(),
+ checkDeclNoexcept(cast<CXXRecordDecl>(T->getDecl())->getDestructor(),
/*IsDtor=*/true);
}
} else
@@ -727,14 +705,15 @@ bool Sema::ActOnCoroutineBodyStart(Scope *SC, SourceLocation KWLoc,
SourceLocation Loc = Fn->getLocation();
// Build the initial suspend point
auto buildSuspends = [&](StringRef Name) mutable -> StmtResult {
- ExprResult Suspend =
+ ExprResult Operand =
buildPromiseCall(*this, ScopeInfo->CoroutinePromise, Loc, Name, None);
- if (Suspend.isInvalid())
+ if (Operand.isInvalid())
return StmtError();
- Suspend = buildOperatorCoawaitCall(*this, SC, Loc, Suspend.get());
+ ExprResult Suspend =
+ buildOperatorCoawaitCall(*this, SC, Loc, Operand.get());
if (Suspend.isInvalid())
return StmtError();
- Suspend = BuildResolvedCoawaitExpr(Loc, Suspend.get(),
+ Suspend = BuildResolvedCoawaitExpr(Loc, Operand.get(), Suspend.get(),
/*IsImplicit*/ true);
Suspend = ActOnFinishFullExpr(Suspend.get(), /*DiscardedValue*/ false);
if (Suspend.isInvalid()) {
@@ -776,8 +755,8 @@ static bool isWithinCatchScope(Scope *S) {
// }();
// }
// }
- while (S && !(S->getFlags() & Scope::FnScope)) {
- if (S->getFlags() & Scope::CatchScope)
+ while (S && !S->isFunctionScope()) {
+ if (S->isCatchScope())
return true;
S = S->getParent();
}
@@ -815,88 +794,112 @@ ExprResult Sema::ActOnCoawaitExpr(Scope *S, SourceLocation Loc, Expr *E) {
if (R.isInvalid()) return ExprError();
E = R.get();
}
- ExprResult Lookup = buildOperatorCoawaitLookupExpr(*this, S, Loc);
+ ExprResult Lookup = BuildOperatorCoawaitLookupExpr(S, Loc);
if (Lookup.isInvalid())
return ExprError();
return BuildUnresolvedCoawaitExpr(Loc, E,
cast<UnresolvedLookupExpr>(Lookup.get()));
}
-ExprResult Sema::BuildUnresolvedCoawaitExpr(SourceLocation Loc, Expr *E,
+ExprResult Sema::BuildOperatorCoawaitLookupExpr(Scope *S, SourceLocation Loc) {
+ DeclarationName OpName =
+ Context.DeclarationNames.getCXXOperatorName(OO_Coawait);
+ LookupResult Operators(*this, OpName, SourceLocation(),
+ Sema::LookupOperatorName);
+ LookupName(Operators, S);
+
+ assert(!Operators.isAmbiguous() && "Operator lookup cannot be ambiguous");
+ const auto &Functions = Operators.asUnresolvedSet();
+ bool IsOverloaded =
+ Functions.size() > 1 ||
+ (Functions.size() == 1 && isa<FunctionTemplateDecl>(*Functions.begin()));
+ Expr *CoawaitOp = UnresolvedLookupExpr::Create(
+ Context, /*NamingClass*/ nullptr, NestedNameSpecifierLoc(),
+ DeclarationNameInfo(OpName, Loc), /*RequiresADL*/ true, IsOverloaded,
+ Functions.begin(), Functions.end());
+ assert(CoawaitOp);
+ return CoawaitOp;
+}
+
+// Attempts to resolve and build a CoawaitExpr from "raw" inputs, bailing out to
+// DependentCoawaitExpr if needed.
+ExprResult Sema::BuildUnresolvedCoawaitExpr(SourceLocation Loc, Expr *Operand,
UnresolvedLookupExpr *Lookup) {
auto *FSI = checkCoroutineContext(*this, Loc, "co_await");
if (!FSI)
return ExprError();
- if (E->hasPlaceholderType()) {
- ExprResult R = CheckPlaceholderExpr(E);
+ if (Operand->hasPlaceholderType()) {
+ ExprResult R = CheckPlaceholderExpr(Operand);
if (R.isInvalid())
return ExprError();
- E = R.get();
+ Operand = R.get();
}
auto *Promise = FSI->CoroutinePromise;
if (Promise->getType()->isDependentType()) {
- Expr *Res =
- new (Context) DependentCoawaitExpr(Loc, Context.DependentTy, E, Lookup);
+ Expr *Res = new (Context)
+ DependentCoawaitExpr(Loc, Context.DependentTy, Operand, Lookup);
return Res;
}
auto *RD = Promise->getType()->getAsCXXRecordDecl();
+ auto *Transformed = Operand;
if (lookupMember(*this, "await_transform", RD, Loc)) {
- ExprResult R = buildPromiseCall(*this, Promise, Loc, "await_transform", E);
+ ExprResult R =
+ buildPromiseCall(*this, Promise, Loc, "await_transform", Operand);
if (R.isInvalid()) {
Diag(Loc,
diag::note_coroutine_promise_implicit_await_transform_required_here)
- << E->getSourceRange();
+ << Operand->getSourceRange();
return ExprError();
}
- E = R.get();
+ Transformed = R.get();
}
- ExprResult Awaitable = buildOperatorCoawaitCall(*this, Loc, E, Lookup);
- if (Awaitable.isInvalid())
+ ExprResult Awaiter = BuildOperatorCoawaitCall(Loc, Transformed, Lookup);
+ if (Awaiter.isInvalid())
return ExprError();
- return BuildResolvedCoawaitExpr(Loc, Awaitable.get());
+ return BuildResolvedCoawaitExpr(Loc, Operand, Awaiter.get());
}
-ExprResult Sema::BuildResolvedCoawaitExpr(SourceLocation Loc, Expr *E,
- bool IsImplicit) {
+ExprResult Sema::BuildResolvedCoawaitExpr(SourceLocation Loc, Expr *Operand,
+ Expr *Awaiter, bool IsImplicit) {
auto *Coroutine = checkCoroutineContext(*this, Loc, "co_await", IsImplicit);
if (!Coroutine)
return ExprError();
- if (E->hasPlaceholderType()) {
- ExprResult R = CheckPlaceholderExpr(E);
+ if (Awaiter->hasPlaceholderType()) {
+ ExprResult R = CheckPlaceholderExpr(Awaiter);
if (R.isInvalid()) return ExprError();
- E = R.get();
+ Awaiter = R.get();
}
- if (E->getType()->isDependentType()) {
+ if (Awaiter->getType()->isDependentType()) {
Expr *Res = new (Context)
- CoawaitExpr(Loc, Context.DependentTy, E, IsImplicit);
+ CoawaitExpr(Loc, Context.DependentTy, Operand, Awaiter, IsImplicit);
return Res;
}
// If the expression is a temporary, materialize it as an lvalue so that we
// can use it multiple times.
- if (E->isPRValue())
- E = CreateMaterializeTemporaryExpr(E->getType(), E, true);
+ if (Awaiter->isPRValue())
+ Awaiter = CreateMaterializeTemporaryExpr(Awaiter->getType(), Awaiter, true);
// The location of the `co_await` token cannot be used when constructing
// the member call expressions since it's before the location of `Expr`, which
// is used as the start of the member call expression.
- SourceLocation CallLoc = E->getExprLoc();
+ SourceLocation CallLoc = Awaiter->getExprLoc();
// Build the await_ready, await_suspend, await_resume calls.
- ReadySuspendResumeResult RSS = buildCoawaitCalls(
- *this, Coroutine->CoroutinePromise, CallLoc, E);
+ ReadySuspendResumeResult RSS =
+ buildCoawaitCalls(*this, Coroutine->CoroutinePromise, CallLoc, Awaiter);
if (RSS.IsInvalid)
return ExprError();
- Expr *Res =
- new (Context) CoawaitExpr(Loc, E, RSS.Results[0], RSS.Results[1],
- RSS.Results[2], RSS.OpaqueValue, IsImplicit);
+ Expr *Res = new (Context)
+ CoawaitExpr(Loc, Operand, Awaiter, RSS.Results[0], RSS.Results[1],
+ RSS.Results[2], RSS.OpaqueValue, IsImplicit);
return Res;
}
@@ -933,8 +936,10 @@ ExprResult Sema::BuildCoyieldExpr(SourceLocation Loc, Expr *E) {
E = R.get();
}
+ Expr *Operand = E;
+
if (E->getType()->isDependentType()) {
- Expr *Res = new (Context) CoyieldExpr(Loc, Context.DependentTy, E);
+ Expr *Res = new (Context) CoyieldExpr(Loc, Context.DependentTy, Operand, E);
return Res;
}
@@ -950,7 +955,7 @@ ExprResult Sema::BuildCoyieldExpr(SourceLocation Loc, Expr *E) {
return ExprError();
Expr *Res =
- new (Context) CoyieldExpr(Loc, E, RSS.Results[0], RSS.Results[1],
+ new (Context) CoyieldExpr(Loc, Operand, E, RSS.Results[0], RSS.Results[1],
RSS.Results[2], RSS.OpaqueValue);
return Res;
@@ -1081,6 +1086,14 @@ void Sema::CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *&Body) {
return;
}
+ // The always_inline attribute doesn't reliably apply to a coroutine,
+ // because the coroutine will be split into pieces and some pieces
+ // might be called indirectly, as in a virtual call. Even the ramp
+ // function cannot be inlined at -O0, due to pipeline ordering
+ // problems (see https://llvm.org/PR53413). Tell the user about it.
+ if (FD->hasAttr<AlwaysInlineAttr>())
+ Diag(FD->getLocation(), diag::warn_always_inline_coroutine);
+
// [stmt.return.coroutine]p1:
// A coroutine shall not enclose a return statement ([stmt.return]).
if (Fn->FirstReturnLoc.isValid()) {
@@ -1226,6 +1239,41 @@ bool CoroutineStmtBuilder::makeReturnOnAllocFailure() {
return true;
}
+// Collect placement arguments for allocation function of coroutine FD.
+// Return true if we collect placement arguments succesfully. Return false,
+// otherwise.
+static bool collectPlacementArgs(Sema &S, FunctionDecl &FD, SourceLocation Loc,
+ SmallVectorImpl<Expr *> &PlacementArgs) {
+ if (auto *MD = dyn_cast<CXXMethodDecl>(&FD)) {
+ if (MD->isInstance() && !isLambdaCallOperator(MD)) {
+ ExprResult ThisExpr = S.ActOnCXXThis(Loc);
+ if (ThisExpr.isInvalid())
+ return false;
+ ThisExpr = S.CreateBuiltinUnaryOp(Loc, UO_Deref, ThisExpr.get());
+ if (ThisExpr.isInvalid())
+ return false;
+ PlacementArgs.push_back(ThisExpr.get());
+ }
+ }
+
+ for (auto *PD : FD.parameters()) {
+ if (PD->getType()->isDependentType())
+ continue;
+
+ // Build a reference to the parameter.
+ auto PDLoc = PD->getLocation();
+ ExprResult PDRefExpr =
+ S.BuildDeclRefExpr(PD, PD->getOriginalType().getNonReferenceType(),
+ ExprValueKind::VK_LValue, PDLoc);
+ if (PDRefExpr.isInvalid())
+ return false;
+
+ PlacementArgs.push_back(PDRefExpr.get());
+ }
+
+ return true;
+}
+
bool CoroutineStmtBuilder::makeNewAndDeleteExpr() {
// Form and check allocation and deallocation calls.
assert(!IsPromiseDependentType &&
@@ -1242,13 +1290,7 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() {
// allocated, followed by the coroutine function's arguments. If a matching
// allocation function exists, use it. Otherwise, use an allocation function
// that just takes the requested size.
-
- FunctionDecl *OperatorNew = nullptr;
- FunctionDecl *OperatorDelete = nullptr;
- FunctionDecl *UnusedResult = nullptr;
- bool PassAlignment = false;
- SmallVector<Expr *, 1> PlacementArgs;
-
+ //
// [dcl.fct.def.coroutine]p9
// An implementation may need to allocate additional storage for a
// coroutine.
@@ -1275,58 +1317,55 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() {
// and p_i denotes the i-th function parameter otherwise. For a non-static
// member function, q_1 is an lvalue that denotes *this; any other q_i is an
// lvalue that denotes the parameter copy corresponding to p_i.
- if (auto *MD = dyn_cast<CXXMethodDecl>(&FD)) {
- if (MD->isInstance() && !isLambdaCallOperator(MD)) {
- ExprResult ThisExpr = S.ActOnCXXThis(Loc);
- if (ThisExpr.isInvalid())
- return false;
- ThisExpr = S.CreateBuiltinUnaryOp(Loc, UO_Deref, ThisExpr.get());
- if (ThisExpr.isInvalid())
- return false;
- PlacementArgs.push_back(ThisExpr.get());
- }
- }
- for (auto *PD : FD.parameters()) {
- if (PD->getType()->isDependentType())
- continue;
- // Build a reference to the parameter.
- auto PDLoc = PD->getLocation();
- ExprResult PDRefExpr =
- S.BuildDeclRefExpr(PD, PD->getOriginalType().getNonReferenceType(),
- ExprValueKind::VK_LValue, PDLoc);
- if (PDRefExpr.isInvalid())
- return false;
+ FunctionDecl *OperatorNew = nullptr;
+ FunctionDecl *OperatorDelete = nullptr;
+ FunctionDecl *UnusedResult = nullptr;
+ bool PassAlignment = false;
+ SmallVector<Expr *, 1> PlacementArgs;
- PlacementArgs.push_back(PDRefExpr.get());
- }
- S.FindAllocationFunctions(Loc, SourceRange(), /*NewScope*/ Sema::AFS_Class,
- /*DeleteScope*/ Sema::AFS_Both, PromiseType,
- /*isArray*/ false, PassAlignment, PlacementArgs,
- OperatorNew, UnusedResult, /*Diagnose*/ false);
+ bool PromiseContainsNew = [this, &PromiseType]() -> bool {
+ DeclarationName NewName =
+ S.getASTContext().DeclarationNames.getCXXOperatorName(OO_New);
+ LookupResult R(S, NewName, Loc, Sema::LookupOrdinaryName);
- // [dcl.fct.def.coroutine]p9
- // If no viable function is found ([over.match.viable]), overload resolution
- // is performed again on a function call created by passing just the amount of
- // space required as an argument of type std::size_t.
- if (!OperatorNew && !PlacementArgs.empty()) {
- PlacementArgs.clear();
- S.FindAllocationFunctions(Loc, SourceRange(), /*NewScope*/ Sema::AFS_Class,
+ if (PromiseType->isRecordType())
+ S.LookupQualifiedName(R, PromiseType->getAsCXXRecordDecl());
+
+ return !R.empty() && !R.isAmbiguous();
+ }();
+
+ auto LookupAllocationFunction = [&]() {
+ // [dcl.fct.def.coroutine]p9
+ // The allocation function's name is looked up by searching for it in the
+ // scope of the promise type.
+ // - If any declarations are found, ...
+ // - If no declarations are found in the scope of the promise type, a search
+ // is performed in the global scope.
+ Sema::AllocationFunctionScope NewScope =
+ PromiseContainsNew ? Sema::AFS_Class : Sema::AFS_Global;
+ S.FindAllocationFunctions(Loc, SourceRange(),
+ NewScope,
/*DeleteScope*/ Sema::AFS_Both, PromiseType,
/*isArray*/ false, PassAlignment, PlacementArgs,
OperatorNew, UnusedResult, /*Diagnose*/ false);
- }
+ };
+
+ // We don't expect to call to global operator new with (size, p0, …, pn).
+ // So if we choose to lookup the allocation function in global scope, we
+ // shouldn't lookup placement arguments.
+ if (PromiseContainsNew && !collectPlacementArgs(S, FD, Loc, PlacementArgs))
+ return false;
+
+ LookupAllocationFunction();
// [dcl.fct.def.coroutine]p9
- // The allocation function's name is looked up by searching for it in the
- // scope of the promise type.
- // - If any declarations are found, ...
- // - Otherwise, a search is performed in the global scope.
- if (!OperatorNew) {
- S.FindAllocationFunctions(Loc, SourceRange(), /*NewScope*/ Sema::AFS_Global,
- /*DeleteScope*/ Sema::AFS_Both, PromiseType,
- /*isArray*/ false, PassAlignment, PlacementArgs,
- OperatorNew, UnusedResult);
+ // If no viable function is found ([over.match.viable]), overload resolution
+ // is performed again on a function call created by passing just the amount of
+ // space required as an argument of type std::size_t.
+ if (!OperatorNew && !PlacementArgs.empty() && PromiseContainsNew) {
+ PlacementArgs.clear();
+ LookupAllocationFunction();
}
bool IsGlobalOverload =
@@ -1346,8 +1385,12 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() {
OperatorNew, UnusedResult);
}
- if (!OperatorNew)
+ if (!OperatorNew) {
+ if (PromiseContainsNew)
+ S.Diag(Loc, diag::err_coroutine_unusable_new) << PromiseType << &FD;
+
return false;
+ }
if (RequiresNoThrowAlloc) {
const auto *FT = OperatorNew->getType()->castAs<FunctionProtoType>();
@@ -1382,8 +1425,7 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() {
return false;
SmallVector<Expr *, 2> NewArgs(1, FrameSize);
- for (auto Arg : PlacementArgs)
- NewArgs.push_back(Arg);
+ llvm::append_range(NewArgs, PlacementArgs);
ExprResult NewExpr =
S.BuildCallExpr(S.getCurScope(), NewRef.get(), Loc, NewArgs, Loc);
@@ -1569,7 +1611,6 @@ bool CoroutineStmtBuilder::makeGroDeclAndReturnStmt() {
if (Res.isInvalid())
return false;
- this->ResultDecl = Res.get();
return true;
}
@@ -1582,51 +1623,11 @@ bool CoroutineStmtBuilder::makeGroDeclAndReturnStmt() {
return false;
}
- auto *GroDecl = VarDecl::Create(
- S.Context, &FD, FD.getLocation(), FD.getLocation(),
- &S.PP.getIdentifierTable().get("__coro_gro"), GroType,
- S.Context.getTrivialTypeSourceInfo(GroType, Loc), SC_None);
- GroDecl->setImplicit();
-
- S.CheckVariableDeclarationType(GroDecl);
- if (GroDecl->isInvalidDecl())
- return false;
-
- InitializedEntity Entity = InitializedEntity::InitializeVariable(GroDecl);
- ExprResult Res =
- S.PerformCopyInitialization(Entity, SourceLocation(), ReturnValue);
- if (Res.isInvalid())
- return false;
-
- Res = S.ActOnFinishFullExpr(Res.get(), /*DiscardedValue*/ false);
- if (Res.isInvalid())
- return false;
-
- S.AddInitializerToDecl(GroDecl, Res.get(),
- /*DirectInit=*/false);
-
- S.FinalizeDeclaration(GroDecl);
-
- // Form a declaration statement for the return declaration, so that AST
- // visitors can more easily find it.
- StmtResult GroDeclStmt =
- S.ActOnDeclStmt(S.ConvertDeclToDeclGroup(GroDecl), Loc, Loc);
- if (GroDeclStmt.isInvalid())
- return false;
-
- this->ResultDecl = GroDeclStmt.get();
-
- ExprResult declRef = S.BuildDeclRefExpr(GroDecl, GroType, VK_LValue, Loc);
- if (declRef.isInvalid())
- return false;
-
- StmtResult ReturnStmt = S.BuildReturnStmt(Loc, declRef.get());
+ StmtResult ReturnStmt = S.BuildReturnStmt(Loc, ReturnValue);
if (ReturnStmt.isInvalid()) {
noteMemberDeclaredHere(S, ReturnValue, Fn);
return false;
}
- if (cast<clang::ReturnStmt>(ReturnStmt.get())->getNRVOCandidate() == GroDecl)
- GroDecl->setNRVOVariable(true);
this->ReturnStmt = ReturnStmt.get();
return true;
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index cbd9df4d6a7b..1139088ecde2 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -24,6 +24,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/NonTrivialTypeVisitor.h"
+#include "clang/AST/Randstruct.h"
#include "clang/AST/StmtCXX.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/PartialDiagnostic.h"
@@ -503,9 +504,11 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
FoundUsingShadow = nullptr;
} else if (AllowDeducedTemplate) {
if (auto *TD = getAsTypeTemplateDecl(IIDecl)) {
- // FIXME: TemplateName should include FoundUsingShadow sugar.
- T = Context.getDeducedTemplateSpecializationType(TemplateName(TD),
- QualType(), false);
+ assert(!FoundUsingShadow || FoundUsingShadow->getTargetDecl() == TD);
+ TemplateName Template =
+ FoundUsingShadow ? TemplateName(FoundUsingShadow) : TemplateName(TD);
+ T = Context.getDeducedTemplateSpecializationType(Template, QualType(),
+ false);
// Don't wrap in a further UsingType.
FoundUsingShadow = nullptr;
}
@@ -930,9 +933,13 @@ Corrected:
//
// appeared.
//
- // We also allow this in C99 as an extension.
- if (NamedDecl *D = ImplicitlyDefineFunction(NameLoc, *Name, S))
- return NameClassification::NonType(D);
+ // We also allow this in C99 as an extension. However, this is not
+ // allowed in all language modes as functions without prototypes may not
+ // be supported.
+ if (getLangOpts().implicitFunctionsAllowed()) {
+ if (NamedDecl *D = ImplicitlyDefineFunction(NameLoc, *Name, S))
+ return NameClassification::NonType(D);
+ }
}
if (getLangOpts().CPlusPlus20 && SS.isEmpty() && NextToken.is(tok::less)) {
@@ -1106,12 +1113,16 @@ Corrected:
IsFunctionTemplate = isa<FunctionTemplateDecl>(TD);
IsVarTemplate = isa<VarTemplateDecl>(TD);
+ UsingShadowDecl *FoundUsingShadow =
+ dyn_cast<UsingShadowDecl>(*Result.begin());
+ assert(!FoundUsingShadow ||
+ TD == cast<TemplateDecl>(FoundUsingShadow->getTargetDecl()));
+ Template =
+ FoundUsingShadow ? TemplateName(FoundUsingShadow) : TemplateName(TD);
if (SS.isNotEmpty())
- Template =
- Context.getQualifiedTemplateName(SS.getScopeRep(),
- /*TemplateKeyword=*/false, TD);
- else
- Template = TemplateName(TD);
+ Template = Context.getQualifiedTemplateName(SS.getScopeRep(),
+ /*TemplateKeyword=*/false,
+ Template);
} else {
// All results were non-template functions. This is a function template
// name.
@@ -1460,27 +1471,38 @@ void Sema::ActOnExitFunctionContext() {
assert(CurContext && "Popped translation unit!");
}
-/// Determine whether we allow overloading of the function
-/// PrevDecl with another declaration.
+/// Determine whether overloading is allowed for a new function
+/// declaration considering prior declarations of the same name.
///
/// This routine determines whether overloading is possible, not
-/// whether some new function is actually an overload. It will return
-/// true in C++ (where we can always provide overloads) or, as an
-/// extension, in C when the previous function is already an
-/// overloaded function declaration or has the "overloadable"
-/// attribute.
-static bool AllowOverloadingOfFunction(LookupResult &Previous,
+/// whether a new declaration actually overloads a previous one.
+/// It will return true in C++ (where overloads are alway permitted)
+/// or, as a C extension, when either the new declaration or a
+/// previous one is declared with the 'overloadable' attribute.
+static bool AllowOverloadingOfFunction(const LookupResult &Previous,
ASTContext &Context,
const FunctionDecl *New) {
- if (Context.getLangOpts().CPlusPlus)
+ if (Context.getLangOpts().CPlusPlus || New->hasAttr<OverloadableAttr>())
return true;
- if (Previous.getResultKind() == LookupResult::FoundOverloaded)
- return true;
+ // Multiversion function declarations are not overloads in the
+ // usual sense of that term, but lookup will report that an
+ // overload set was found if more than one multiversion function
+ // declaration is present for the same name. It is therefore
+ // inadequate to assume that some prior declaration(s) had
+ // the overloadable attribute; checking is required. Since one
+ // declaration is permitted to omit the attribute, it is necessary
+ // to check at least two; hence the 'any_of' check below. Note that
+ // the overloadable attribute is implicitly added to declarations
+ // that were required to have it but did not.
+ if (Previous.getResultKind() == LookupResult::FoundOverloaded) {
+ return llvm::any_of(Previous, [](const NamedDecl *ND) {
+ return ND->hasAttr<OverloadableAttr>();
+ });
+ } else if (Previous.getResultKind() == LookupResult::Found)
+ return Previous.getFoundDecl()->hasAttr<OverloadableAttr>();
- return Previous.getResultKind() == LookupResult::Found &&
- (Previous.getFoundDecl()->hasAttr<OverloadableAttr>() ||
- New->hasAttr<OverloadableAttr>());
+ return false;
}
/// Add this decl to the scope shadowed decl chains.
@@ -1608,6 +1630,14 @@ bool Sema::CheckRedeclarationModuleOwnership(NamedDecl *New, NamedDecl *Old) {
if (OldM && OldM->Kind == Module::PrivateModuleFragment)
OldM = OldM->Parent;
+ // If we have a decl in a module partition, it is part of the containing
+ // module (which is the only thing that can be importing it).
+ if (NewM && OldM &&
+ (OldM->Kind == Module::ModulePartitionInterface ||
+ OldM->Kind == Module::ModulePartitionImplementation)) {
+ return false;
+ }
+
if (NewM == OldM)
return false;
@@ -1660,7 +1690,13 @@ bool Sema::CheckRedeclarationExported(NamedDecl *New, NamedDecl *Old) {
assert(IsNewExported);
- Diag(New->getLocation(), diag::err_redeclaration_non_exported) << New;
+ auto Lk = Old->getFormalLinkage();
+ int S = 0;
+ if (Lk == Linkage::InternalLinkage)
+ S = 1;
+ else if (Lk == Linkage::ModuleLinkage)
+ S = 2;
+ Diag(New->getLocation(), diag::err_redeclaration_non_exported) << New << S;
Diag(Old->getLocation(), diag::note_previous_declaration);
return true;
}
@@ -1870,15 +1906,28 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
// Types of valid local variables should be complete, so this should succeed.
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
- // White-list anything with an __attribute__((unused)) type.
+ const Expr *Init = VD->getInit();
+ if (const auto *Cleanups = dyn_cast_or_null<ExprWithCleanups>(Init))
+ Init = Cleanups->getSubExpr();
+
const auto *Ty = VD->getType().getTypePtr();
// Only look at the outermost level of typedef.
if (const TypedefType *TT = Ty->getAs<TypedefType>()) {
+ // Allow anything marked with __attribute__((unused)).
if (TT->getDecl()->hasAttr<UnusedAttr>())
return false;
}
+ // Warn for reference variables whose initializtion performs lifetime
+ // extension.
+ if (const auto *MTE = dyn_cast_or_null<MaterializeTemporaryExpr>(Init)) {
+ if (MTE->getExtendingDecl()) {
+ Ty = VD->getType().getNonReferenceType().getTypePtr();
+ Init = MTE->getSubExpr()->IgnoreImplicitAsWritten();
+ }
+ }
+
// If we failed to complete the type for some reason, or if the type is
// dependent, don't diagnose the variable.
if (Ty->isIncompleteType() || Ty->isDependentType())
@@ -1897,10 +1946,7 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
if (!RD->hasTrivialDestructor() && !RD->hasAttr<WarnUnusedAttr>())
return false;
- if (const Expr *Init = VD->getInit()) {
- if (const ExprWithCleanups *Cleanups =
- dyn_cast<ExprWithCleanups>(Init))
- Init = Cleanups->getSubExpr();
+ if (Init) {
const CXXConstructExpr *Construct =
dyn_cast<CXXConstructExpr>(Init);
if (Construct && !Construct->isElidable()) {
@@ -1912,10 +1958,16 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
// Suppress the warning if we don't know how this is constructed, and
// it could possibly be non-trivial constructor.
- if (Init->isTypeDependent())
+ if (Init->isTypeDependent()) {
for (const CXXConstructorDecl *Ctor : RD->ctors())
if (!Ctor->isTrivial())
return false;
+ }
+
+ // Suppress the warning if the constructor is unresolved because
+ // its arguments are dependent.
+ if (isa<CXXUnresolvedConstructExpr>(Init))
+ return false;
}
}
}
@@ -2008,6 +2060,12 @@ void Sema::DiagnoseUnusedButSetDecl(const VarDecl *VD) {
if (VD->hasAttr<BlocksAttr>() && Ty->isObjCObjectPointerType())
return;
+ // Don't warn about Objective-C pointer variables with precise lifetime
+ // semantics; they can be used to ensure ARC releases the object at a known
+ // time, which may mean assignment but no other references.
+ if (VD->hasAttr<ObjCPreciseLifetimeAttr>() && Ty->isObjCObjectPointerType())
+ return;
+
auto iter = RefsMinusAssignments.find(VD);
if (iter == RefsMinusAssignments.end())
return;
@@ -2244,7 +2302,8 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID,
if (!ForRedeclaration &&
(Context.BuiltinInfo.isPredefinedLibFunction(ID) ||
Context.BuiltinInfo.isHeaderDependentFunction(ID))) {
- Diag(Loc, diag::ext_implicit_lib_function_decl)
+ Diag(Loc, LangOpts.C99 ? diag::ext_implicit_lib_function_decl_c99
+ : diag::ext_implicit_lib_function_decl)
<< Context.BuiltinInfo.getName(ID) << R;
if (const char *Header = Context.BuiltinInfo.getHeaderName(ID))
Diag(Loc, diag::note_include_header_or_declare)
@@ -2745,6 +2804,11 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
NewAttr = S.mergeEnforceTCBLeafAttr(D, *TCBLA);
else if (const auto *BTFA = dyn_cast<BTFDeclTagAttr>(Attr))
NewAttr = S.mergeBTFDeclTagAttr(D, *BTFA);
+ else if (const auto *NT = dyn_cast<HLSLNumThreadsAttr>(Attr))
+ NewAttr =
+ S.mergeHLSLNumThreadsAttr(D, *NT, NT->getX(), NT->getY(), NT->getZ());
+ else if (const auto *SA = dyn_cast<HLSLShaderAttr>(Attr))
+ NewAttr = S.mergeHLSLShaderAttr(D, *SA, SA->getType());
else if (Attr->shouldInheritEvenIfAlreadyPresent() || !DeclHasAttr(D, Attr))
NewAttr = cast<InheritableAttr>(Attr->clone(S.Context));
@@ -3195,6 +3259,10 @@ getNoteDiagForInvalidRedeclaration(const T *Old, const T *New) {
PrevDiag = diag::note_previous_definition;
else if (Old->isImplicit()) {
PrevDiag = diag::note_previous_implicit_declaration;
+ if (const auto *FD = dyn_cast<FunctionDecl>(Old)) {
+ if (FD->getBuiltinID())
+ PrevDiag = diag::note_previous_builtin_declaration;
+ }
if (OldLocation.isInvalid())
OldLocation = New->getLocation();
} else
@@ -3346,8 +3414,8 @@ static void adjustDeclContextForDeclaratorDecl(DeclaratorDecl *NewD,
/// merged with.
///
/// Returns true if there was an error, false otherwise.
-bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD,
- Scope *S, bool MergeTypeWithOld) {
+bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, Scope *S,
+ bool MergeTypeWithOld, bool NewDeclIsDefn) {
// Verify the old decl was also a function.
FunctionDecl *Old = OldD->getAsFunction();
if (!Old) {
@@ -3828,39 +3896,109 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD,
// C: Function types need to be compatible, not identical. This handles
// duplicate function decls like "void f(int); void f(enum X);" properly.
- if (!getLangOpts().CPlusPlus &&
- Context.typesAreCompatible(OldQType, NewQType)) {
- const FunctionType *OldFuncType = OldQType->getAs<FunctionType>();
- const FunctionType *NewFuncType = NewQType->getAs<FunctionType>();
- const FunctionProtoType *OldProto = nullptr;
- if (MergeTypeWithOld && isa<FunctionNoProtoType>(NewFuncType) &&
- (OldProto = dyn_cast<FunctionProtoType>(OldFuncType))) {
- // The old declaration provided a function prototype, but the
- // new declaration does not. Merge in the prototype.
- assert(!OldProto->hasExceptionSpec() && "Exception spec in C");
- SmallVector<QualType, 16> ParamTypes(OldProto->param_types());
- NewQType =
- Context.getFunctionType(NewFuncType->getReturnType(), ParamTypes,
- OldProto->getExtProtoInfo());
- New->setType(NewQType);
- New->setHasInheritedPrototype();
-
- // Synthesize parameters with the same types.
- SmallVector<ParmVarDecl*, 16> Params;
- for (const auto &ParamType : OldProto->param_types()) {
- ParmVarDecl *Param = ParmVarDecl::Create(Context, New, SourceLocation(),
- SourceLocation(), nullptr,
- ParamType, /*TInfo=*/nullptr,
- SC_None, nullptr);
- Param->setScopeInfo(0, Params.size());
- Param->setImplicit();
- Params.push_back(Param);
+ if (!getLangOpts().CPlusPlus) {
+ // C99 6.7.5.3p15: ...If one type has a parameter type list and the other
+ // type is specified by a function definition that contains a (possibly
+ // empty) identifier list, both shall agree in the number of parameters
+ // and the type of each parameter shall be compatible with the type that
+ // results from the application of default argument promotions to the
+ // type of the corresponding identifier. ...
+ // This cannot be handled by ASTContext::typesAreCompatible() because that
+ // doesn't know whether the function type is for a definition or not when
+ // eventually calling ASTContext::mergeFunctionTypes(). The only situation
+ // we need to cover here is that the number of arguments agree as the
+ // default argument promotion rules were already checked by
+ // ASTContext::typesAreCompatible().
+ if (Old->hasPrototype() && !New->hasWrittenPrototype() && NewDeclIsDefn &&
+ Old->getNumParams() != New->getNumParams()) {
+ if (Old->hasInheritedPrototype())
+ Old = Old->getCanonicalDecl();
+ Diag(New->getLocation(), diag::err_conflicting_types) << New;
+ Diag(Old->getLocation(), PrevDiag) << Old << Old->getType();
+ return true;
+ }
+
+ // If we are merging two functions where only one of them has a prototype,
+ // we may have enough information to decide to issue a diagnostic that the
+ // function without a protoype will change behavior in C2x. This handles
+ // cases like:
+ // void i(); void i(int j);
+ // void i(int j); void i();
+ // void i(); void i(int j) {}
+ // See ActOnFinishFunctionBody() for other cases of the behavior change
+ // diagnostic. See GetFullTypeForDeclarator() for handling of a function
+ // type without a prototype.
+ if (New->hasWrittenPrototype() != Old->hasWrittenPrototype() &&
+ !New->isImplicit() && !Old->isImplicit()) {
+ const FunctionDecl *WithProto, *WithoutProto;
+ if (New->hasWrittenPrototype()) {
+ WithProto = New;
+ WithoutProto = Old;
+ } else {
+ WithProto = Old;
+ WithoutProto = New;
}
- New->setParams(Params);
+ if (WithProto->getNumParams() != 0) {
+ if (WithoutProto->getBuiltinID() == 0 && !WithoutProto->isImplicit()) {
+ // The one without the prototype will be changing behavior in C2x, so
+ // warn about that one so long as it's a user-visible declaration.
+ bool IsWithoutProtoADef = false, IsWithProtoADef = false;
+ if (WithoutProto == New)
+ IsWithoutProtoADef = NewDeclIsDefn;
+ else
+ IsWithProtoADef = NewDeclIsDefn;
+ Diag(WithoutProto->getLocation(),
+ diag::warn_non_prototype_changes_behavior)
+ << IsWithoutProtoADef << (WithoutProto->getNumParams() ? 0 : 1)
+ << (WithoutProto == Old) << IsWithProtoADef;
+
+ // The reason the one without the prototype will be changing behavior
+ // is because of the one with the prototype, so note that so long as
+ // it's a user-visible declaration. There is one exception to this:
+ // when the new declaration is a definition without a prototype, the
+ // old declaration with a prototype is not the cause of the issue,
+ // and that does not need to be noted because the one with a
+ // prototype will not change behavior in C2x.
+ if (WithProto->getBuiltinID() == 0 && !WithProto->isImplicit() &&
+ !IsWithoutProtoADef)
+ Diag(WithProto->getLocation(), diag::note_conflicting_prototype);
+ }
+ }
}
- return MergeCompatibleFunctionDecls(New, Old, S, MergeTypeWithOld);
+ if (Context.typesAreCompatible(OldQType, NewQType)) {
+ const FunctionType *OldFuncType = OldQType->getAs<FunctionType>();
+ const FunctionType *NewFuncType = NewQType->getAs<FunctionType>();
+ const FunctionProtoType *OldProto = nullptr;
+ if (MergeTypeWithOld && isa<FunctionNoProtoType>(NewFuncType) &&
+ (OldProto = dyn_cast<FunctionProtoType>(OldFuncType))) {
+ // The old declaration provided a function prototype, but the
+ // new declaration does not. Merge in the prototype.
+ assert(!OldProto->hasExceptionSpec() && "Exception spec in C");
+ SmallVector<QualType, 16> ParamTypes(OldProto->param_types());
+ NewQType =
+ Context.getFunctionType(NewFuncType->getReturnType(), ParamTypes,
+ OldProto->getExtProtoInfo());
+ New->setType(NewQType);
+ New->setHasInheritedPrototype();
+
+ // Synthesize parameters with the same types.
+ SmallVector<ParmVarDecl *, 16> Params;
+ for (const auto &ParamType : OldProto->param_types()) {
+ ParmVarDecl *Param = ParmVarDecl::Create(
+ Context, New, SourceLocation(), SourceLocation(), nullptr,
+ ParamType, /*TInfo=*/nullptr, SC_None, nullptr);
+ Param->setScopeInfo(0, Params.size());
+ Param->setImplicit();
+ Params.push_back(Param);
+ }
+
+ New->setParams(Params);
+ }
+
+ return MergeCompatibleFunctionDecls(New, Old, S, MergeTypeWithOld);
+ }
}
// Check if the function types are compatible when pointer size address
@@ -4370,15 +4508,15 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
}
// C++ doesn't have tentative definitions, so go right ahead and check here.
- if (getLangOpts().CPlusPlus &&
- New->isThisDeclarationADefinition() == VarDecl::Definition) {
+ if (getLangOpts().CPlusPlus) {
if (Old->isStaticDataMember() && Old->getCanonicalDecl()->isInline() &&
Old->getCanonicalDecl()->isConstexpr()) {
// This definition won't be a definition any more once it's been merged.
Diag(New->getLocation(),
diag::warn_deprecated_redundant_constexpr_static_def);
- } else if (VarDecl *Def = Old->getDefinition()) {
- if (checkVarDeclRedefinition(Def, New))
+ } else if (New->isThisDeclarationADefinition() == VarDecl::Definition) {
+ VarDecl *Def = Old->getDefinition();
+ if (Def && checkVarDeclRedefinition(Def, New))
return;
}
}
@@ -4491,11 +4629,12 @@ bool Sema::checkVarDeclRedefinition(VarDecl *Old, VarDecl *New) {
/// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
/// no declarator (e.g. "struct foo;") is parsed.
-Decl *
-Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS,
- RecordDecl *&AnonRecord) {
- return ParsedFreeStandingDeclSpec(S, AS, DS, MultiTemplateParamsArg(), false,
- AnonRecord);
+Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
+ DeclSpec &DS,
+ const ParsedAttributesView &DeclAttrs,
+ RecordDecl *&AnonRecord) {
+ return ParsedFreeStandingDeclSpec(
+ S, AS, DS, DeclAttrs, MultiTemplateParamsArg(), false, AnonRecord);
}
// The MS ABI changed between VS2013 and VS2015 with regard to numbers used to
@@ -4708,11 +4847,12 @@ static unsigned GetDiagnosticTypeSpecifierID(DeclSpec::TST T) {
/// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
/// no declarator (e.g. "struct foo;") is parsed. It also accepts template
/// parameters to cope with template friend declarations.
-Decl *
-Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS,
- MultiTemplateParamsArg TemplateParams,
- bool IsExplicitInstantiation,
- RecordDecl *&AnonRecord) {
+Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
+ DeclSpec &DS,
+ const ParsedAttributesView &DeclAttrs,
+ MultiTemplateParamsArg TemplateParams,
+ bool IsExplicitInstantiation,
+ RecordDecl *&AnonRecord) {
Decl *TagD = nullptr;
TagDecl *Tag = nullptr;
if (DS.getTypeSpecType() == DeclSpec::TST_class ||
@@ -4951,7 +5091,7 @@ Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS,
// Warn about ignored type attributes, for example:
// __attribute__((aligned)) struct A;
// Attributes should be placed after tag to apply to type declaration.
- if (!DS.getAttributes().empty()) {
+ if (!DS.getAttributes().empty() || !DeclAttrs.empty()) {
DeclSpec::TST TypeSpecType = DS.getTypeSpecType();
if (TypeSpecType == DeclSpec::TST_class ||
TypeSpecType == DeclSpec::TST_struct ||
@@ -4961,6 +5101,9 @@ Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS,
for (const ParsedAttr &AL : DS.getAttributes())
Diag(AL.getLoc(), diag::warn_declspec_attribute_ignored)
<< AL << GetDiagnosticTypeSpecifierID(TypeSpecType);
+ for (const ParsedAttr &AL : DeclAttrs)
+ Diag(AL.getLoc(), diag::warn_declspec_attribute_ignored)
+ << AL << GetDiagnosticTypeSpecifierID(TypeSpecType);
}
}
@@ -5323,7 +5466,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
Diag(DS.getBeginLoc(), diag::ext_no_declarators) << DS.getSourceRange();
// Mock up a declarator.
- Declarator Dc(DS, DeclaratorContext::Member);
+ Declarator Dc(DS, ParsedAttributesView::none(), DeclaratorContext::Member);
TypeSourceInfo *TInfo = GetTypeForDeclarator(Dc, S);
assert(TInfo && "couldn't build declarator info for anonymous struct/union");
@@ -5420,7 +5563,7 @@ Decl *Sema::BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS,
assert(Record && "expected a record!");
// Mock up a declarator.
- Declarator Dc(DS, DeclaratorContext::TypeName);
+ Declarator Dc(DS, ParsedAttributesView::none(), DeclaratorContext::TypeName);
TypeSourceInfo *TInfo = GetTypeForDeclarator(Dc, S);
assert(TInfo && "couldn't build declarator info for anonymous struct");
@@ -5629,7 +5772,7 @@ static bool hasSimilarParameters(ASTContext &Context,
return true;
}
-/// NeedsRebuildingInCurrentInstantiation - Checks whether the given
+/// RebuildDeclaratorInCurrentInstantiation - Checks whether the given
/// declarator needs to be rebuilt in the current instantiation.
/// Any bits of declarator which appear before the name are valid for
/// consideration here. That's specifically the type in the decl spec
@@ -5725,12 +5868,25 @@ void Sema::warnOnReservedIdentifier(const NamedDecl *D) {
Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D) {
D.setFunctionDefinitionKind(FunctionDefinitionKind::Declaration);
+
+ // Check if we are in an `omp begin/end declare variant` scope. Handle this
+ // declaration only if the `bind_to_declaration` extension is set.
+ SmallVector<FunctionDecl *, 4> Bases;
+ if (LangOpts.OpenMP && isInOpenMPDeclareVariantScope())
+ if (getOMPTraitInfoForSurroundingScope()->isExtensionActive(llvm::omp::TraitProperty::
+ implementation_extension_bind_to_declaration))
+ ActOnStartOfFunctionDefinitionInOpenMPDeclareVariantScope(
+ S, D, MultiTemplateParamsArg(), Bases);
+
Decl *Dcl = HandleDeclarator(S, D, MultiTemplateParamsArg());
if (OriginalLexicalContext && OriginalLexicalContext->isObjCContainer() &&
Dcl && Dcl->getDeclContext()->isFileContext())
Dcl->setTopLevelDeclInObjCContainer();
+ if (!Bases.empty())
+ ActOnFinishedFunctionDefinitionInOpenMPDeclareVariantScope(Dcl, Bases);
+
return Dcl;
}
@@ -6862,7 +7018,8 @@ static bool hasParsedAttr(Scope *S, const Declarator &PD,
}
// Finally, check attributes on the decl itself.
- return PD.getAttributes().hasAttribute(Kind);
+ return PD.getAttributes().hasAttribute(Kind) ||
+ PD.getDeclarationAttributes().hasAttribute(Kind);
}
/// Adjust the \c DeclContext for a function or variable that might be a
@@ -8640,15 +8797,24 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
bool isInline = D.getDeclSpec().isInlineSpecified();
if (!SemaRef.getLangOpts().CPlusPlus) {
- // Determine whether the function was written with a
- // prototype. This true when:
+ // Determine whether the function was written with a prototype. This is
+ // true when:
// - there is a prototype in the declarator, or
// - the type R of the function is some kind of typedef or other non-
// attributed reference to a type name (which eventually refers to a
- // function type).
+ // function type). Note, we can't always look at the adjusted type to
+ // check this case because attributes may cause a non-function
+ // declarator to still have a function type. e.g.,
+ // typedef void func(int a);
+ // __attribute__((noreturn)) func other_func; // This has a prototype
bool HasPrototype =
- (D.isFunctionDeclarator() && D.getFunctionTypeInfo().hasPrototype) ||
- (!R->getAsAdjusted<FunctionType>() && R->isFunctionProtoType());
+ (D.isFunctionDeclarator() && D.getFunctionTypeInfo().hasPrototype) ||
+ (D.getDeclSpec().isTypeRep() &&
+ D.getDeclSpec().getRepAsType().get()->isFunctionProtoType()) ||
+ (!R->getAsAdjusted<FunctionType>() && R->isFunctionProtoType());
+ assert(
+ (HasPrototype || !SemaRef.getLangOpts().requiresStrictPrototypes()) &&
+ "Strict prototypes are required");
NewFD = FunctionDecl::Create(
SemaRef.Context, DC, D.getBeginLoc(), NameInfo, R, TInfo, SC,
@@ -8704,6 +8870,10 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
SemaRef.getCurFPFeatures().isFPConstrained(), isInline,
/*isImplicitlyDeclared=*/false, ConstexprKind,
TrailingRequiresClause);
+ // User defined destructors start as not selected if the class definition is still
+ // not done.
+ if (Record->isBeingDefined())
+ NewDD->setIneligibleOrNotSelected(true);
// If the destructor needs an implicit exception specification, set it
// now. FIXME: It'd be nice to be able to create the right type to start
@@ -9100,6 +9270,32 @@ static Scope *getTagInjectionScope(Scope *S, const LangOptions &LangOpts) {
return S;
}
+/// Determine whether a declaration matches a known function in namespace std.
+static bool isStdBuiltin(ASTContext &Ctx, FunctionDecl *FD,
+ unsigned BuiltinID) {
+ switch (BuiltinID) {
+ case Builtin::BI__GetExceptionInfo:
+ // No type checking whatsoever.
+ return Ctx.getTargetInfo().getCXXABI().isMicrosoft();
+
+ case Builtin::BIaddressof:
+ case Builtin::BI__addressof:
+ case Builtin::BIforward:
+ case Builtin::BImove:
+ case Builtin::BImove_if_noexcept:
+ case Builtin::BIas_const: {
+ // Ensure that we don't treat the algorithm
+ // OutputIt std::move(InputIt, InputIt, OutputIt)
+ // as the builtin std::move.
+ const auto *FPT = FD->getType()->castAs<FunctionProtoType>();
+ return FPT->getNumParams() == 1 && !FPT->isVariadic();
+ }
+
+ default:
+ return false;
+ }
+}
+
NamedDecl*
Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
TypeSourceInfo *TInfo, LookupResult &Previous,
@@ -9112,8 +9308,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
Diag(D.getIdentifierLoc(), diag::err_function_decl_cmse_ns_call);
SmallVector<TemplateParameterList *, 4> TemplateParamLists;
- for (TemplateParameterList *TPL : TemplateParamListsRef)
- TemplateParamLists.push_back(TPL);
+ llvm::append_range(TemplateParamLists, TemplateParamListsRef);
if (TemplateParameterList *Invented = D.getInventedTemplateParameterList()) {
if (!TemplateParamLists.empty() &&
Invented->getDepth() == TemplateParamLists.back()->getDepth())
@@ -9193,7 +9388,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
if ((Parent->isClass() || Parent->isStruct()) &&
Parent->hasAttr<SYCLSpecialClassAttr>() &&
- NewFD->getKind() == Decl::Kind::CXXMethod &&
+ NewFD->getKind() == Decl::Kind::CXXMethod && NewFD->getIdentifier() &&
NewFD->getName() == "__init" && D.isFunctionDefinition()) {
if (auto *Def = Parent->getDefinition())
Def->setInitMethod(true);
@@ -9673,7 +9868,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (!NewFD->isInvalidDecl())
D.setRedeclaration(CheckFunctionDeclaration(S, NewFD, Previous,
- isMemberSpecialization));
+ isMemberSpecialization,
+ D.isFunctionDefinition()));
else if (!Previous.empty())
// Recover gracefully from an invalid redeclaration.
D.setRedeclaration(true);
@@ -9823,7 +10019,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (!NewFD->isInvalidDecl())
D.setRedeclaration(CheckFunctionDeclaration(S, NewFD, Previous,
- isMemberSpecialization));
+ isMemberSpecialization,
+ D.isFunctionDefinition()));
else if (!Previous.empty())
// Recover gracefully from an invalid redeclaration.
D.setRedeclaration(true);
@@ -9951,28 +10148,30 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// If this is the first declaration of a library builtin function, add
// attributes as appropriate.
- if (!D.isRedeclaration() &&
- NewFD->getDeclContext()->getRedeclContext()->isFileContext()) {
+ if (!D.isRedeclaration()) {
if (IdentifierInfo *II = Previous.getLookupName().getAsIdentifierInfo()) {
if (unsigned BuiltinID = II->getBuiltinID()) {
- if (NewFD->getLanguageLinkage() == CLanguageLinkage) {
- // Validate the type matches unless this builtin is specified as
- // matching regardless of its declared type.
- if (Context.BuiltinInfo.allowTypeMismatch(BuiltinID)) {
- NewFD->addAttr(BuiltinAttr::CreateImplicit(Context, BuiltinID));
- } else {
- ASTContext::GetBuiltinTypeError Error;
- LookupNecessaryTypesForBuiltin(S, BuiltinID);
- QualType BuiltinType = Context.GetBuiltinType(BuiltinID, Error);
-
- if (!Error && !BuiltinType.isNull() &&
- Context.hasSameFunctionTypeIgnoringExceptionSpec(
- NewFD->getType(), BuiltinType))
+ bool InStdNamespace = Context.BuiltinInfo.isInStdNamespace(BuiltinID);
+ if (!InStdNamespace &&
+ NewFD->getDeclContext()->getRedeclContext()->isFileContext()) {
+ if (NewFD->getLanguageLinkage() == CLanguageLinkage) {
+ // Validate the type matches unless this builtin is specified as
+ // matching regardless of its declared type.
+ if (Context.BuiltinInfo.allowTypeMismatch(BuiltinID)) {
NewFD->addAttr(BuiltinAttr::CreateImplicit(Context, BuiltinID));
+ } else {
+ ASTContext::GetBuiltinTypeError Error;
+ LookupNecessaryTypesForBuiltin(S, BuiltinID);
+ QualType BuiltinType = Context.GetBuiltinType(BuiltinID, Error);
+
+ if (!Error && !BuiltinType.isNull() &&
+ Context.hasSameFunctionTypeIgnoringExceptionSpec(
+ NewFD->getType(), BuiltinType))
+ NewFD->addAttr(BuiltinAttr::CreateImplicit(Context, BuiltinID));
+ }
}
- } else if (BuiltinID == Builtin::BI__GetExceptionInfo &&
- Context.getTargetInfo().getCXXABI().isMicrosoft()) {
- // FIXME: We should consider this a builtin only in the std namespace.
+ } else if (InStdNamespace && NewFD->isInStdNamespace() &&
+ isStdBuiltin(Context, NewFD, BuiltinID)) {
NewFD->addAttr(BuiltinAttr::CreateImplicit(Context, BuiltinID));
}
}
@@ -10010,10 +10209,14 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// marking the function.
AddCFAuditedAttribute(NewFD);
- // If this is a function definition, check if we have to apply optnone due to
- // a pragma.
- if(D.isFunctionDefinition())
+ // If this is a function definition, check if we have to apply any
+ // attributes (i.e. optnone and no_builtin) due to a pragma.
+ if (D.isFunctionDefinition()) {
AddRangeBasedOptnone(NewFD);
+ AddImplicitMSFunctionNoBuiltinAttr(NewFD);
+ AddSectionMSAllocText(NewFD);
+ ModifyFnAttributesMSPragmaOptimize(NewFD);
+ }
// If this is the first declaration of an extern C variable, update
// the map of such variables.
@@ -10337,14 +10540,14 @@ static bool CheckMultiVersionValue(Sema &S, const FunctionDecl *FD) {
// Provide a white-list of attributes that are allowed to be combined with
// multiversion functions.
static bool AttrCompatibleWithMultiVersion(attr::Kind Kind,
- MultiVersionKind MVType) {
+ MultiVersionKind MVKind) {
// Note: this list/diagnosis must match the list in
// checkMultiversionAttributesAllSame.
switch (Kind) {
default:
return false;
case attr::Used:
- return MVType == MultiVersionKind::Target;
+ return MVKind == MultiVersionKind::Target;
case attr::NonNull:
case attr::NoThrow:
return true;
@@ -10354,10 +10557,10 @@ static bool AttrCompatibleWithMultiVersion(attr::Kind Kind,
static bool checkNonMultiVersionCompatAttributes(Sema &S,
const FunctionDecl *FD,
const FunctionDecl *CausedFD,
- MultiVersionKind MVType) {
- const auto Diagnose = [FD, CausedFD, MVType](Sema &S, const Attr *A) {
+ MultiVersionKind MVKind) {
+ const auto Diagnose = [FD, CausedFD, MVKind](Sema &S, const Attr *A) {
S.Diag(FD->getLocation(), diag::err_multiversion_disallowed_other_attr)
- << static_cast<unsigned>(MVType) << A;
+ << static_cast<unsigned>(MVKind) << A;
if (CausedFD)
S.Diag(CausedFD->getLocation(), diag::note_multiversioning_caused_here);
return true;
@@ -10367,20 +10570,20 @@ static bool checkNonMultiVersionCompatAttributes(Sema &S,
switch (A->getKind()) {
case attr::CPUDispatch:
case attr::CPUSpecific:
- if (MVType != MultiVersionKind::CPUDispatch &&
- MVType != MultiVersionKind::CPUSpecific)
+ if (MVKind != MultiVersionKind::CPUDispatch &&
+ MVKind != MultiVersionKind::CPUSpecific)
return Diagnose(S, A);
break;
case attr::Target:
- if (MVType != MultiVersionKind::Target)
+ if (MVKind != MultiVersionKind::Target)
return Diagnose(S, A);
break;
case attr::TargetClones:
- if (MVType != MultiVersionKind::TargetClones)
+ if (MVKind != MultiVersionKind::TargetClones)
return Diagnose(S, A);
break;
default:
- if (!AttrCompatibleWithMultiVersion(A->getKind(), MVType))
+ if (!AttrCompatibleWithMultiVersion(A->getKind(), MVKind))
return Diagnose(S, A);
break;
}
@@ -10504,7 +10707,7 @@ bool Sema::areMultiversionVariantFunctionsCompatible(
static bool CheckMultiVersionAdditionalRules(Sema &S, const FunctionDecl *OldFD,
const FunctionDecl *NewFD,
bool CausesMV,
- MultiVersionKind MVType) {
+ MultiVersionKind MVKind) {
if (!S.getASTContext().getTargetInfo().supportsMultiVersioning()) {
S.Diag(NewFD->getLocation(), diag::err_multiversion_not_supported);
if (OldFD)
@@ -10512,15 +10715,15 @@ static bool CheckMultiVersionAdditionalRules(Sema &S, const FunctionDecl *OldFD,
return true;
}
- bool IsCPUSpecificCPUDispatchMVType =
- MVType == MultiVersionKind::CPUDispatch ||
- MVType == MultiVersionKind::CPUSpecific;
+ bool IsCPUSpecificCPUDispatchMVKind =
+ MVKind == MultiVersionKind::CPUDispatch ||
+ MVKind == MultiVersionKind::CPUSpecific;
if (CausesMV && OldFD &&
- checkNonMultiVersionCompatAttributes(S, OldFD, NewFD, MVType))
+ checkNonMultiVersionCompatAttributes(S, OldFD, NewFD, MVKind))
return true;
- if (checkNonMultiVersionCompatAttributes(S, NewFD, nullptr, MVType))
+ if (checkNonMultiVersionCompatAttributes(S, NewFD, nullptr, MVKind))
return true;
// Only allow transition to MultiVersion if it hasn't been used.
@@ -10533,11 +10736,11 @@ static bool CheckMultiVersionAdditionalRules(Sema &S, const FunctionDecl *OldFD,
S.PDiag(diag::note_multiversioning_caused_here)),
PartialDiagnosticAt(NewFD->getLocation(),
S.PDiag(diag::err_multiversion_doesnt_support)
- << static_cast<unsigned>(MVType)),
+ << static_cast<unsigned>(MVKind)),
PartialDiagnosticAt(NewFD->getLocation(),
S.PDiag(diag::err_multiversion_diff)),
/*TemplatesSupported=*/false,
- /*ConstexprSupported=*/!IsCPUSpecificCPUDispatchMVType,
+ /*ConstexprSupported=*/!IsCPUSpecificCPUDispatchMVKind,
/*CLinkageMayDiffer=*/false);
}
@@ -10548,22 +10751,22 @@ static bool CheckMultiVersionAdditionalRules(Sema &S, const FunctionDecl *OldFD,
///
/// Returns true if there was an error, false otherwise.
static bool CheckMultiVersionFirstFunction(Sema &S, FunctionDecl *FD,
- MultiVersionKind MVType,
+ MultiVersionKind MVKind,
const TargetAttr *TA) {
- assert(MVType != MultiVersionKind::None &&
+ assert(MVKind != MultiVersionKind::None &&
"Function lacks multiversion attribute");
// Target only causes MV if it is default, otherwise this is a normal
// function.
- if (MVType == MultiVersionKind::Target && !TA->isDefaultVersion())
+ if (MVKind == MultiVersionKind::Target && !TA->isDefaultVersion())
return false;
- if (MVType == MultiVersionKind::Target && CheckMultiVersionValue(S, FD)) {
+ if (MVKind == MultiVersionKind::Target && CheckMultiVersionValue(S, FD)) {
FD->setInvalidDecl();
return true;
}
- if (CheckMultiVersionAdditionalRules(S, nullptr, FD, true, MVType)) {
+ if (CheckMultiVersionAdditionalRules(S, nullptr, FD, true, MVKind)) {
FD->setInvalidDecl();
return true;
}
@@ -10583,8 +10786,7 @@ static bool PreviousDeclsHaveMultiVersionAttribute(const FunctionDecl *FD) {
static bool CheckTargetCausesMultiVersioning(
Sema &S, FunctionDecl *OldFD, FunctionDecl *NewFD, const TargetAttr *NewTA,
- bool &Redeclaration, NamedDecl *&OldDecl, bool &MergeTypeWithPrevious,
- LookupResult &Previous) {
+ bool &Redeclaration, NamedDecl *&OldDecl, LookupResult &Previous) {
const auto *OldTA = OldFD->getAttr<TargetAttr>();
ParsedTargetAttr NewParsed = NewTA->parse();
// Sort order doesn't matter, it just needs to be consistent.
@@ -10597,13 +10799,6 @@ static bool CheckTargetCausesMultiVersioning(
return false;
// Otherwise, this decl causes MultiVersioning.
- if (!S.getASTContext().getTargetInfo().supportsMultiVersioning()) {
- S.Diag(NewFD->getLocation(), diag::err_multiversion_not_supported);
- S.Diag(OldFD->getLocation(), diag::note_previous_declaration);
- NewFD->setInvalidDecl();
- return true;
- }
-
if (CheckMultiVersionAdditionalRules(S, OldFD, NewFD, true,
MultiVersionKind::Target)) {
NewFD->setInvalidDecl();
@@ -10656,7 +10851,6 @@ static bool CheckTargetCausesMultiVersioning(
OldFD->setIsMultiVersion();
NewFD->setIsMultiVersion();
Redeclaration = false;
- MergeTypeWithPrevious = false;
OldDecl = nullptr;
Previous.clear();
return false;
@@ -10678,14 +10872,14 @@ static bool MultiVersionTypesCompatible(MultiVersionKind Old,
/// multiversioned declaration collection.
static bool CheckMultiVersionAdditionalDecl(
Sema &S, FunctionDecl *OldFD, FunctionDecl *NewFD,
- MultiVersionKind NewMVType, const TargetAttr *NewTA,
+ MultiVersionKind NewMVKind, const TargetAttr *NewTA,
const CPUDispatchAttr *NewCPUDisp, const CPUSpecificAttr *NewCPUSpec,
const TargetClonesAttr *NewClones, bool &Redeclaration, NamedDecl *&OldDecl,
- bool &MergeTypeWithPrevious, LookupResult &Previous) {
+ LookupResult &Previous) {
- MultiVersionKind OldMVType = OldFD->getMultiVersionKind();
+ MultiVersionKind OldMVKind = OldFD->getMultiVersionKind();
// Disallow mixing of multiversioning types.
- if (!MultiVersionTypesCompatible(OldMVType, NewMVType)) {
+ if (!MultiVersionTypesCompatible(OldMVKind, NewMVKind)) {
S.Diag(NewFD->getLocation(), diag::err_multiversion_types_mixed);
S.Diag(OldFD->getLocation(), diag::note_previous_declaration);
NewFD->setInvalidDecl();
@@ -10701,18 +10895,22 @@ static bool CheckMultiVersionAdditionalDecl(
bool UseMemberUsingDeclRules =
S.CurContext->isRecord() && !NewFD->getFriendObjectKind();
+ bool MayNeedOverloadableChecks =
+ AllowOverloadingOfFunction(Previous, S.Context, NewFD);
+
// Next, check ALL non-overloads to see if this is a redeclaration of a
// previous member of the MultiVersion set.
for (NamedDecl *ND : Previous) {
FunctionDecl *CurFD = ND->getAsFunction();
if (!CurFD)
continue;
- if (S.IsOverload(NewFD, CurFD, UseMemberUsingDeclRules))
+ if (MayNeedOverloadableChecks &&
+ S.IsOverload(NewFD, CurFD, UseMemberUsingDeclRules))
continue;
- switch (NewMVType) {
+ switch (NewMVKind) {
case MultiVersionKind::None:
- assert(OldMVType == MultiVersionKind::TargetClones &&
+ assert(OldMVKind == MultiVersionKind::TargetClones &&
"Only target_clones can be omitted in subsequent declarations");
break;
case MultiVersionKind::Target: {
@@ -10737,7 +10935,6 @@ static bool CheckMultiVersionAdditionalDecl(
const auto *CurClones = CurFD->getAttr<TargetClonesAttr>();
Redeclaration = true;
OldDecl = CurFD;
- MergeTypeWithPrevious = true;
NewFD->setIsMultiVersion();
if (CurClones && NewClones &&
@@ -10760,7 +10957,7 @@ static bool CheckMultiVersionAdditionalDecl(
// Handle CPUDispatch/CPUSpecific versions.
// Only 1 CPUDispatch function is allowed, this will make it go through
// the redeclaration errors.
- if (NewMVType == MultiVersionKind::CPUDispatch &&
+ if (NewMVKind == MultiVersionKind::CPUDispatch &&
CurFD->hasAttr<CPUDispatchAttr>()) {
if (CurCPUDisp->cpus_size() == NewCPUDisp->cpus_size() &&
std::equal(
@@ -10781,8 +10978,7 @@ static bool CheckMultiVersionAdditionalDecl(
NewFD->setInvalidDecl();
return true;
}
- if (NewMVType == MultiVersionKind::CPUSpecific && CurCPUSpec) {
-
+ if (NewMVKind == MultiVersionKind::CPUSpecific && CurCPUSpec) {
if (CurCPUSpec->cpus_size() == NewCPUSpec->cpus_size() &&
std::equal(
CurCPUSpec->cpus_begin(), CurCPUSpec->cpus_end(),
@@ -10817,14 +11013,14 @@ static bool CheckMultiVersionAdditionalDecl(
// Else, this is simply a non-redecl case. Checking the 'value' is only
// necessary in the Target case, since The CPUSpecific/Dispatch cases are
// handled in the attribute adding step.
- if (NewMVType == MultiVersionKind::Target &&
+ if (NewMVKind == MultiVersionKind::Target &&
CheckMultiVersionValue(S, NewFD)) {
NewFD->setInvalidDecl();
return true;
}
if (CheckMultiVersionAdditionalRules(S, OldFD, NewFD,
- !OldFD->isMultiVersion(), NewMVType)) {
+ !OldFD->isMultiVersion(), NewMVKind)) {
NewFD->setInvalidDecl();
return true;
}
@@ -10840,7 +11036,6 @@ static bool CheckMultiVersionAdditionalDecl(
NewFD->setIsMultiVersion();
Redeclaration = false;
- MergeTypeWithPrevious = false;
OldDecl = nullptr;
Previous.clear();
return false;
@@ -10854,19 +11049,18 @@ static bool CheckMultiVersionAdditionalDecl(
/// Returns true if there was an error, false otherwise.
static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD,
bool &Redeclaration, NamedDecl *&OldDecl,
- bool &MergeTypeWithPrevious,
LookupResult &Previous) {
const auto *NewTA = NewFD->getAttr<TargetAttr>();
const auto *NewCPUDisp = NewFD->getAttr<CPUDispatchAttr>();
const auto *NewCPUSpec = NewFD->getAttr<CPUSpecificAttr>();
const auto *NewClones = NewFD->getAttr<TargetClonesAttr>();
- MultiVersionKind MVType = NewFD->getMultiVersionKind();
+ MultiVersionKind MVKind = NewFD->getMultiVersionKind();
// Main isn't allowed to become a multiversion function, however it IS
// permitted to have 'main' be marked with the 'target' optimization hint.
if (NewFD->isMain()) {
- if (MVType != MultiVersionKind::None &&
- !(MVType == MultiVersionKind::Target && !NewTA->isDefaultVersion())) {
+ if (MVKind != MultiVersionKind::None &&
+ !(MVKind == MultiVersionKind::Target && !NewTA->isDefaultVersion())) {
S.Diag(NewFD->getLocation(), diag::err_multiversion_not_allowed_on_main);
NewFD->setInvalidDecl();
return true;
@@ -10879,19 +11073,19 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD,
NewFD->getDeclContext()->getRedeclContext()) {
// If there's no previous declaration, AND this isn't attempting to cause
// multiversioning, this isn't an error condition.
- if (MVType == MultiVersionKind::None)
+ if (MVKind == MultiVersionKind::None)
return false;
- return CheckMultiVersionFirstFunction(S, NewFD, MVType, NewTA);
+ return CheckMultiVersionFirstFunction(S, NewFD, MVKind, NewTA);
}
FunctionDecl *OldFD = OldDecl->getAsFunction();
- if (!OldFD->isMultiVersion() && MVType == MultiVersionKind::None)
+ if (!OldFD->isMultiVersion() && MVKind == MultiVersionKind::None)
return false;
// Multiversioned redeclarations aren't allowed to omit the attribute, except
// for target_clones.
- if (OldFD->isMultiVersion() && MVType == MultiVersionKind::None &&
+ if (OldFD->isMultiVersion() && MVKind == MultiVersionKind::None &&
OldFD->getMultiVersionKind() != MultiVersionKind::TargetClones) {
S.Diag(NewFD->getLocation(), diag::err_multiversion_required_in_redecl)
<< (OldFD->getMultiVersionKind() != MultiVersionKind::Target);
@@ -10900,11 +11094,10 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD,
}
if (!OldFD->isMultiVersion()) {
- switch (MVType) {
+ switch (MVKind) {
case MultiVersionKind::Target:
return CheckTargetCausesMultiVersioning(S, OldFD, NewFD, NewTA,
- Redeclaration, OldDecl,
- MergeTypeWithPrevious, Previous);
+ Redeclaration, OldDecl, Previous);
case MultiVersionKind::TargetClones:
if (OldFD->isUsed(false)) {
NewFD->setInvalidDecl();
@@ -10918,18 +11111,13 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD,
break;
}
}
- // Handle the target potentially causes multiversioning case.
- if (!OldFD->isMultiVersion() && MVType == MultiVersionKind::Target)
- return CheckTargetCausesMultiVersioning(S, OldFD, NewFD, NewTA,
- Redeclaration, OldDecl,
- MergeTypeWithPrevious, Previous);
// At this point, we have a multiversion function decl (in OldFD) AND an
// appropriate attribute in the current function decl. Resolve that these are
// still compatible with previous declarations.
- return CheckMultiVersionAdditionalDecl(
- S, OldFD, NewFD, MVType, NewTA, NewCPUDisp, NewCPUSpec, NewClones,
- Redeclaration, OldDecl, MergeTypeWithPrevious, Previous);
+ return CheckMultiVersionAdditionalDecl(S, OldFD, NewFD, MVKind, NewTA,
+ NewCPUDisp, NewCPUSpec, NewClones,
+ Redeclaration, OldDecl, Previous);
}
/// Perform semantic checking of a new function declaration.
@@ -10951,7 +11139,8 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD,
/// \returns true if the function declaration is a redeclaration.
bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
LookupResult &Previous,
- bool IsMemberSpecialization) {
+ bool IsMemberSpecialization,
+ bool DeclIsDefn) {
assert(!NewFD->getReturnType()->isVariablyModifiedType() &&
"Variably modified return types are not handled here");
@@ -11019,8 +11208,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
}
}
- if (CheckMultiVersionFunction(*this, NewFD, Redeclaration, OldDecl,
- MergeTypeWithPrevious, Previous))
+ if (CheckMultiVersionFunction(*this, NewFD, Redeclaration, OldDecl, Previous))
return Redeclaration;
// PPC MMA non-pointer types are not allowed as function return types.
@@ -11070,7 +11258,8 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
if (Redeclaration) {
// NewFD and OldDecl represent declarations that need to be
// merged.
- if (MergeFunctionDecl(NewFD, OldDecl, S, MergeTypeWithPrevious)) {
+ if (MergeFunctionDecl(NewFD, OldDecl, S, MergeTypeWithPrevious,
+ DeclIsDefn)) {
NewFD->setInvalidDecl();
return Redeclaration;
}
@@ -11200,6 +11389,15 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
checkThisInStaticMemberFunctionType(Method);
}
+ // C++20: dcl.decl.general p4:
+ // The optional requires-clause ([temp.pre]) in an init-declarator or
+ // member-declarator shall be present only if the declarator declares a
+ // templated function ([dcl.fct]).
+ if (Expr *TRC = NewFD->getTrailingRequiresClause()) {
+ if (!NewFD->isTemplated() && !NewFD->isTemplateInstantiation())
+ Diag(TRC->getBeginLoc(), diag::err_constrained_non_templated_function);
+ }
+
if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(NewFD))
ActOnConversionDeclarator(Conversion);
@@ -11315,6 +11513,11 @@ void Sema::CheckMain(FunctionDecl* FD, const DeclSpec& DS) {
return;
}
+ // Functions named main in hlsl are default entries, but don't have specific
+ // signatures they are required to conform to.
+ if (getLangOpts().HLSL)
+ return;
+
QualType T = FD->getType();
assert(T->isFunctionType() && "function decl is not of function type");
const FunctionType* FT = T->castAs<FunctionType>();
@@ -12990,7 +13193,6 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
if (Type->isReferenceType()) {
Diag(Var->getLocation(), diag::err_reference_var_requires_init)
<< Var << SourceRange(Var->getLocation(), Var->getLocation());
- Var->setInvalidDecl();
return;
}
@@ -13139,11 +13341,9 @@ void Sema::ActOnCXXForRangeDecl(Decl *D) {
}
}
-StmtResult
-Sema::ActOnCXXForRangeIdentifier(Scope *S, SourceLocation IdentLoc,
- IdentifierInfo *Ident,
- ParsedAttributes &Attrs,
- SourceLocation AttrEnd) {
+StmtResult Sema::ActOnCXXForRangeIdentifier(Scope *S, SourceLocation IdentLoc,
+ IdentifierInfo *Ident,
+ ParsedAttributes &Attrs) {
// C++1y [stmt.iter]p1:
// A range-based for statement of the form
// for ( for-range-identifier : for-range-initializer ) statement
@@ -13156,9 +13356,9 @@ Sema::ActOnCXXForRangeIdentifier(Scope *S, SourceLocation IdentLoc,
DS.SetTypeSpecType(DeclSpec::TST_auto, IdentLoc, PrevSpec, DiagID,
getPrintingPolicy());
- Declarator D(DS, DeclaratorContext::ForInit);
+ Declarator D(DS, ParsedAttributesView::none(), DeclaratorContext::ForInit);
D.SetIdentifier(Ident, IdentLoc);
- D.takeAttributes(Attrs, AttrEnd);
+ D.takeAttributes(Attrs);
D.AddTypeInfo(DeclaratorChunk::getReference(0, IdentLoc, /*lvalue*/ false),
IdentLoc);
@@ -13166,7 +13366,8 @@ Sema::ActOnCXXForRangeIdentifier(Scope *S, SourceLocation IdentLoc,
cast<VarDecl>(Var)->setCXXForRangeDecl(true);
FinalizeDeclaration(Var);
return ActOnDeclStmt(FinalizeDeclaratorGroup(S, DS, Var), IdentLoc,
- AttrEnd.isValid() ? AttrEnd : IdentLoc);
+ Attrs.Range.getEnd().isValid() ? Attrs.Range.getEnd()
+ : IdentLoc);
}
void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
@@ -14119,18 +14320,28 @@ void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D,
SourceLocation LocAfterDecls) {
DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo();
- // Verify 6.9.1p6: 'every identifier in the identifier list shall be declared'
- // for a K&R function.
+ // C99 6.9.1p6 "If a declarator includes an identifier list, each declaration
+ // in the declaration list shall have at least one declarator, those
+ // declarators shall only declare identifiers from the identifier list, and
+ // every identifier in the identifier list shall be declared.
+ //
+ // C89 3.7.1p5 "If a declarator includes an identifier list, only the
+ // identifiers it names shall be declared in the declaration list."
+ //
+ // This is why we only diagnose in C99 and later. Note, the other conditions
+ // listed are checked elsewhere.
if (!FTI.hasPrototype) {
for (int i = FTI.NumParams; i != 0; /* decrement in loop */) {
--i;
if (FTI.Params[i].Param == nullptr) {
- SmallString<256> Code;
- llvm::raw_svector_ostream(Code)
- << " int " << FTI.Params[i].Ident->getName() << ";\n";
- Diag(FTI.Params[i].IdentLoc, diag::ext_param_not_declared)
- << FTI.Params[i].Ident
- << FixItHint::CreateInsertion(LocAfterDecls, Code);
+ if (getLangOpts().C99) {
+ SmallString<256> Code;
+ llvm::raw_svector_ostream(Code)
+ << " int " << FTI.Params[i].Ident->getName() << ";\n";
+ Diag(FTI.Params[i].IdentLoc, diag::ext_param_not_declared)
+ << FTI.Params[i].Ident
+ << FixItHint::CreateInsertion(LocAfterDecls, Code);
+ }
// Implicitly declare the argument as type 'int' for lack of a better
// type.
@@ -14143,7 +14354,8 @@ void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D,
// Use the identifier location for the type source range.
DS.SetRangeStart(FTI.Params[i].IdentLoc);
DS.SetRangeEnd(FTI.Params[i].IdentLoc);
- Declarator ParamD(DS, DeclaratorContext::KNRTypeList);
+ Declarator ParamD(DS, ParsedAttributesView::none(),
+ DeclaratorContext::KNRTypeList);
ParamD.SetIdentifier(FTI.Params[i].Ident, FTI.Params[i].IdentLoc);
FTI.Params[i].Param = ActOnParamDeclarator(S, ParamD);
}
@@ -14154,7 +14366,7 @@ void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D,
Decl *
Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D,
MultiTemplateParamsArg TemplateParameterLists,
- SkipBodyInfo *SkipBody) {
+ SkipBodyInfo *SkipBody, FnBodyKind BodyKind) {
assert(getCurFunctionDecl() == nullptr && "Function parsing confused");
assert(D.isFunctionDeclarator() && "Not a function declarator!");
Scope *ParentScope = FnBodyScope->getParent();
@@ -14173,7 +14385,7 @@ Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D,
D.setFunctionDefinitionKind(FunctionDefinitionKind::Definition);
Decl *DP = HandleDeclarator(ParentScope, D, TemplateParameterLists);
- Decl *Dcl = ActOnStartOfFunctionDef(FnBodyScope, DP, SkipBody);
+ Decl *Dcl = ActOnStartOfFunctionDef(FnBodyScope, DP, SkipBody, BodyKind);
if (!Bases.empty())
ActOnFinishedFunctionDefinitionInOpenMPDeclareVariantScope(Dcl, Bases);
@@ -14196,9 +14408,6 @@ ShouldWarnAboutMissingPrototype(const FunctionDecl *FD,
if (!FD->isGlobal())
return false;
- if (!FD->isExternallyVisible())
- return false;
-
// Don't warn about C++ member functions.
if (isa<CXXMethodDecl>(FD))
return false;
@@ -14229,6 +14438,11 @@ ShouldWarnAboutMissingPrototype(const FunctionDecl *FD,
if (FD->isDeleted())
return false;
+ // Don't warn on implicitly local functions (such as having local-typed
+ // parameters).
+ if (!FD->isExternallyVisible())
+ return false;
+
for (const FunctionDecl *Prev = FD->getPreviousDecl();
Prev; Prev = Prev->getPreviousDecl()) {
// Ignore any declarations that occur in function or method
@@ -14347,7 +14561,8 @@ static void RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator,
}
Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
- SkipBodyInfo *SkipBody) {
+ SkipBodyInfo *SkipBody,
+ FnBodyKind BodyKind) {
if (!D) {
// Parsing the function declaration failed in some way. Push on a fake scope
// anyway so we can try to parse the function body.
@@ -14436,11 +14651,11 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
}
}
- // The return type of a function definition must be complete
- // (C99 6.9.1p3, C++ [dcl.fct]p6).
+ // The return type of a function definition must be complete (C99 6.9.1p3),
+ // unless the function is deleted (C++ specifc, C++ [dcl.fct.def.general]p2)
QualType ResultType = FD->getReturnType();
if (!ResultType->isDependentType() && !ResultType->isVoidType() &&
- !FD->isInvalidDecl() &&
+ !FD->isInvalidDecl() && BodyKind != FnBodyKind::Delete &&
RequireCompleteType(FD->getLocation(), ResultType,
diag::err_func_def_incomplete_result))
FD->setInvalidDecl();
@@ -14449,8 +14664,9 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
PushDeclContext(FnBodyScope, FD);
// Check the validity of our function parameters
- CheckParmsForFunctionDef(FD->parameters(),
- /*CheckParameterNames=*/true);
+ if (BodyKind != FnBodyKind::Delete)
+ CheckParmsForFunctionDef(FD->parameters(),
+ /*CheckParameterNames=*/true);
// Add non-parameter declarations already in the function to the current
// scope.
@@ -14660,18 +14876,20 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
if (getLangOpts().CPlusPlus14) {
if (!FD->isInvalidDecl() && Body && !FD->isDependentContext() &&
FD->getReturnType()->isUndeducedType()) {
- // If the function has a deduced result type but contains no 'return'
- // statements, the result type as written must be exactly 'auto', and
- // the deduced result type is 'void'.
+ // For a function with a deduced result type to return void,
+ // the result type as written must be 'auto' or 'decltype(auto)',
+ // possibly cv-qualified or constrained, but not ref-qualified.
if (!FD->getReturnType()->getAs<AutoType>()) {
Diag(dcl->getLocation(), diag::err_auto_fn_no_return_but_not_auto)
<< FD->getReturnType();
FD->setInvalidDecl();
} else {
- // Substitute 'void' for the 'auto' in the type.
- TypeLoc ResultType = getReturnTypeLoc(FD);
- Context.adjustDeducedFunctionResultType(
- FD, SubstAutoType(ResultType.getType(), Context.VoidTy));
+ // Falling off the end of the function is the same as 'return;'.
+ Expr *Dummy = nullptr;
+ if (DeduceFunctionTypeFromReturnExpr(
+ FD, dcl->getLocation(), Dummy,
+ FD->getReturnType()->getAs<AutoType>()))
+ FD->setInvalidDecl();
}
}
} else if (getLangOpts().CPlusPlus11 && isLambdaCallOperator(FD)) {
@@ -14796,18 +15014,56 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
? FixItHint::CreateInsertion(findBeginLoc(), "static ")
: FixItHint{});
}
+ }
- // GNU warning -Wstrict-prototypes
- // Warn if K&R function is defined without a previous declaration.
- // This warning is issued only if the definition itself does not
- // provide a prototype. Only K&R definitions do not provide a
- // prototype.
- if (!FD->hasWrittenPrototype()) {
- TypeSourceInfo *TI = FD->getTypeSourceInfo();
- TypeLoc TL = TI->getTypeLoc();
- FunctionTypeLoc FTL = TL.getAsAdjusted<FunctionTypeLoc>();
- Diag(FTL.getLParenLoc(), diag::warn_strict_prototypes) << 2;
- }
+ // If the function being defined does not have a prototype, then we may
+ // need to diagnose it as changing behavior in C2x because we now know
+ // whether the function accepts arguments or not. This only handles the
+ // case where the definition has no prototype but does have parameters
+ // and either there is no previous potential prototype, or the previous
+ // potential prototype also has no actual prototype. This handles cases
+ // like:
+ // void f(); void f(a) int a; {}
+ // void g(a) int a; {}
+ // See MergeFunctionDecl() for other cases of the behavior change
+ // diagnostic. See GetFullTypeForDeclarator() for handling of a function
+ // type without a prototype.
+ if (!FD->hasWrittenPrototype() && FD->getNumParams() != 0 &&
+ (!PossiblePrototype || (!PossiblePrototype->hasWrittenPrototype() &&
+ !PossiblePrototype->isImplicit()))) {
+ // The function definition has parameters, so this will change behavior
+ // in C2x. If there is a possible prototype, it comes before the
+ // function definition.
+ // FIXME: The declaration may have already been diagnosed as being
+ // deprecated in GetFullTypeForDeclarator() if it had no arguments, but
+ // there's no way to test for the "changes behavior" condition in
+ // SemaType.cpp when forming the declaration's function type. So, we do
+ // this awkward dance instead.
+ //
+ // If we have a possible prototype and it declares a function with a
+ // prototype, we don't want to diagnose it; if we have a possible
+ // prototype and it has no prototype, it may have already been
+ // diagnosed in SemaType.cpp as deprecated depending on whether
+ // -Wstrict-prototypes is enabled. If we already warned about it being
+ // deprecated, add a note that it also changes behavior. If we didn't
+ // warn about it being deprecated (because the diagnostic is not
+ // enabled), warn now that it is deprecated and changes behavior.
+
+ // This K&R C function definition definitely changes behavior in C2x,
+ // so diagnose it.
+ Diag(FD->getLocation(), diag::warn_non_prototype_changes_behavior)
+ << /*definition*/ 1 << /* not supported in C2x */ 0;
+
+ // If we have a possible prototype for the function which is a user-
+ // visible declaration, we already tested that it has no prototype.
+ // This will change behavior in C2x. This gets a warning rather than a
+ // note because it's the same behavior-changing problem as with the
+ // definition.
+ if (PossiblePrototype)
+ Diag(PossiblePrototype->getLocation(),
+ diag::warn_non_prototype_changes_behavior)
+ << /*declaration*/ 0 << /* conflicting */ 1 << /*subsequent*/ 1
+ << /*definition*/ 1;
}
// Warn on CPUDispatch with an actual body.
@@ -15028,6 +15284,10 @@ void Sema::ActOnFinishDelayedAttribute(Scope *S, Decl *D,
/// call, forming a call to an implicitly defined function (per C99 6.5.1p2).
NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
IdentifierInfo &II, Scope *S) {
+ // It is not valid to implicitly define a function in C2x.
+ assert(LangOpts.implicitFunctionsAllowed() &&
+ "Implicit function declarations aren't allowed in this language mode");
+
// Find the scope in which the identifier is injected and the corresponding
// DeclContext.
// FIXME: C89 does not say what happens if there is no enclosing block scope.
@@ -15066,15 +15326,13 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
}
}
- // Extension in C99. Legal in C90, but warn about it.
+ // Extension in C99 (defaults to error). Legal in C89, but warn about it.
unsigned diag_id;
if (II.getName().startswith("__builtin_"))
diag_id = diag::warn_builtin_unknown;
// OpenCL v2.0 s6.9.u - Implicit function declaration is not supported.
- else if (getLangOpts().OpenCL)
- diag_id = diag::err_opencl_implicit_function_decl;
else if (getLangOpts().C99)
- diag_id = diag::ext_implicit_function_decl;
+ diag_id = diag::ext_implicit_function_decl_c99;
else
diag_id = diag::warn_implicit_function_decl;
@@ -15092,9 +15350,16 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
}
Diag(Loc, diag_id) << &II;
- if (Corrected)
- diagnoseTypo(Corrected, PDiag(diag::note_function_suggestion),
- /*ErrorRecovery*/ false);
+ if (Corrected) {
+ // If the correction is going to suggest an implicitly defined function,
+ // skip the correction as not being a particularly good idea.
+ bool Diagnose = true;
+ if (const auto *D = Corrected.getCorrectionDecl())
+ Diagnose = !D->isImplicit();
+ if (Diagnose)
+ diagnoseTypo(Corrected, PDiag(diag::note_function_suggestion),
+ /*ErrorRecovery*/ false);
+ }
// If we found a prior declaration of this function, don't bother building
// another one. We've already pushed that one into scope, so there's nothing
@@ -15112,7 +15377,7 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
(void)Error; // Silence warning.
assert(!Error && "Error setting up implicit decl!");
SourceLocation NoLoc;
- Declarator D(DS, DeclaratorContext::Block);
+ Declarator D(DS, ParsedAttributesView::none(), DeclaratorContext::Block);
D.AddTypeInfo(DeclaratorChunk::getFunction(/*HasProto=*/false,
/*IsAmbiguous=*/false,
/*LParenLoc=*/NoLoc,
@@ -15197,7 +15462,7 @@ void Sema::AddKnownFunctionAttributesForReplaceableGlobalAllocationFunction(
// (3.1) If the allocation function takes an argument of type
// std​::​align_­val_­t, the storage will have the alignment
// specified by the value of this argument.
- if (AlignmentParam.hasValue() && !FD->hasAttr<AllocAlignAttr>()) {
+ if (AlignmentParam && !FD->hasAttr<AllocAlignAttr>()) {
FD->addAttr(AllocAlignAttr::CreateImplicit(
Context, ParamIdx(AlignmentParam.getValue(), FD), FD->getLocation()));
}
@@ -15315,28 +15580,32 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
// Add known guaranteed alignment for allocation functions.
switch (BuiltinID) {
+ case Builtin::BImemalign:
case Builtin::BIaligned_alloc:
if (!FD->hasAttr<AllocAlignAttr>())
FD->addAttr(AllocAlignAttr::CreateImplicit(Context, ParamIdx(1, FD),
FD->getLocation()));
- LLVM_FALLTHROUGH;
+ break;
+ default:
+ break;
+ }
+
+ // Add allocsize attribute for allocation functions.
+ switch (BuiltinID) {
case Builtin::BIcalloc:
- case Builtin::BImalloc:
+ FD->addAttr(AllocSizeAttr::CreateImplicit(
+ Context, ParamIdx(1, FD), ParamIdx(2, FD), FD->getLocation()));
+ break;
case Builtin::BImemalign:
+ case Builtin::BIaligned_alloc:
case Builtin::BIrealloc:
- case Builtin::BIstrdup:
- case Builtin::BIstrndup: {
- if (!FD->hasAttr<AssumeAlignedAttr>()) {
- unsigned NewAlign = Context.getTargetInfo().getNewAlign() /
- Context.getTargetInfo().getCharWidth();
- IntegerLiteral *Alignment = IntegerLiteral::Create(
- Context, Context.MakeIntValue(NewAlign, Context.UnsignedIntTy),
- Context.UnsignedIntTy, FD->getLocation());
- FD->addAttr(AssumeAlignedAttr::CreateImplicit(
- Context, Alignment, /*Offset=*/nullptr, FD->getLocation()));
- }
+ FD->addAttr(AllocSizeAttr::CreateImplicit(Context, ParamIdx(2, FD),
+ ParamIdx(), FD->getLocation()));
+ break;
+ case Builtin::BImalloc:
+ FD->addAttr(AllocSizeAttr::CreateImplicit(Context, ParamIdx(1, FD),
+ ParamIdx(), FD->getLocation()));
break;
- }
default:
break;
}
@@ -16036,9 +16305,20 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// with C structs, unions, and enums when looking for a matching
// tag declaration or definition. See the similar lookup tweak
// in Sema::LookupName; is there a better way to deal with this?
- while (isa<RecordDecl>(SearchDC) || isa<EnumDecl>(SearchDC))
+ while (isa<RecordDecl, EnumDecl, ObjCContainerDecl>(SearchDC))
+ SearchDC = SearchDC->getParent();
+ } else if (getLangOpts().CPlusPlus) {
+ // Inside ObjCContainer want to keep it as a lexical decl context but go
+ // past it (most often to TranslationUnit) to find the semantic decl
+ // context.
+ while (isa<ObjCContainerDecl>(SearchDC))
SearchDC = SearchDC->getParent();
}
+ } else if (getLangOpts().CPlusPlus) {
+ // Don't use ObjCContainerDecl as the semantic decl context for anonymous
+ // TagDecl the same way as we skip it for named TagDecl.
+ while (isa<ObjCContainerDecl>(SearchDC))
+ SearchDC = SearchDC->getParent();
}
if (Previous.isSingleResult() &&
@@ -16688,8 +16968,7 @@ void Sema::ActOnTagStartDefinition(Scope *S, Decl *TagD) {
AddPushedVisibilityAttribute(Tag);
}
-bool Sema::ActOnDuplicateDefinition(DeclSpec &DS, Decl *Prev,
- SkipBodyInfo &SkipBody) {
+bool Sema::ActOnDuplicateDefinition(Decl *Prev, SkipBodyInfo &SkipBody) {
if (!hasStructuralCompatLayout(Prev, SkipBody.New))
return false;
@@ -16698,14 +16977,10 @@ bool Sema::ActOnDuplicateDefinition(DeclSpec &DS, Decl *Prev,
return true;
}
-Decl *Sema::ActOnObjCContainerStartDefinition(Decl *IDecl) {
- assert(isa<ObjCContainerDecl>(IDecl) &&
- "ActOnObjCContainerStartDefinition - Not ObjCContainerDecl");
- DeclContext *OCD = cast<DeclContext>(IDecl);
- assert(OCD->getLexicalParent() == CurContext &&
+void Sema::ActOnObjCContainerStartDefinition(ObjCContainerDecl *IDecl) {
+ assert(IDecl->getLexicalParent() == CurContext &&
"The next DeclContext should be lexically contained in the current one.");
- CurContext = OCD;
- return IDecl;
+ CurContext = IDecl;
}
void Sema::ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagD,
@@ -16813,14 +17088,14 @@ void Sema::ActOnObjCContainerFinishDefinition() {
PopDeclContext();
}
-void Sema::ActOnObjCTemporaryExitContainerContext(DeclContext *DC) {
- assert(DC == CurContext && "Mismatch of container contexts");
- OriginalLexicalContext = DC;
+void Sema::ActOnObjCTemporaryExitContainerContext(ObjCContainerDecl *ObjCCtx) {
+ assert(ObjCCtx == CurContext && "Mismatch of container contexts");
+ OriginalLexicalContext = ObjCCtx;
ActOnObjCContainerFinishDefinition();
}
-void Sema::ActOnObjCReenterContainerContext(DeclContext *DC) {
- ActOnObjCContainerStartDefinition(cast<Decl>(DC));
+void Sema::ActOnObjCReenterContainerContext(ObjCContainerDecl *ObjCCtx) {
+ ActOnObjCContainerStartDefinition(ObjCCtx);
OriginalLexicalContext = nullptr;
}
@@ -16844,17 +17119,12 @@ void Sema::ActOnTagDefinitionError(Scope *S, Decl *TagD) {
// Note that FieldName may be null for anonymous bitfields.
ExprResult Sema::VerifyBitField(SourceLocation FieldLoc,
- IdentifierInfo *FieldName,
- QualType FieldTy, bool IsMsStruct,
- Expr *BitWidth, bool *ZeroWidth) {
+ IdentifierInfo *FieldName, QualType FieldTy,
+ bool IsMsStruct, Expr *BitWidth) {
assert(BitWidth);
if (BitWidth->containsErrors())
return ExprError();
- // Default to true; that shouldn't confuse checks for emptiness
- if (ZeroWidth)
- *ZeroWidth = true;
-
// C99 6.7.2.1p4 - verify the field type.
// C++ 9.6p3: A bit-field shall have integral or enumeration type.
if (!FieldTy->isDependentType() && !FieldTy->isIntegralOrEnumerationType()) {
@@ -16882,9 +17152,6 @@ ExprResult Sema::VerifyBitField(SourceLocation FieldLoc,
return ICE;
BitWidth = ICE.get();
- if (Value != 0 && ZeroWidth)
- *ZeroWidth = false;
-
// Zero-width bitfield is ok for anonymous field.
if (Value == 0 && FieldName)
return Diag(FieldLoc, diag::err_bitfield_has_zero_width) << FieldName;
@@ -17137,17 +17404,15 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
AbstractFieldType))
InvalidDecl = true;
- bool ZeroWidth = false;
if (InvalidDecl)
BitWidth = nullptr;
// If this is declared as a bit-field, check the bit-field.
if (BitWidth) {
- BitWidth = VerifyBitField(Loc, II, T, Record->isMsStruct(Context), BitWidth,
- &ZeroWidth).get();
+ BitWidth =
+ VerifyBitField(Loc, II, T, Record->isMsStruct(Context), BitWidth).get();
if (!BitWidth) {
InvalidDecl = true;
BitWidth = nullptr;
- ZeroWidth = false;
}
}
@@ -17469,6 +17734,75 @@ void Sema::ActOnLastBitfield(SourceLocation DeclLoc,
AllIvarDecls.push_back(Ivar);
}
+namespace {
+/// [class.dtor]p4:
+/// At the end of the definition of a class, overload resolution is
+/// performed among the prospective destructors declared in that class with
+/// an empty argument list to select the destructor for the class, also
+/// known as the selected destructor.
+///
+/// We do the overload resolution here, then mark the selected constructor in the AST.
+/// Later CXXRecordDecl::getDestructor() will return the selected constructor.
+void ComputeSelectedDestructor(Sema &S, CXXRecordDecl *Record) {
+ if (!Record->hasUserDeclaredDestructor()) {
+ return;
+ }
+
+ SourceLocation Loc = Record->getLocation();
+ OverloadCandidateSet OCS(Loc, OverloadCandidateSet::CSK_Normal);
+
+ for (auto *Decl : Record->decls()) {
+ if (auto *DD = dyn_cast<CXXDestructorDecl>(Decl)) {
+ if (DD->isInvalidDecl())
+ continue;
+ S.AddOverloadCandidate(DD, DeclAccessPair::make(DD, DD->getAccess()), {},
+ OCS);
+ assert(DD->isIneligibleOrNotSelected() && "Selecting a destructor but a destructor was already selected.");
+ }
+ }
+
+ if (OCS.empty()) {
+ return;
+ }
+ OverloadCandidateSet::iterator Best;
+ unsigned Msg = 0;
+ OverloadCandidateDisplayKind DisplayKind;
+
+ switch (OCS.BestViableFunction(S, Loc, Best)) {
+ case OR_Success:
+ case OR_Deleted:
+ Record->addedSelectedDestructor(dyn_cast<CXXDestructorDecl>(Best->Function));
+ break;
+
+ case OR_Ambiguous:
+ Msg = diag::err_ambiguous_destructor;
+ DisplayKind = OCD_AmbiguousCandidates;
+ break;
+
+ case OR_No_Viable_Function:
+ Msg = diag::err_no_viable_destructor;
+ DisplayKind = OCD_AllCandidates;
+ break;
+ }
+
+ if (Msg) {
+ // OpenCL have got their own thing going with destructors. It's slightly broken,
+ // but we allow it.
+ if (!S.LangOpts.OpenCL) {
+ PartialDiagnostic Diag = S.PDiag(Msg) << Record;
+ OCS.NoteCandidates(PartialDiagnosticAt(Loc, Diag), S, DisplayKind, {});
+ Record->setInvalidDecl();
+ }
+ // It's a bit hacky: At this point we've raised an error but we want the
+ // rest of the compiler to continue somehow working. However almost
+ // everything we'll try to do with the class will depend on there being a
+ // destructor. So let's pretend the first one is selected and hope for the
+ // best.
+ Record->addedSelectedDestructor(dyn_cast<CXXDestructorDecl>(OCS.begin()->Function));
+ }
+}
+} // namespace
+
void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
ArrayRef<Decl *> Fields, SourceLocation LBrac,
SourceLocation RBrac,
@@ -17495,6 +17829,9 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
RecordDecl *Record = dyn_cast<RecordDecl>(EnclosingDecl);
CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(EnclosingDecl);
+ if (CXXRecord && !CXXRecord->isDependentType())
+ ComputeSelectedDestructor(*this, CXXRecord);
+
// Start counting up the number of named members; make sure to include
// members of anonymous structs and unions in the total.
unsigned NumNamedMembers = 0;
@@ -17789,6 +18126,33 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
// Handle attributes before checking the layout.
ProcessDeclAttributeList(S, Record, Attrs);
+ // Check to see if a FieldDecl is a pointer to a function.
+ auto IsFunctionPointer = [&](const Decl *D) {
+ const FieldDecl *FD = dyn_cast<FieldDecl>(D);
+ if (!FD)
+ return false;
+ QualType FieldType = FD->getType().getDesugaredType(Context);
+ if (isa<PointerType>(FieldType)) {
+ QualType PointeeType = cast<PointerType>(FieldType)->getPointeeType();
+ return PointeeType.getDesugaredType(Context)->isFunctionType();
+ }
+ return false;
+ };
+
+ // Maybe randomize the record's decls. We automatically randomize a record
+ // of function pointers, unless it has the "no_randomize_layout" attribute.
+ if (!getLangOpts().CPlusPlus &&
+ (Record->hasAttr<RandomizeLayoutAttr>() ||
+ (!Record->hasAttr<NoRandomizeLayoutAttr>() &&
+ llvm::all_of(Record->decls(), IsFunctionPointer))) &&
+ !Record->isUnion() && !getLangOpts().RandstructSeed.empty() &&
+ !Record->isRandomized()) {
+ SmallVector<Decl *, 32> NewDeclOrdering;
+ if (randstruct::randomizeStructureLayout(Context, Record,
+ NewDeclOrdering))
+ Record->reorderDecls(NewDeclOrdering);
+ }
+
// We may have deferred checking for a deleted destructor. Check now.
if (CXXRecord) {
auto *Dtor = CXXRecord->getDestructor();
@@ -18407,7 +18771,7 @@ bool Sema::IsValueInFlagEnum(const EnumDecl *ED, const llvm::APInt &Val,
const auto &EVal = E->getInitVal();
// Only single-bit enumerators introduce new flag values.
if (EVal.isPowerOf2())
- FlagBits = FlagBits.zextOrSelf(EVal.getBitWidth()) | EVal;
+ FlagBits = FlagBits.zext(EVal.getBitWidth()) | EVal;
}
}
@@ -18456,9 +18820,6 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange,
unsigned NumNegativeBits = 0;
unsigned NumPositiveBits = 0;
- // Keep track of whether all elements have type int.
- bool AllElementsInt = true;
-
for (unsigned i = 0, e = Elements.size(); i != e; ++i) {
EnumConstantDecl *ECD =
cast_or_null<EnumConstantDecl>(Elements[i]);
@@ -18473,10 +18834,6 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange,
else
NumNegativeBits = std::max(NumNegativeBits,
(unsigned)InitVal.getMinSignedBits());
-
- // Keep track of whether every enum element has type int (very common).
- if (AllElementsInt)
- AllElementsInt = ECD->getType() == Context.IntTy;
}
// Figure out the type that should be used for this enum.
@@ -18704,9 +19061,7 @@ void Sema::ActOnPragmaWeakID(IdentifierInfo* Name,
if (PrevDecl) {
PrevDecl->addAttr(WeakAttr::CreateImplicit(Context, PragmaLoc, AttributeCommonInfo::AS_Pragma));
} else {
- (void)WeakUndeclaredIdentifiers.insert(
- std::pair<IdentifierInfo*,WeakInfo>
- (Name, WeakInfo((IdentifierInfo*)nullptr, NameLoc)));
+ (void)WeakUndeclaredIdentifiers[Name].insert(WeakInfo(nullptr, NameLoc));
}
}
@@ -18724,12 +19079,11 @@ void Sema::ActOnPragmaWeakAlias(IdentifierInfo* Name,
if (NamedDecl *ND = dyn_cast<NamedDecl>(PrevDecl))
DeclApplyPragmaWeak(TUScope, ND, W);
} else {
- (void)WeakUndeclaredIdentifiers.insert(
- std::pair<IdentifierInfo*,WeakInfo>(AliasName, W));
+ (void)WeakUndeclaredIdentifiers[AliasName].insert(W);
}
}
-Decl *Sema::getObjCDeclContext() const {
+ObjCContainerDecl *Sema::getObjCDeclContext() const {
return (dyn_cast_or_null<ObjCContainerDecl>(CurContext));
}
@@ -18766,12 +19120,12 @@ Sema::FunctionEmissionStatus Sema::getEmissionStatus(FunctionDecl *FD,
// #pragma omp declare target to(*) device_type(*).
// Therefore DevTy having no value does not imply host. The emission status
// will be checked again at the end of compilation unit with Final = true.
- if (DevTy.hasValue())
+ if (DevTy)
if (*DevTy == OMPDeclareTargetDeclAttr::DT_Host)
return FunctionEmissionStatus::OMPDiscarded;
// If we have an explicit value for the device type, or we are in a target
// declare context, we need to emit all extern and used symbols.
- if (isInOpenMPDeclareTargetContext() || DevTy.hasValue())
+ if (isInOpenMPDeclareTargetContext() || DevTy)
if (IsEmittedForExternalSymbol())
return FunctionEmissionStatus::Emitted;
// Device mode only emits what it must, if it wasn't tagged yet and needed,
@@ -18784,7 +19138,7 @@ Sema::FunctionEmissionStatus Sema::getEmissionStatus(FunctionDecl *FD,
// be ommitted.
Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
OMPDeclareTargetDeclAttr::getDeviceType(FD->getCanonicalDecl());
- if (DevTy.hasValue())
+ if (DevTy)
if (*DevTy == OMPDeclareTargetDeclAttr::DT_NoHost)
return FunctionEmissionStatus::OMPDiscarded;
}
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index e76e7c608e0c..f79523983ed8 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -24,6 +24,7 @@
#include "clang/AST/Type.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/DarwinSDKInfo.h"
+#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetBuiltins.h"
@@ -334,6 +335,26 @@ static bool checkFunctionOrMethodParameterIndex(
return true;
}
+/// Check if the argument \p E is a ASCII string literal. If not emit an error
+/// and return false, otherwise set \p Str to the value of the string literal
+/// and return true.
+bool Sema::checkStringLiteralArgumentAttr(const AttributeCommonInfo &CI,
+ const Expr *E, StringRef &Str,
+ SourceLocation *ArgLocation) {
+ const auto *Literal = dyn_cast<StringLiteral>(E->IgnoreParenCasts());
+ if (ArgLocation)
+ *ArgLocation = E->getBeginLoc();
+
+ if (!Literal || !Literal->isOrdinary()) {
+ Diag(E->getBeginLoc(), diag::err_attribute_argument_type)
+ << CI << AANT_ArgumentString;
+ return false;
+ }
+
+ Str = Literal->getString();
+ return true;
+}
+
/// Check if the argument \p ArgNum of \p Attr is a ASCII string literal.
/// If not emit an error and return false. If the argument is an identifier it
/// will emit an error with a fixit hint and treat it as if it was a string
@@ -356,18 +377,7 @@ bool Sema::checkStringLiteralArgumentAttr(const ParsedAttr &AL, unsigned ArgNum,
// Now check for an actual string literal.
Expr *ArgExpr = AL.getArgAsExpr(ArgNum);
- const auto *Literal = dyn_cast<StringLiteral>(ArgExpr->IgnoreParenCasts());
- if (ArgLocation)
- *ArgLocation = ArgExpr->getBeginLoc();
-
- if (!Literal || !Literal->isAscii()) {
- Diag(ArgExpr->getBeginLoc(), diag::err_attribute_argument_type)
- << AL << AANT_ArgumentString;
- return false;
- }
-
- Str = Literal->getString();
- return true;
+ return checkStringLiteralArgumentAttr(AL, ArgExpr, Str, ArgLocation);
}
/// Applies the given attribute to the Decl without performing any
@@ -610,7 +620,7 @@ static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D,
if (const auto *StrLit = dyn_cast<StringLiteral>(ArgExp)) {
if (StrLit->getLength() == 0 ||
- (StrLit->isAscii() && StrLit->getString() == StringRef("*"))) {
+ (StrLit->isOrdinary() && StrLit->getString() == StringRef("*"))) {
// Pass empty strings to the analyzer without warnings.
// Treat "*" as the universal lock.
Args.push_back(ArgExp);
@@ -1394,9 +1404,9 @@ static void handlePackedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
FD->isBitField() &&
S.Context.getTypeAlign(FD->getType()) <= 8);
- if (S.getASTContext().getTargetInfo().getTriple().isPS4()) {
+ if (S.getASTContext().getTargetInfo().getTriple().isPS()) {
if (BitfieldByteAligned)
- // The PS4 target needs to maintain ABI backwards compatibility.
+ // The PS4/PS5 targets need to maintain ABI backwards compatibility.
S.Diag(AL.getLoc(), diag::warn_attribute_ignored_for_field_of_type)
<< AL << FD->getType();
else
@@ -2149,6 +2159,14 @@ static void handleNakedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
<< AL << Triple.getArchName();
return;
}
+
+ // This form is not allowed to be written on a member function (static or
+ // nonstatic) when in Microsoft compatibility mode.
+ if (S.getLangOpts().MSVCCompat && isa<CXXMethodDecl>(D)) {
+ S.Diag(AL.getLoc(), diag::err_attribute_wrong_decl_type_str)
+ << AL << "non-member functions";
+ return;
+ }
}
D->addAttr(::new (S.Context) NakedAttr(S.Context, AL));
@@ -2166,6 +2184,21 @@ static void handleNoReturnAttr(Sema &S, Decl *D, const ParsedAttr &Attrs) {
D->addAttr(::new (S.Context) NoReturnAttr(S.Context, Attrs));
}
+static void handleStandardNoReturnAttr(Sema &S, Decl *D, const ParsedAttr &A) {
+ // The [[_Noreturn]] spelling is deprecated in C2x, so if that was used,
+ // issue an appropriate diagnostic. However, don't issue a diagnostic if the
+ // attribute name comes from a macro expansion. We don't want to punish users
+ // who write [[noreturn]] after including <stdnoreturn.h> (where 'noreturn'
+ // is defined as a macro which expands to '_Noreturn').
+ if (!S.getLangOpts().CPlusPlus &&
+ A.getSemanticSpelling() == CXX11NoReturnAttr::C2x_Noreturn &&
+ !(A.getLoc().isMacroID() &&
+ S.getSourceManager().isInSystemMacro(A.getLoc())))
+ S.Diag(A.getLoc(), diag::warn_deprecated_noreturn_spelling) << A.getRange();
+
+ D->addAttr(::new (S.Context) CXX11NoReturnAttr(S.Context, A));
+}
+
static void handleNoCfCheckAttr(Sema &S, Decl *D, const ParsedAttr &Attrs) {
if (!S.getLangOpts().CFProtectionBranch)
S.Diag(Attrs.getLoc(), diag::warn_nocf_check_attribute_ignored);
@@ -2647,8 +2680,8 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
auto Major = Version.getMajor();
auto NewMajor = Major >= 9 ? Major - 7 : 0;
if (NewMajor >= 2) {
- if (Version.getMinor().hasValue()) {
- if (Version.getSubminor().hasValue())
+ if (Version.getMinor()) {
+ if (Version.getSubminor())
return VersionTuple(NewMajor, Version.getMinor().getValue(),
Version.getSubminor().getValue());
else
@@ -2696,7 +2729,7 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (IOSToTvOSMapping) {
if (auto MappedVersion =
IOSToTvOSMapping->map(Version, VersionTuple(0, 0), None)) {
- return MappedVersion.getValue();
+ return *MappedVersion;
}
}
return Version;
@@ -3123,6 +3156,14 @@ static void handleWarnUnusedResult(Sema &S, Decl *D, const ParsedAttr &AL) {
S.Diag(AL.getLoc(), diag::ext_cxx17_attr) << AL;
}
+ if ((!AL.isGNUAttribute() &&
+ !(AL.isStandardAttributeSyntax() && AL.isClangScope())) &&
+ isa<TypedefNameDecl>(D)) {
+ S.Diag(AL.getLoc(), diag::warn_unused_result_typedef_unsupported_spelling)
+ << AL.isGNUScope();
+ return;
+ }
+
D->addAttr(::new (S.Context) WarnUnusedResultAttr(S.Context, AL, Str));
}
@@ -3457,7 +3498,7 @@ bool Sema::checkTargetClonesAttrString(SourceLocation LiteralLoc, StringRef Str,
return Diag(CurLoc, diag::warn_unsupported_target_attribute)
<< Unsupported << None << Cur << TargetClones;
- if (llvm::find(Strings, Cur) != Strings.end() || DefaultIsDupe)
+ if (llvm::is_contained(Strings, Cur) || DefaultIsDupe)
Diag(CurLoc, diag::warn_target_clone_duplicate_options);
// Note: Add even if there are duplicates, since it changes name mangling.
Strings.push_back(Cur);
@@ -3628,8 +3669,7 @@ static void handleFormatArgAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
(!Ty->isPointerType() ||
!Ty->castAs<PointerType>()->getPointeeType()->isCharType())) {
S.Diag(AL.getLoc(), diag::err_format_attribute_not)
- << "a string type" << IdxExpr->getSourceRange()
- << getFunctionOrMethodParamRange(D, 0);
+ << IdxExpr->getSourceRange() << getFunctionOrMethodParamRange(D, 0);
return;
}
Ty = getFunctionOrMethodResultType(D);
@@ -3829,27 +3869,12 @@ static void handleFormatAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
// make sure the format string is really a string
QualType Ty = getFunctionOrMethodParamType(D, ArgIdx);
- if (Kind == CFStringFormat) {
- if (!isCFStringType(Ty, S.Context)) {
- S.Diag(AL.getLoc(), diag::err_format_attribute_not)
- << "a CFString" << IdxExpr->getSourceRange()
- << getFunctionOrMethodParamRange(D, ArgIdx);
- return;
- }
- } else if (Kind == NSStringFormat) {
- // FIXME: do we need to check if the type is NSString*? What are the
- // semantics?
- if (!isNSStringType(Ty, S.Context, /*AllowNSAttributedString=*/true)) {
- S.Diag(AL.getLoc(), diag::err_format_attribute_not)
- << "an NSString" << IdxExpr->getSourceRange()
- << getFunctionOrMethodParamRange(D, ArgIdx);
- return;
- }
- } else if (!Ty->isPointerType() ||
- !Ty->castAs<PointerType>()->getPointeeType()->isCharType()) {
+ if (!isNSStringType(Ty, S.Context, true) &&
+ !isCFStringType(Ty, S.Context) &&
+ (!Ty->isPointerType() ||
+ !Ty->castAs<PointerType>()->getPointeeType()->isCharType())) {
S.Diag(AL.getLoc(), diag::err_format_attribute_not)
- << "a string type" << IdxExpr->getSourceRange()
- << getFunctionOrMethodParamRange(D, ArgIdx);
+ << IdxExpr->getSourceRange() << getFunctionOrMethodParamRange(D, ArgIdx);
return;
}
@@ -4122,48 +4147,10 @@ static void handleTransparentUnionAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
void Sema::AddAnnotationAttr(Decl *D, const AttributeCommonInfo &CI,
StringRef Str, MutableArrayRef<Expr *> Args) {
auto *Attr = AnnotateAttr::Create(Context, Str, Args.data(), Args.size(), CI);
- llvm::SmallVector<PartialDiagnosticAt, 8> Notes;
- for (unsigned Idx = 0; Idx < Attr->args_size(); Idx++) {
- Expr *&E = Attr->args_begin()[Idx];
- assert(E && "error are handled before");
- if (E->isValueDependent() || E->isTypeDependent())
- continue;
-
- if (E->getType()->isArrayType())
- E = ImpCastExprToType(E, Context.getPointerType(E->getType()),
- clang::CK_ArrayToPointerDecay)
- .get();
- if (E->getType()->isFunctionType())
- E = ImplicitCastExpr::Create(Context,
- Context.getPointerType(E->getType()),
- clang::CK_FunctionToPointerDecay, E, nullptr,
- VK_PRValue, FPOptionsOverride());
- if (E->isLValue())
- E = ImplicitCastExpr::Create(Context, E->getType().getNonReferenceType(),
- clang::CK_LValueToRValue, E, nullptr,
- VK_PRValue, FPOptionsOverride());
-
- Expr::EvalResult Eval;
- Notes.clear();
- Eval.Diag = &Notes;
-
- bool Result =
- E->EvaluateAsConstantExpr(Eval, Context);
-
- /// Result means the expression can be folded to a constant.
- /// Note.empty() means the expression is a valid constant expression in the
- /// current language mode.
- if (!Result || !Notes.empty()) {
- Diag(E->getBeginLoc(), diag::err_attribute_argument_n_type)
- << CI << (Idx + 1) << AANT_ArgumentConstantExpr;
- for (auto &Note : Notes)
- Diag(Note.first, Note.second);
- return;
- }
- assert(Eval.Val.hasValue());
- E = ConstantExpr::Create(Context, E, Eval.Val);
+ if (ConstantFoldAttrArgs(
+ CI, MutableArrayRef<Expr *>(Attr->args_begin(), Attr->args_end()))) {
+ D->addAttr(Attr);
}
- D->addAttr(Attr);
}
static void handleAnnotateAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -4266,6 +4253,9 @@ void Sema::AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E,
// declared with the register storage class specifier. An
// alignment-specifier may also be applied to the declaration of a class
// or enumeration type.
+ // CWG 2354:
+ // CWG agreed to remove permission for alignas to be applied to
+ // enumerations.
// C11 6.7.5/2:
// An alignment attribute shall not be specified in a declaration of
// a typedef, or a bit-field, or a function, or a parameter, or an
@@ -4281,6 +4271,9 @@ void Sema::AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E,
} else if (const auto *FD = dyn_cast<FieldDecl>(D)) {
if (FD->isBitField())
DiagKind = 3;
+ } else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
+ if (ED->getLangOpts().CPlusPlus)
+ DiagKind = 4;
} else if (!isa<TagDecl>(D)) {
Diag(AttrLoc, diag::err_attribute_wrong_decl_type) << &TmpAttr
<< (TmpAttr.isC11() ? ExpectedVariableOrField
@@ -4985,6 +4978,12 @@ static void handleCallConvAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
case ParsedAttr::AT_AArch64VectorPcs:
D->addAttr(::new (S.Context) AArch64VectorPcsAttr(S.Context, AL));
return;
+ case ParsedAttr::AT_AArch64SVEPcs:
+ D->addAttr(::new (S.Context) AArch64SVEPcsAttr(S.Context, AL));
+ return;
+ case ParsedAttr::AT_AMDGPUKernelCall:
+ D->addAttr(::new (S.Context) AMDGPUKernelCallAttr(S.Context, AL));
+ return;
case ParsedAttr::AT_IntelOclBicc:
D->addAttr(::new (S.Context) IntelOclBiccAttr(S.Context, AL));
return;
@@ -5082,6 +5081,21 @@ static void handleLifetimeCategoryAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
}
+static void handleRandomizeLayoutAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ if (checkAttrMutualExclusion<NoRandomizeLayoutAttr>(S, D, AL))
+ return;
+ if (!D->hasAttr<RandomizeLayoutAttr>())
+ D->addAttr(::new (S.Context) RandomizeLayoutAttr(S.Context, AL));
+}
+
+static void handleNoRandomizeLayoutAttr(Sema &S, Decl *D,
+ const ParsedAttr &AL) {
+ if (checkAttrMutualExclusion<RandomizeLayoutAttr>(S, D, AL))
+ return;
+ if (!D->hasAttr<NoRandomizeLayoutAttr>())
+ D->addAttr(::new (S.Context) NoRandomizeLayoutAttr(S.Context, AL));
+}
+
bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC,
const FunctionDecl *FD) {
if (Attrs.isInvalid())
@@ -5127,6 +5141,12 @@ bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC,
case ParsedAttr::AT_AArch64VectorPcs:
CC = CC_AArch64VectorCall;
break;
+ case ParsedAttr::AT_AArch64SVEPcs:
+ CC = CC_AArch64SVEPCS;
+ break;
+ case ParsedAttr::AT_AMDGPUKernelCall:
+ CC = CC_AMDGPUKernelCall;
+ break;
case ParsedAttr::AT_RegCall:
CC = CC_X86RegCall;
break;
@@ -5609,11 +5629,12 @@ static void handleBuiltinAliasAttr(Sema &S, Decl *D,
bool IsAArch64 = S.Context.getTargetInfo().getTriple().isAArch64();
bool IsARM = S.Context.getTargetInfo().getTriple().isARM();
bool IsRISCV = S.Context.getTargetInfo().getTriple().isRISCV();
+ bool IsHLSL = S.Context.getLangOpts().HLSL;
if ((IsAArch64 && !ArmSveAliasValid(S.Context, BuiltinID, AliasName)) ||
(IsARM && !ArmMveAliasValid(BuiltinID, AliasName) &&
!ArmCdeAliasValid(BuiltinID, AliasName)) ||
(IsRISCV && !RISCVAliasValid(BuiltinID, AliasName)) ||
- (!IsAArch64 && !IsARM && !IsRISCV)) {
+ (!IsAArch64 && !IsARM && !IsRISCV && !IsHLSL)) {
S.Diag(AL.getLoc(), diag::err_attribute_builtin_alias) << AL;
return;
}
@@ -6798,6 +6819,127 @@ static void handleUuidAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
D->addAttr(UA);
}
+static void handleHLSLNumThreadsAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ using llvm::Triple;
+ Triple Target = S.Context.getTargetInfo().getTriple();
+ if (!llvm::is_contained({Triple::Compute, Triple::Mesh, Triple::Amplification,
+ Triple::Library},
+ Target.getEnvironment())) {
+ uint32_t Pipeline =
+ (uint32_t)S.Context.getTargetInfo().getTriple().getEnvironment() -
+ (uint32_t)llvm::Triple::Pixel;
+ S.Diag(AL.getLoc(), diag::err_hlsl_attr_unsupported_in_stage)
+ << AL << Pipeline << "Compute, Amplification, Mesh or Library";
+ return;
+ }
+
+ llvm::VersionTuple SMVersion = Target.getOSVersion();
+ uint32_t ZMax = 1024;
+ uint32_t ThreadMax = 1024;
+ if (SMVersion.getMajor() <= 4) {
+ ZMax = 1;
+ ThreadMax = 768;
+ } else if (SMVersion.getMajor() == 5) {
+ ZMax = 64;
+ ThreadMax = 1024;
+ }
+
+ uint32_t X;
+ if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(0), X))
+ return;
+ if (X > 1024) {
+ S.Diag(AL.getArgAsExpr(0)->getExprLoc(),
+ diag::err_hlsl_numthreads_argument_oor) << 0 << 1024;
+ return;
+ }
+ uint32_t Y;
+ if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(1), Y))
+ return;
+ if (Y > 1024) {
+ S.Diag(AL.getArgAsExpr(1)->getExprLoc(),
+ diag::err_hlsl_numthreads_argument_oor) << 1 << 1024;
+ return;
+ }
+ uint32_t Z;
+ if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(2), Z))
+ return;
+ if (Z > ZMax) {
+ S.Diag(AL.getArgAsExpr(2)->getExprLoc(),
+ diag::err_hlsl_numthreads_argument_oor) << 2 << ZMax;
+ return;
+ }
+
+ if (X * Y * Z > ThreadMax) {
+ S.Diag(AL.getLoc(), diag::err_hlsl_numthreads_invalid) << ThreadMax;
+ return;
+ }
+
+ HLSLNumThreadsAttr *NewAttr = S.mergeHLSLNumThreadsAttr(D, AL, X, Y, Z);
+ if (NewAttr)
+ D->addAttr(NewAttr);
+}
+
+HLSLNumThreadsAttr *Sema::mergeHLSLNumThreadsAttr(Decl *D,
+ const AttributeCommonInfo &AL,
+ int X, int Y, int Z) {
+ if (HLSLNumThreadsAttr *NT = D->getAttr<HLSLNumThreadsAttr>()) {
+ if (NT->getX() != X || NT->getY() != Y || NT->getZ() != Z) {
+ Diag(NT->getLocation(), diag::err_hlsl_attribute_param_mismatch) << AL;
+ Diag(AL.getLoc(), diag::note_conflicting_attribute);
+ }
+ return nullptr;
+ }
+ return ::new (Context) HLSLNumThreadsAttr(Context, AL, X, Y, Z);
+}
+
+static void handleHLSLSVGroupIndexAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ using llvm::Triple;
+ Triple Target = S.Context.getTargetInfo().getTriple();
+ if (Target.getEnvironment() != Triple::Compute) {
+ uint32_t Pipeline =
+ (uint32_t)S.Context.getTargetInfo().getTriple().getEnvironment() -
+ (uint32_t)llvm::Triple::Pixel;
+ S.Diag(AL.getLoc(), diag::err_hlsl_attr_unsupported_in_stage)
+ << AL << Pipeline << "Compute";
+ return;
+ }
+
+ D->addAttr(::new (S.Context) HLSLSV_GroupIndexAttr(S.Context, AL));
+}
+
+static void handleHLSLShaderAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ StringRef Str;
+ SourceLocation ArgLoc;
+ if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
+ return;
+
+ HLSLShaderAttr::ShaderType ShaderType;
+ if (!HLSLShaderAttr::ConvertStrToShaderType(Str, ShaderType)) {
+ S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported)
+ << AL << Str << ArgLoc;
+ return;
+ }
+
+ // FIXME: check function match the shader stage.
+
+ HLSLShaderAttr *NewAttr = S.mergeHLSLShaderAttr(D, AL, ShaderType);
+ if (NewAttr)
+ D->addAttr(NewAttr);
+}
+
+HLSLShaderAttr *
+Sema::mergeHLSLShaderAttr(Decl *D, const AttributeCommonInfo &AL,
+ HLSLShaderAttr::ShaderType ShaderType) {
+ if (HLSLShaderAttr *NT = D->getAttr<HLSLShaderAttr>()) {
+ if (NT->getType() != ShaderType) {
+ Diag(NT->getLocation(), diag::err_hlsl_attribute_param_mismatch) << AL;
+ Diag(AL.getLoc(), diag::note_conflicting_attribute);
+ }
+ return nullptr;
+ }
+ return HLSLShaderAttr::Create(Context, ShaderType, AL);
+}
+
static void handleMSInheritanceAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!S.LangOpts.CPlusPlus) {
S.Diag(AL.getLoc(), diag::err_attribute_not_supported_in_lang)
@@ -7718,6 +7860,11 @@ static bool isGlobalVar(const Decl *D) {
return false;
}
+static bool isSanitizerAttributeAllowedOnGlobals(StringRef Sanitizer) {
+ return Sanitizer == "address" || Sanitizer == "hwaddress" ||
+ Sanitizer == "memtag";
+}
+
static void handleNoSanitizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!AL.checkAtLeastNumArgs(S, 1))
return;
@@ -7735,7 +7882,7 @@ static void handleNoSanitizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
SanitizerMask() &&
SanitizerName != "coverage")
S.Diag(LiteralLoc, diag::warn_unknown_sanitizer_ignored) << SanitizerName;
- else if (isGlobalVar(D) && SanitizerName != "address")
+ else if (isGlobalVar(D) && !isSanitizerAttributeAllowedOnGlobals(SanitizerName))
S.Diag(D->getLocation(), diag::err_attribute_wrong_decl_type)
<< AL << ExpectedFunctionOrMethod;
Sanitizers.push_back(SanitizerName);
@@ -7837,6 +7984,24 @@ static void handleOpenCLAccessAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
D->addAttr(::new (S.Context) OpenCLAccessAttr(S.Context, AL));
}
+static void handleZeroCallUsedRegsAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ // Check that the argument is a string literal.
+ StringRef KindStr;
+ SourceLocation LiteralLoc;
+ if (!S.checkStringLiteralArgumentAttr(AL, 0, KindStr, &LiteralLoc))
+ return;
+
+ ZeroCallUsedRegsAttr::ZeroCallUsedRegsKind Kind;
+ if (!ZeroCallUsedRegsAttr::ConvertStrToZeroCallUsedRegsKind(KindStr, Kind)) {
+ S.Diag(LiteralLoc, diag::warn_attribute_type_not_supported)
+ << AL << KindStr;
+ return;
+ }
+
+ D->dropAttr<ZeroCallUsedRegsAttr>();
+ D->addAttr(ZeroCallUsedRegsAttr::Create(S.Context, Kind, AL));
+}
+
static void handleSYCLKernelAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
// The 'sycl_kernel' attribute applies only to function templates.
const auto *FD = cast<FunctionDecl>(D);
@@ -8123,18 +8288,55 @@ EnforceTCBLeafAttr *Sema::mergeEnforceTCBLeafAttr(
// Top Level Sema Entry Points
//===----------------------------------------------------------------------===//
+// Returns true if the attribute must delay setting its arguments until after
+// template instantiation, and false otherwise.
+static bool MustDelayAttributeArguments(const ParsedAttr &AL) {
+ // Only attributes that accept expression parameter packs can delay arguments.
+ if (!AL.acceptsExprPack())
+ return false;
+
+ bool AttrHasVariadicArg = AL.hasVariadicArg();
+ unsigned AttrNumArgs = AL.getNumArgMembers();
+ for (size_t I = 0; I < std::min(AL.getNumArgs(), AttrNumArgs); ++I) {
+ bool IsLastAttrArg = I == (AttrNumArgs - 1);
+ // If the argument is the last argument and it is variadic it can contain
+ // any expression.
+ if (IsLastAttrArg && AttrHasVariadicArg)
+ return false;
+ Expr *E = AL.getArgAsExpr(I);
+ bool ArgMemberCanHoldExpr = AL.isParamExpr(I);
+ // If the expression is a pack expansion then arguments must be delayed
+ // unless the argument is an expression and it is the last argument of the
+ // attribute.
+ if (isa<PackExpansionExpr>(E))
+ return !(IsLastAttrArg && ArgMemberCanHoldExpr);
+ // Last case is if the expression is value dependent then it must delay
+ // arguments unless the corresponding argument is able to hold the
+ // expression.
+ if (E->isValueDependent() && !ArgMemberCanHoldExpr)
+ return true;
+ }
+ return false;
+}
+
/// ProcessDeclAttribute - Apply the specific attribute to the specified decl if
/// the attribute applies to decls. If the attribute is a type attribute, just
/// silently ignore it if a GNU attribute.
-static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
- const ParsedAttr &AL,
- bool IncludeCXX11Attributes) {
+static void
+ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
+ const Sema::ProcessDeclAttributeOptions &Options) {
if (AL.isInvalid() || AL.getKind() == ParsedAttr::IgnoredAttribute)
return;
// Ignore C++11 attributes on declarator chunks: they appertain to the type
// instead.
- if (AL.isCXX11Attribute() && !IncludeCXX11Attributes)
+ // FIXME: We currently check the attribute syntax directly instead of using
+ // isCXX11Attribute(), which currently erroneously classifies the C11
+ // `_Alignas` attribute as a C++11 attribute. `_Alignas` can appear on the
+ // `DeclSpec`, so we need to let it through here to make sure it is processed
+ // appropriately. Once the behavior of isCXX11Attribute() is fixed, we can
+ // go back to using that here.
+ if (AL.getSyntax() == ParsedAttr::AS_CXX11 && !Options.IncludeCXX11Attributes)
return;
// Unknown attributes are automatically warned on. Target-specific attributes
@@ -8150,22 +8352,93 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
return;
}
- if (S.checkCommonAttributeFeatures(D, AL))
+ // Check if argument population must delayed to after template instantiation.
+ bool MustDelayArgs = MustDelayAttributeArguments(AL);
+
+ // Argument number check must be skipped if arguments are delayed.
+ if (S.checkCommonAttributeFeatures(D, AL, MustDelayArgs))
+ return;
+
+ if (MustDelayArgs) {
+ AL.handleAttrWithDelayedArgs(S, D);
return;
+ }
switch (AL.getKind()) {
default:
if (AL.getInfo().handleDeclAttribute(S, D, AL) != ParsedAttrInfo::NotHandled)
break;
if (!AL.isStmtAttr()) {
- // Type attributes are handled elsewhere; silently move on.
assert(AL.isTypeAttr() && "Non-type attribute not handled");
- break;
+ }
+ if (AL.isTypeAttr()) {
+ if (Options.IgnoreTypeAttributes)
+ break;
+ if (!AL.isStandardAttributeSyntax()) {
+ // Non-[[]] type attributes are handled in processTypeAttrs(); silently
+ // move on.
+ break;
+ }
+
+ // According to the C and C++ standards, we should never see a
+ // [[]] type attribute on a declaration. However, we have in the past
+ // allowed some type attributes to "slide" to the `DeclSpec`, so we need
+ // to continue to support this legacy behavior. We only do this, however,
+ // if
+ // - we actually have a `DeclSpec`, i.e. if we're looking at a
+ // `DeclaratorDecl`, or
+ // - we are looking at an alias-declaration, where historically we have
+ // allowed type attributes after the identifier to slide to the type.
+ if (AL.slidesFromDeclToDeclSpecLegacyBehavior() &&
+ isa<DeclaratorDecl, TypeAliasDecl>(D)) {
+ // Suggest moving the attribute to the type instead, but only for our
+ // own vendor attributes; moving other vendors' attributes might hurt
+ // portability.
+ if (AL.isClangScope()) {
+ S.Diag(AL.getLoc(), diag::warn_type_attribute_deprecated_on_decl)
+ << AL << D->getLocation();
+ }
+
+ // Allow this type attribute to be handled in processTypeAttrs();
+ // silently move on.
+ break;
+ }
+
+ if (AL.getKind() == ParsedAttr::AT_Regparm) {
+ // `regparm` is a special case: It's a type attribute but we still want
+ // to treat it as if it had been written on the declaration because that
+ // way we'll be able to handle it directly in `processTypeAttr()`.
+ // If we treated `regparm` it as if it had been written on the
+ // `DeclSpec`, the logic in `distributeFunctionTypeAttrFromDeclSepc()`
+ // would try to move it to the declarator, but that doesn't work: We
+ // can't remove the attribute from the list of declaration attributes
+ // because it might be needed by other declarators in the same
+ // declaration.
+ break;
+ }
+
+ if (AL.getKind() == ParsedAttr::AT_VectorSize) {
+ // `vector_size` is a special case: It's a type attribute semantically,
+ // but GCC expects the [[]] syntax to be written on the declaration (and
+ // warns that the attribute has no effect if it is placed on the
+ // decl-specifier-seq).
+ // Silently move on and allow the attribute to be handled in
+ // processTypeAttr().
+ break;
+ }
+
+ if (AL.getKind() == ParsedAttr::AT_NoDeref) {
+ // FIXME: `noderef` currently doesn't work correctly in [[]] syntax.
+ // See https://github.com/llvm/llvm-project/issues/55790 for details.
+ // We allow processTypeAttrs() to emit a warning and silently move on.
+ break;
+ }
}
// N.B., ClangAttrEmitter.cpp emits a diagnostic helper that ensures a
// statement attribute is not written on a declaration, but this code is
- // needed for attributes in Attr.td that do not list any subjects.
- S.Diag(AL.getLoc(), diag::err_stmt_attribute_invalid_on_decl)
+ // needed for type attributes as well as statement attributes in Attr.td
+ // that do not list any subjects.
+ S.Diag(AL.getLoc(), diag::err_attribute_invalid_on_decl)
<< AL << D->getLocation();
break;
case ParsedAttr::AT_Interrupt:
@@ -8365,6 +8638,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_NoReturn:
handleNoReturnAttr(S, D, AL);
break;
+ case ParsedAttr::AT_CXX11NoReturn:
+ handleStandardNoReturnAttr(S, D, AL);
+ break;
case ParsedAttr::AT_AnyX86NoCfCheck:
handleNoCfCheckAttr(S, D, AL);
break;
@@ -8462,6 +8738,12 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_Section:
handleSectionAttr(S, D, AL);
break;
+ case ParsedAttr::AT_RandomizeLayout:
+ handleRandomizeLayoutAttr(S, D, AL);
+ break;
+ case ParsedAttr::AT_NoRandomizeLayout:
+ handleNoRandomizeLayoutAttr(S, D, AL);
+ break;
case ParsedAttr::AT_CodeSeg:
handleCodeSegAttr(S, D, AL);
break;
@@ -8551,6 +8833,8 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_PreserveMost:
case ParsedAttr::AT_PreserveAll:
case ParsedAttr::AT_AArch64VectorPcs:
+ case ParsedAttr::AT_AArch64SVEPcs:
+ case ParsedAttr::AT_AMDGPUKernelCall:
handleCallConvAttr(S, D, AL);
break;
case ParsedAttr::AT_Suppress:
@@ -8581,6 +8865,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_InternalLinkage:
handleInternalLinkageAttr(S, D, AL);
break;
+ case ParsedAttr::AT_ZeroCallUsedRegs:
+ handleZeroCallUsedRegsAttr(S, D, AL);
+ break;
// Microsoft attributes:
case ParsedAttr::AT_LayoutVersion:
@@ -8596,6 +8883,17 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
handleDeclspecThreadAttr(S, D, AL);
break;
+ // HLSL attributes:
+ case ParsedAttr::AT_HLSLNumThreads:
+ handleHLSLNumThreadsAttr(S, D, AL);
+ break;
+ case ParsedAttr::AT_HLSLSV_GroupIndex:
+ handleHLSLSVGroupIndexAttr(S, D, AL);
+ break;
+ case ParsedAttr::AT_HLSLShader:
+ handleHLSLShaderAttr(S, D, AL);
+ break;
+
case ParsedAttr::AT_AbiTag:
handleAbiTagAttr(S, D, AL);
break;
@@ -8786,14 +9084,14 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
/// ProcessDeclAttributeList - Apply all the decl attributes in the specified
/// attribute list to the specified decl, ignoring any type attributes.
-void Sema::ProcessDeclAttributeList(Scope *S, Decl *D,
- const ParsedAttributesView &AttrList,
- bool IncludeCXX11Attributes) {
+void Sema::ProcessDeclAttributeList(
+ Scope *S, Decl *D, const ParsedAttributesView &AttrList,
+ const ProcessDeclAttributeOptions &Options) {
if (AttrList.empty())
return;
for (const ParsedAttr &AL : AttrList)
- ProcessDeclAttribute(*this, S, D, AL, IncludeCXX11Attributes);
+ ProcessDeclAttribute(*this, S, D, AL, Options);
// FIXME: We should be able to handle these cases in TableGen.
// GCC accepts
@@ -8881,7 +9179,8 @@ bool Sema::ProcessAccessDeclAttributeList(
AccessSpecDecl *ASDecl, const ParsedAttributesView &AttrList) {
for (const ParsedAttr &AL : AttrList) {
if (AL.getKind() == ParsedAttr::AT_Annotate) {
- ProcessDeclAttribute(*this, nullptr, ASDecl, AL, AL.isCXX11Attribute());
+ ProcessDeclAttribute(*this, nullptr, ASDecl, AL,
+ ProcessDeclAttributeOptions());
} else {
Diag(AL.getLoc(), diag::err_only_annotate_after_access_spec);
return true;
@@ -8914,6 +9213,7 @@ static void checkUnusedDeclAttributes(Sema &S, const ParsedAttributesView &A) {
/// used to build a declaration, complain about any decl attributes
/// which might be lying around on it.
void Sema::checkUnusedDeclAttributes(Declarator &D) {
+ ::checkUnusedDeclAttributes(*this, D.getDeclarationAttributes());
::checkUnusedDeclAttributes(*this, D.getDeclSpec().getAttributes());
::checkUnusedDeclAttributes(*this, D.getAttributes());
for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i)
@@ -8922,8 +9222,8 @@ void Sema::checkUnusedDeclAttributes(Declarator &D) {
/// DeclClonePragmaWeak - clone existing decl (maybe definition),
/// \#pragma weak needs a non-definition decl and source may not have one.
-NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II,
- SourceLocation Loc) {
+NamedDecl *Sema::DeclClonePragmaWeak(NamedDecl *ND, const IdentifierInfo *II,
+ SourceLocation Loc) {
assert(isa<FunctionDecl>(ND) || isa<VarDecl>(ND));
NamedDecl *NewD = nullptr;
if (auto *FD = dyn_cast<FunctionDecl>(ND)) {
@@ -8968,9 +9268,7 @@ NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II,
/// DeclApplyPragmaWeak - A declaration (maybe definition) needs \#pragma weak
/// applied to it, possibly with an alias.
-void Sema::DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W) {
- if (W.getUsed()) return; // only do this once
- W.setUsed(true);
+void Sema::DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, const WeakInfo &W) {
if (W.getAlias()) { // clone decl, impersonate __attribute(weak,alias(...))
IdentifierInfo *NDId = ND->getIdentifier();
NamedDecl *NewD = DeclClonePragmaWeak(ND, W.getAlias(), W.getLocation());
@@ -8997,23 +9295,25 @@ void Sema::ProcessPragmaWeak(Scope *S, Decl *D) {
// It's valid to "forward-declare" #pragma weak, in which case we
// have to do this.
LoadExternalWeakUndeclaredIdentifiers();
- if (!WeakUndeclaredIdentifiers.empty()) {
- NamedDecl *ND = nullptr;
- if (auto *VD = dyn_cast<VarDecl>(D))
- if (VD->isExternC())
- ND = VD;
- if (auto *FD = dyn_cast<FunctionDecl>(D))
- if (FD->isExternC())
- ND = FD;
- if (ND) {
- if (IdentifierInfo *Id = ND->getIdentifier()) {
- auto I = WeakUndeclaredIdentifiers.find(Id);
- if (I != WeakUndeclaredIdentifiers.end()) {
- WeakInfo W = I->second;
- DeclApplyPragmaWeak(S, ND, W);
- WeakUndeclaredIdentifiers[Id] = W;
- }
- }
+ if (WeakUndeclaredIdentifiers.empty())
+ return;
+ NamedDecl *ND = nullptr;
+ if (auto *VD = dyn_cast<VarDecl>(D))
+ if (VD->isExternC())
+ ND = VD;
+ if (auto *FD = dyn_cast<FunctionDecl>(D))
+ if (FD->isExternC())
+ ND = FD;
+ if (!ND)
+ return;
+ if (IdentifierInfo *Id = ND->getIdentifier()) {
+ auto I = WeakUndeclaredIdentifiers.find(Id);
+ if (I != WeakUndeclaredIdentifiers.end()) {
+ auto &WeakInfos = I->second;
+ for (const auto &W : WeakInfos)
+ DeclApplyPragmaWeak(S, ND, W);
+ std::remove_reference_t<decltype(WeakInfos)> EmptyWeakInfos;
+ WeakInfos.swap(EmptyWeakInfos);
}
}
}
@@ -9022,17 +9322,43 @@ void Sema::ProcessPragmaWeak(Scope *S, Decl *D) {
/// it, apply them to D. This is a bit tricky because PD can have attributes
/// specified in many different places, and we need to find and apply them all.
void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) {
+ // Ordering of attributes can be important, so we take care to process
+ // attributes in the order in which they appeared in the source code.
+
+ // First, process attributes that appeared on the declaration itself (but
+ // only if they don't have the legacy behavior of "sliding" to the DeclSepc).
+ ParsedAttributesView NonSlidingAttrs;
+ for (ParsedAttr &AL : PD.getDeclarationAttributes()) {
+ if (AL.slidesFromDeclToDeclSpecLegacyBehavior()) {
+ // Skip processing the attribute, but do check if it appertains to the
+ // declaration. This is needed for the `MatrixType` attribute, which,
+ // despite being a type attribute, defines a `SubjectList` that only
+ // allows it to be used on typedef declarations.
+ AL.diagnoseAppertainsTo(*this, D);
+ } else {
+ NonSlidingAttrs.addAtEnd(&AL);
+ }
+ }
+ ProcessDeclAttributeList(S, D, NonSlidingAttrs);
+
// Apply decl attributes from the DeclSpec if present.
- if (!PD.getDeclSpec().getAttributes().empty())
- ProcessDeclAttributeList(S, D, PD.getDeclSpec().getAttributes());
+ if (!PD.getDeclSpec().getAttributes().empty()) {
+ ProcessDeclAttributeList(S, D, PD.getDeclSpec().getAttributes(),
+ ProcessDeclAttributeOptions()
+ .WithIncludeCXX11Attributes(false)
+ .WithIgnoreTypeAttributes(true));
+ }
// Walk the declarator structure, applying decl attributes that were in a type
// position to the decl itself. This handles cases like:
// int *__attr__(x)** D;
// when X is a decl attribute.
- for (unsigned i = 0, e = PD.getNumTypeObjects(); i != e; ++i)
+ for (unsigned i = 0, e = PD.getNumTypeObjects(); i != e; ++i) {
ProcessDeclAttributeList(S, D, PD.getTypeObject(i).getAttrs(),
- /*IncludeCXX11Attributes=*/false);
+ ProcessDeclAttributeOptions()
+ .WithIncludeCXX11Attributes(false)
+ .WithIgnoreTypeAttributes(true));
+ }
// Finally, apply any attributes on the decl itself.
ProcessDeclAttributeList(S, D, PD.getAttributes());
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 16cdb7e57723..221cbd14da97 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -1892,16 +1892,26 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl,
if (VD->isStaticLocal()) {
if (Kind == Sema::CheckConstexprKind::Diagnose) {
SemaRef.Diag(VD->getLocation(),
- diag::err_constexpr_local_var_static)
- << isa<CXXConstructorDecl>(Dcl)
- << (VD->getTLSKind() == VarDecl::TLS_Dynamic);
+ SemaRef.getLangOpts().CPlusPlus2b
+ ? diag::warn_cxx20_compat_constexpr_var
+ : diag::ext_constexpr_static_var)
+ << isa<CXXConstructorDecl>(Dcl)
+ << (VD->getTLSKind() == VarDecl::TLS_Dynamic);
+ } else if (!SemaRef.getLangOpts().CPlusPlus2b) {
+ return false;
}
- return false;
}
- if (CheckLiteralType(SemaRef, Kind, VD->getLocation(), VD->getType(),
- diag::err_constexpr_local_var_non_literal_type,
- isa<CXXConstructorDecl>(Dcl)))
+ if (SemaRef.LangOpts.CPlusPlus2b) {
+ CheckLiteralType(SemaRef, Kind, VD->getLocation(), VD->getType(),
+ diag::warn_cxx20_compat_constexpr_var,
+ isa<CXXConstructorDecl>(Dcl),
+ /*variable of non-literal type*/ 2);
+ } else if (CheckLiteralType(
+ SemaRef, Kind, VD->getLocation(), VD->getType(),
+ diag::err_constexpr_local_var_non_literal_type,
+ isa<CXXConstructorDecl>(Dcl))) {
return false;
+ }
if (!VD->getType()->isDependentType() &&
!VD->hasInit() && !VD->isCXXForRangeDecl()) {
if (Kind == Sema::CheckConstexprKind::Diagnose) {
@@ -2021,6 +2031,7 @@ static bool
CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
SmallVectorImpl<SourceLocation> &ReturnStmts,
SourceLocation &Cxx1yLoc, SourceLocation &Cxx2aLoc,
+ SourceLocation &Cxx2bLoc,
Sema::CheckConstexprKind Kind) {
// - its function-body shall be [...] a compound-statement that contains only
switch (S->getStmtClass()) {
@@ -2053,9 +2064,9 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
case Stmt::AttributedStmtClass:
// Attributes on a statement don't affect its formal kind and hence don't
// affect its validity in a constexpr function.
- return CheckConstexprFunctionStmt(SemaRef, Dcl,
- cast<AttributedStmt>(S)->getSubStmt(),
- ReturnStmts, Cxx1yLoc, Cxx2aLoc, Kind);
+ return CheckConstexprFunctionStmt(
+ SemaRef, Dcl, cast<AttributedStmt>(S)->getSubStmt(), ReturnStmts,
+ Cxx1yLoc, Cxx2aLoc, Cxx2bLoc, Kind);
case Stmt::CompoundStmtClass: {
// C++1y allows compound-statements.
@@ -2065,7 +2076,7 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
CompoundStmt *CompStmt = cast<CompoundStmt>(S);
for (auto *BodyIt : CompStmt->body()) {
if (!CheckConstexprFunctionStmt(SemaRef, Dcl, BodyIt, ReturnStmts,
- Cxx1yLoc, Cxx2aLoc, Kind))
+ Cxx1yLoc, Cxx2aLoc, Cxx2bLoc, Kind))
return false;
}
return true;
@@ -2078,11 +2089,11 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
IfStmt *If = cast<IfStmt>(S);
if (!CheckConstexprFunctionStmt(SemaRef, Dcl, If->getThen(), ReturnStmts,
- Cxx1yLoc, Cxx2aLoc, Kind))
+ Cxx1yLoc, Cxx2aLoc, Cxx2bLoc, Kind))
return false;
if (If->getElse() &&
!CheckConstexprFunctionStmt(SemaRef, Dcl, If->getElse(), ReturnStmts,
- Cxx1yLoc, Cxx2aLoc, Kind))
+ Cxx1yLoc, Cxx2aLoc, Cxx2bLoc, Kind))
return false;
return true;
}
@@ -2098,11 +2109,12 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
break;
if (!Cxx1yLoc.isValid())
Cxx1yLoc = S->getBeginLoc();
- for (Stmt *SubStmt : S->children())
+ for (Stmt *SubStmt : S->children()) {
if (SubStmt &&
!CheckConstexprFunctionStmt(SemaRef, Dcl, SubStmt, ReturnStmts,
- Cxx1yLoc, Cxx2aLoc, Kind))
+ Cxx1yLoc, Cxx2aLoc, Cxx2bLoc, Kind))
return false;
+ }
return true;
case Stmt::SwitchStmtClass:
@@ -2113,11 +2125,24 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
// mutation, we can reasonably allow them in C++11 as an extension.
if (!Cxx1yLoc.isValid())
Cxx1yLoc = S->getBeginLoc();
- for (Stmt *SubStmt : S->children())
+ for (Stmt *SubStmt : S->children()) {
+ if (SubStmt &&
+ !CheckConstexprFunctionStmt(SemaRef, Dcl, SubStmt, ReturnStmts,
+ Cxx1yLoc, Cxx2aLoc, Cxx2bLoc, Kind))
+ return false;
+ }
+ return true;
+
+ case Stmt::LabelStmtClass:
+ case Stmt::GotoStmtClass:
+ if (Cxx2bLoc.isInvalid())
+ Cxx2bLoc = S->getBeginLoc();
+ for (Stmt *SubStmt : S->children()) {
if (SubStmt &&
!CheckConstexprFunctionStmt(SemaRef, Dcl, SubStmt, ReturnStmts,
- Cxx1yLoc, Cxx2aLoc, Kind))
+ Cxx1yLoc, Cxx2aLoc, Cxx2bLoc, Kind))
return false;
+ }
return true;
case Stmt::GCCAsmStmtClass:
@@ -2129,7 +2154,7 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
for (Stmt *SubStmt : S->children()) {
if (SubStmt &&
!CheckConstexprFunctionStmt(SemaRef, Dcl, SubStmt, ReturnStmts,
- Cxx1yLoc, Cxx2aLoc, Kind))
+ Cxx1yLoc, Cxx2aLoc, Cxx2bLoc, Kind))
return false;
}
return true;
@@ -2137,9 +2162,9 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
case Stmt::CXXCatchStmtClass:
// Do not bother checking the language mode (already covered by the
// try block check).
- if (!CheckConstexprFunctionStmt(SemaRef, Dcl,
- cast<CXXCatchStmt>(S)->getHandlerBlock(),
- ReturnStmts, Cxx1yLoc, Cxx2aLoc, Kind))
+ if (!CheckConstexprFunctionStmt(
+ SemaRef, Dcl, cast<CXXCatchStmt>(S)->getHandlerBlock(), ReturnStmts,
+ Cxx1yLoc, Cxx2aLoc, Cxx2bLoc, Kind))
return false;
return true;
@@ -2204,20 +2229,27 @@ static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl,
//
// Note that walking the children here is enough to properly check for
// CompoundStmt and CXXTryStmt body.
- SourceLocation Cxx1yLoc, Cxx2aLoc;
+ SourceLocation Cxx1yLoc, Cxx2aLoc, Cxx2bLoc;
for (Stmt *SubStmt : Body->children()) {
if (SubStmt &&
!CheckConstexprFunctionStmt(SemaRef, Dcl, SubStmt, ReturnStmts,
- Cxx1yLoc, Cxx2aLoc, Kind))
+ Cxx1yLoc, Cxx2aLoc, Cxx2bLoc, Kind))
return false;
}
if (Kind == Sema::CheckConstexprKind::CheckValid) {
// If this is only valid as an extension, report that we don't satisfy the
// constraints of the current language.
- if ((Cxx2aLoc.isValid() && !SemaRef.getLangOpts().CPlusPlus20) ||
+ if ((Cxx2bLoc.isValid() && !SemaRef.getLangOpts().CPlusPlus2b) ||
+ (Cxx2aLoc.isValid() && !SemaRef.getLangOpts().CPlusPlus20) ||
(Cxx1yLoc.isValid() && !SemaRef.getLangOpts().CPlusPlus17))
return false;
+ } else if (Cxx2bLoc.isValid()) {
+ SemaRef.Diag(Cxx2bLoc,
+ SemaRef.getLangOpts().CPlusPlus2b
+ ? diag::warn_cxx20_compat_constexpr_body_invalid_stmt
+ : diag::ext_constexpr_body_invalid_stmt_cxx2b)
+ << isa<CXXConstructorDecl>(Dcl);
} else if (Cxx2aLoc.isValid()) {
SemaRef.Diag(Cxx2aLoc,
SemaRef.getLangOpts().CPlusPlus20
@@ -2469,6 +2501,11 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
bool Virtual, AccessSpecifier Access,
TypeSourceInfo *TInfo,
SourceLocation EllipsisLoc) {
+ // In HLSL, unspecified class access is public rather than private.
+ if (getLangOpts().HLSL && Class->getTagKind() == TTK_Class &&
+ Access == AS_none)
+ Access = AS_public;
+
QualType BaseType = TInfo->getType();
if (BaseType->containsErrors()) {
// Already emitted a diagnostic when parsing the error type.
@@ -2615,12 +2652,11 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
/// example:
/// class foo : public bar, virtual private baz {
/// 'public bar' and 'virtual private baz' are each base-specifiers.
-BaseResult
-Sema::ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange,
- ParsedAttributes &Attributes,
- bool Virtual, AccessSpecifier Access,
- ParsedType basetype, SourceLocation BaseLoc,
- SourceLocation EllipsisLoc) {
+BaseResult Sema::ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange,
+ const ParsedAttributesView &Attributes,
+ bool Virtual, AccessSpecifier Access,
+ ParsedType basetype, SourceLocation BaseLoc,
+ SourceLocation EllipsisLoc) {
if (!classdecl)
return true;
@@ -3395,6 +3431,15 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
return nullptr;
}
+ if (D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId) {
+ Diag(D.getIdentifierLoc(), diag::err_member_with_template_arguments)
+ << II
+ << SourceRange(D.getName().TemplateId->LAngleLoc,
+ D.getName().TemplateId->RAngleLoc)
+ << D.getName().TemplateId->LAngleLoc;
+ D.SetIdentifier(II, Loc);
+ }
+
if (SS.isSet() && !SS.isInvalid()) {
// The user provided a superfluous scope specifier inside a class
// definition:
@@ -4262,6 +4307,15 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
}
}
+ if (getLangOpts().MSVCCompat && !getLangOpts().CPlusPlus20) {
+ auto UnqualifiedBase = R.getAsSingle<ClassTemplateDecl>();
+ if (UnqualifiedBase) {
+ Diag(IdLoc, diag::ext_unqualified_base_class)
+ << SourceRange(IdLoc, Init->getSourceRange().getEnd());
+ BaseType = UnqualifiedBase->getInjectedClassNameSpecialization();
+ }
+ }
+
// If no results were found, try to correct typos.
TypoCorrection Corr;
MemInitializerValidatorCCC CCC(ClassDecl);
@@ -5376,8 +5430,7 @@ static void DiagnoseBaseOrMemInitializerOrder(
return;
// Sort based on the ideal order, first in the pair.
- llvm::sort(CorrelatedInitOrder,
- [](auto &LHS, auto &RHS) { return LHS.first < RHS.first; });
+ llvm::sort(CorrelatedInitOrder, llvm::less_first());
// Introduce a new scope as SemaDiagnosticBuilder needs to be destroyed to
// emit the diagnostic before we can try adding notes.
@@ -6640,7 +6693,7 @@ static bool canPassInRegisters(Sema &S, CXXRecordDecl *D,
return false;
for (const CXXMethodDecl *MD : D->methods()) {
- if (MD->isDeleted())
+ if (MD->isDeleted() || MD->isIneligibleOrNotSelected())
continue;
auto *CD = dyn_cast<CXXConstructorDecl>(MD);
@@ -8564,10 +8617,10 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD,
int(1)))
return true;
- if (llvm::find_if(RD->friends(), [&](const FriendDecl *F) {
+ if (llvm::none_of(RD->friends(), [&](const FriendDecl *F) {
return FD->getCanonicalDecl() ==
F->getFriendDecl()->getCanonicalDecl();
- }) == RD->friends().end()) {
+ })) {
Diag(FD->getLocation(), diag::err_defaulted_comparison_not_friend)
<< int(DCK) << int(0) << RD;
Diag(RD->getCanonicalDecl()->getLocation(), diag::note_declared_at);
@@ -9159,13 +9212,12 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) {
<< !!ICI << MD->getParent() << FD << FieldType << /*Reference*/0;
return true;
}
- // C++11 [class.ctor]p5: any non-variant non-static data member of
- // const-qualified type (or array thereof) with no
- // brace-or-equal-initializer does not have a user-provided default
- // constructor.
+ // C++11 [class.ctor]p5 (modified by DR2394): any non-variant non-static
+ // data member of const-qualified type (or array thereof) with no
+ // brace-or-equal-initializer is not const-default-constructible.
if (!inUnion() && FieldType.isConstQualified() &&
!FD->hasInClassInitializer() &&
- (!FieldRecord || !FieldRecord->hasUserProvidedDefaultConstructor())) {
+ (!FieldRecord || !FieldRecord->allowConstDefaultInit())) {
if (Diagnose)
S.Diag(FD->getLocation(), diag::note_deleted_default_ctor_uninit_field)
<< !!ICI << MD->getParent() << FD << FD->getType() << /*Const*/1;
@@ -9720,11 +9772,22 @@ bool Sema::SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM,
case CXXCopyConstructor:
case CXXCopyAssignment: {
- // Trivial copy operations always have const, non-volatile parameter types.
- ConstArg = true;
const ParmVarDecl *Param0 = MD->getParamDecl(0);
const ReferenceType *RT = Param0->getType()->getAs<ReferenceType>();
- if (!RT || RT->getPointeeType().getCVRQualifiers() != Qualifiers::Const) {
+
+ // When ClangABICompat14 is true, CXX copy constructors will only be trivial
+ // if they are not user-provided and their parameter-type-list is equivalent
+ // to the parameter-type-list of an implicit declaration. This maintains the
+ // behavior before dr2171 was implemented.
+ //
+ // Otherwise, if ClangABICompat14 is false, All copy constructors can be
+ // trivial, if they are not user-provided, regardless of the qualifiers on
+ // the reference type.
+ const bool ClangABICompat14 = Context.getLangOpts().getClangABICompat() <=
+ LangOptions::ClangABI::Ver14;
+ if (!RT ||
+ ((RT->getPointeeType().getCVRQualifiers() != Qualifiers::Const) &&
+ ClangABICompat14)) {
if (Diagnose)
Diag(Param0->getLocation(), diag::note_nontrivial_param_type)
<< Param0->getSourceRange() << Param0->getType()
@@ -9732,6 +9795,8 @@ bool Sema::SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM,
Context.getRecordType(RD).withConst());
return false;
}
+
+ ConstArg = RT->getPointeeType().isConstQualified();
break;
}
@@ -10983,6 +11048,8 @@ void Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R,
TemplateName SpecifiedName = RetTST.getTypePtr()->getTemplateName();
bool TemplateMatches =
Context.hasSameTemplateName(SpecifiedName, GuidedTemplate);
+ // FIXME: We should consider other template kinds (using, qualified),
+ // otherwise we will emit bogus diagnostics.
if (SpecifiedName.getKind() == TemplateName::Template && TemplateMatches)
AcceptableReturnType = true;
else {
@@ -11025,6 +11092,11 @@ static void DiagnoseNamespaceInlineMismatch(Sema &S, SourceLocation KeywordLoc,
NamespaceDecl *PrevNS) {
assert(*IsInline != PrevNS->isInline());
+ // 'inline' must appear on the original definition, but not necessarily
+ // on all extension definitions, so the note should point to the first
+ // definition to avoid confusion.
+ PrevNS = PrevNS->getFirstDecl();
+
if (PrevNS->isInline())
// The user probably just forgot the 'inline', so suggest that it
// be added back.
@@ -13306,7 +13378,8 @@ void Sema::CheckImplicitSpecialMemberDeclaration(Scope *S, FunctionDecl *FD) {
R.resolveKind();
R.suppressDiagnostics();
- CheckFunctionDeclaration(S, FD, R, /*IsMemberSpecialization*/false);
+ CheckFunctionDeclaration(S, FD, R, /*IsMemberSpecialization*/ false,
+ FD->isThisDeclarationADefinition());
}
void Sema::setupImplicitSpecialMemberType(CXXMethodDecl *SpecialMem,
@@ -13370,14 +13443,13 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
DefaultCon->setAccess(AS_public);
DefaultCon->setDefaulted();
- if (getLangOpts().CUDA) {
+ setupImplicitSpecialMemberType(DefaultCon, Context.VoidTy, None);
+
+ if (getLangOpts().CUDA)
inferCUDATargetForImplicitSpecialMember(ClassDecl, CXXDefaultConstructor,
DefaultCon,
/* ConstRHS */ false,
/* Diagnose */ false);
- }
-
- setupImplicitSpecialMemberType(DefaultCon, Context.VoidTy, None);
// We don't need to use SpecialMemberIsTrivial here; triviality for default
// constructors is easy to compute.
@@ -13651,14 +13723,13 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
Destructor->setAccess(AS_public);
Destructor->setDefaulted();
- if (getLangOpts().CUDA) {
+ setupImplicitSpecialMemberType(Destructor, Context.VoidTy, None);
+
+ if (getLangOpts().CUDA)
inferCUDATargetForImplicitSpecialMember(ClassDecl, CXXDestructor,
Destructor,
/* ConstRHS */ false,
/* Diagnose */ false);
- }
-
- setupImplicitSpecialMemberType(Destructor, Context.VoidTy, None);
// We don't need to use SpecialMemberIsTrivial here; triviality for
// destructors is easy to compute.
@@ -14291,14 +14362,13 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
CopyAssignment->setDefaulted();
CopyAssignment->setImplicit();
- if (getLangOpts().CUDA) {
+ setupImplicitSpecialMemberType(CopyAssignment, RetType, ArgType);
+
+ if (getLangOpts().CUDA)
inferCUDATargetForImplicitSpecialMember(ClassDecl, CXXCopyAssignment,
CopyAssignment,
/* ConstRHS */ Const,
/* Diagnose */ false);
- }
-
- setupImplicitSpecialMemberType(CopyAssignment, RetType, ArgType);
// Add the parameter to the operator.
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyAssignment,
@@ -14626,14 +14696,13 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) {
MoveAssignment->setDefaulted();
MoveAssignment->setImplicit();
- if (getLangOpts().CUDA) {
+ setupImplicitSpecialMemberType(MoveAssignment, RetType, ArgType);
+
+ if (getLangOpts().CUDA)
inferCUDATargetForImplicitSpecialMember(ClassDecl, CXXMoveAssignment,
MoveAssignment,
/* ConstRHS */ false,
/* Diagnose */ false);
- }
-
- setupImplicitSpecialMemberType(MoveAssignment, RetType, ArgType);
// Add the parameter to the operator.
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, MoveAssignment,
@@ -14743,8 +14812,7 @@ static void checkMoveAssignmentForRepeatedMove(Sema &S, CXXRecordDecl *Class,
continue;
// We're going to move the base classes of Base. Add them to the list.
- for (auto &BI : Base->bases())
- Worklist.push_back(&BI);
+ llvm::append_range(Worklist, llvm::make_pointer_range(Base->bases()));
}
}
}
@@ -15006,14 +15074,13 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
CopyConstructor->setAccess(AS_public);
CopyConstructor->setDefaulted();
- if (getLangOpts().CUDA) {
+ setupImplicitSpecialMemberType(CopyConstructor, Context.VoidTy, ArgType);
+
+ if (getLangOpts().CUDA)
inferCUDATargetForImplicitSpecialMember(ClassDecl, CXXCopyConstructor,
CopyConstructor,
/* ConstRHS */ Const,
/* Diagnose */ false);
- }
-
- setupImplicitSpecialMemberType(CopyConstructor, Context.VoidTy, ArgType);
// During template instantiation of special member functions we need a
// reliable TypeSourceInfo for the parameter types in order to allow functions
@@ -15146,14 +15213,13 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor(
MoveConstructor->setAccess(AS_public);
MoveConstructor->setDefaulted();
- if (getLangOpts().CUDA) {
+ setupImplicitSpecialMemberType(MoveConstructor, Context.VoidTy, ArgType);
+
+ if (getLangOpts().CUDA)
inferCUDATargetForImplicitSpecialMember(ClassDecl, CXXMoveConstructor,
MoveConstructor,
/* ConstRHS */ false,
/* Diagnose */ false);
- }
-
- setupImplicitSpecialMemberType(MoveConstructor, Context.VoidTy, ArgType);
// Add the parameter to the constructor.
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, MoveConstructor,
@@ -15287,8 +15353,8 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion(
VK_LValue, Conv->getLocation());
assert(FunctionRef && "Can't refer to __invoke function?");
Stmt *Return = BuildReturnStmt(Conv->getLocation(), FunctionRef).get();
- Conv->setBody(CompoundStmt::Create(Context, Return, Conv->getLocation(),
- Conv->getLocation()));
+ Conv->setBody(CompoundStmt::Create(Context, Return, FPOptionsOverride(),
+ Conv->getLocation(), Conv->getLocation()));
Conv->markUsed(Context);
Conv->setReferenced();
@@ -15342,8 +15408,8 @@ void Sema::DefineImplicitLambdaToBlockPointerConversion(
// Set the body of the conversion function.
Stmt *ReturnS = Return.get();
- Conv->setBody(CompoundStmt::Create(Context, ReturnS, Conv->getLocation(),
- Conv->getLocation()));
+ Conv->setBody(CompoundStmt::Create(Context, ReturnS, FPOptionsOverride(),
+ Conv->getLocation(), Conv->getLocation()));
Conv->markUsed(Context);
// We're done; notify the mutation listener, if any.
@@ -15865,14 +15931,29 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
// An operator function cannot have default arguments (8.3.6),
// except where explicitly stated below.
//
- // Only the function-call operator allows default arguments
- // (C++ [over.call]p1).
+ // Only the function-call operator (C++ [over.call]p1) and the subscript
+ // operator (CWG2507) allow default arguments.
if (Op != OO_Call) {
+ ParmVarDecl *FirstDefaultedParam = nullptr;
for (auto Param : FnDecl->parameters()) {
- if (Param->hasDefaultArg())
- return Diag(Param->getLocation(),
+ if (Param->hasDefaultArg()) {
+ FirstDefaultedParam = Param;
+ break;
+ }
+ }
+ if (FirstDefaultedParam) {
+ if (Op == OO_Subscript) {
+ Diag(FnDecl->getLocation(), LangOpts.CPlusPlus2b
+ ? diag::ext_subscript_overload
+ : diag::error_subscript_overload)
+ << FnDecl->getDeclName() << 1
+ << FirstDefaultedParam->getDefaultArgRange();
+ } else {
+ return Diag(FirstDefaultedParam->getLocation(),
diag::err_operator_overload_default_arg)
- << FnDecl->getDeclName() << Param->getDefaultArgRange();
+ << FnDecl->getDeclName()
+ << FirstDefaultedParam->getDefaultArgRange();
+ }
}
}
@@ -15893,10 +15974,10 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
// described in the rest of this subclause.
unsigned NumParams = FnDecl->getNumParams()
+ (isa<CXXMethodDecl>(FnDecl)? 1 : 0);
- if (Op != OO_Call &&
+ if (Op != OO_Call && Op != OO_Subscript &&
((NumParams == 1 && !CanBeUnaryOperator) ||
- (NumParams == 2 && !CanBeBinaryOperator) ||
- (NumParams < 1) || (NumParams > 2))) {
+ (NumParams == 2 && !CanBeBinaryOperator) || (NumParams < 1) ||
+ (NumParams > 2))) {
// We have the wrong number of parameters.
unsigned ErrorKind;
if (CanBeUnaryOperator && CanBeBinaryOperator) {
@@ -15908,16 +15989,23 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
"All non-call overloaded operators are unary or binary!");
ErrorKind = 1; // 1 -> binary
}
-
return Diag(FnDecl->getLocation(), diag::err_operator_overload_must_be)
<< FnDecl->getDeclName() << NumParams << ErrorKind;
}
- // Overloaded operators other than operator() cannot be variadic.
+ if (Op == OO_Subscript && NumParams != 2) {
+ Diag(FnDecl->getLocation(), LangOpts.CPlusPlus2b
+ ? diag::ext_subscript_overload
+ : diag::error_subscript_overload)
+ << FnDecl->getDeclName() << (NumParams == 1 ? 0 : 2);
+ }
+
+ // Overloaded operators other than operator() and operator[] cannot be
+ // variadic.
if (Op != OO_Call &&
FnDecl->getType()->castAs<FunctionProtoType>()->isVariadic()) {
return Diag(FnDecl->getLocation(), diag::err_operator_overload_variadic)
- << FnDecl->getDeclName();
+ << FnDecl->getDeclName();
}
// Some operators must be non-static member functions.
@@ -16186,7 +16274,7 @@ Decl *Sema::ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc,
Expr *LangStr,
SourceLocation LBraceLoc) {
StringLiteral *Lit = cast<StringLiteral>(LangStr);
- if (!Lit->isAscii()) {
+ if (!Lit->isOrdinary()) {
Diag(LangStr->getExprLoc(), diag::err_language_linkage_spec_not_ascii)
<< LangStr->getSourceRange();
return nullptr;
@@ -16222,7 +16310,12 @@ Decl *Sema::ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc,
if (getLangOpts().CPlusPlusModules && isCurrentModulePurview()) {
Module *GlobalModule =
PushGlobalModuleFragment(ExternLoc, /*IsImplicit=*/true);
- D->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ModulePrivate);
+ /// According to [module.reach]p3.2,
+ /// The declaration in global module fragment is reachable if it is not
+ /// discarded. And the discarded declaration should be deleted. So it
+ /// doesn't matter mark the declaration in global module fragment as
+ /// reachable here.
+ D->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ReachableWhenImported);
D->setLocalOwningModule(GlobalModule);
}
@@ -16499,8 +16592,13 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc,
if (!Failed && !Cond) {
SmallString<256> MsgBuffer;
llvm::raw_svector_ostream Msg(MsgBuffer);
- if (AssertMessage)
- AssertMessage->printPretty(Msg, nullptr, getPrintingPolicy());
+ if (AssertMessage) {
+ const auto *MsgStr = cast<StringLiteral>(AssertMessage);
+ if (MsgStr->isOrdinary())
+ Msg << MsgStr->getString();
+ else
+ MsgStr->printPretty(Msg, nullptr, getPrintingPolicy());
+ }
Expr *InnerCond = nullptr;
std::string InnerCondDescription;
@@ -16785,7 +16883,8 @@ Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
// Try to convert the decl specifier to a type. This works for
// friend templates because ActOnTag never produces a ClassTemplateDecl
// for a TUK_Friend.
- Declarator TheDeclarator(DS, DeclaratorContext::Member);
+ Declarator TheDeclarator(DS, ParsedAttributesView::none(),
+ DeclaratorContext::Member);
TypeSourceInfo *TSI = GetTypeForDeclarator(TheDeclarator, S);
QualType T = TSI->getType();
if (TheDeclarator.isInvalidType())
@@ -17319,6 +17418,21 @@ void Sema::DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock) {
}
}
+void Sema::SetFunctionBodyKind(Decl *D, SourceLocation Loc,
+ FnBodyKind BodyKind) {
+ switch (BodyKind) {
+ case FnBodyKind::Delete:
+ SetDeclDeleted(D, Loc);
+ break;
+ case FnBodyKind::Default:
+ SetDeclDefaulted(D, Loc);
+ break;
+ case FnBodyKind::Other:
+ llvm_unreachable(
+ "Parsed function body should be '= delete;' or '= default;'");
+ }
+}
+
bool Sema::CheckOverridingFunctionAttributes(const CXXMethodDecl *New,
const CXXMethodDecl *Old) {
const auto *NewFT = New->getType()->castAs<FunctionProtoType>();
@@ -18265,8 +18379,7 @@ void Sema::ActOnStartFunctionDeclarationDeclarator(
}
if (ExplicitParams) {
Info.AutoTemplateParameterDepth = ExplicitParams->getDepth();
- for (NamedDecl *Param : *ExplicitParams)
- Info.TemplateParams.push_back(Param);
+ llvm::append_range(Info.TemplateParams, *ExplicitParams);
Info.NumExplicitTemplateParams = ExplicitParams->size();
} else {
Info.AutoTemplateParameterDepth = TemplateParameterDepth;
diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp
index d4fefc3d18d8..a574a5539330 100644
--- a/clang/lib/Sema/SemaDeclObjC.cpp
+++ b/clang/lib/Sema/SemaDeclObjC.cpp
@@ -971,7 +971,7 @@ static bool checkTypeParamListConsistency(Sema &S,
return false;
}
-Decl *Sema::ActOnStartClassInterface(
+ObjCInterfaceDecl *Sema::ActOnStartClassInterface(
Scope *S, SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName,
SourceLocation ClassLoc, ObjCTypeParamList *typeParamList,
IdentifierInfo *SuperName, SourceLocation SuperLoc,
@@ -1100,7 +1100,8 @@ Decl *Sema::ActOnStartClassInterface(
}
CheckObjCDeclScope(IDecl);
- return ActOnObjCContainerStartDefinition(IDecl);
+ ActOnObjCContainerStartDefinition(IDecl);
+ return IDecl;
}
/// ActOnTypedefedProtocols - this action finds protocol list as part of the
@@ -1208,7 +1209,7 @@ bool Sema::CheckForwardProtocolDeclarationForCircularDependency(
return res;
}
-Decl *Sema::ActOnStartProtocolInterface(
+ObjCProtocolDecl *Sema::ActOnStartProtocolInterface(
SourceLocation AtProtoInterfaceLoc, IdentifierInfo *ProtocolName,
SourceLocation ProtocolLoc, Decl *const *ProtoRefs, unsigned NumProtoRefs,
const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc,
@@ -1272,7 +1273,8 @@ Decl *Sema::ActOnStartProtocolInterface(
}
CheckObjCDeclScope(PDecl);
- return ActOnObjCContainerStartDefinition(PDecl);
+ ActOnObjCContainerStartDefinition(PDecl);
+ return PDecl;
}
static bool NestedProtocolHasNoDefinition(ObjCProtocolDecl *PDecl,
@@ -1586,7 +1588,7 @@ void Sema::actOnObjCTypeArgsOrProtocolQualifiers(
DS.SetRangeEnd(loc);
// Form the declarator.
- Declarator D(DS, DeclaratorContext::TypeName);
+ Declarator D(DS, ParsedAttributesView::none(), DeclaratorContext::TypeName);
// If we have a typedef of an Objective-C class type that is missing a '*',
// add the '*'.
@@ -1799,7 +1801,7 @@ Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc,
return BuildDeclaratorGroup(DeclsInGroup);
}
-Decl *Sema::ActOnStartCategoryInterface(
+ObjCCategoryDecl *Sema::ActOnStartCategoryInterface(
SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName,
SourceLocation ClassLoc, ObjCTypeParamList *typeParamList,
IdentifierInfo *CategoryName, SourceLocation CategoryLoc,
@@ -1826,7 +1828,8 @@ Decl *Sema::ActOnStartCategoryInterface(
if (!IDecl)
Diag(ClassLoc, diag::err_undef_interface) << ClassName;
- return ActOnObjCContainerStartDefinition(CDecl);
+ ActOnObjCContainerStartDefinition(CDecl);
+ return CDecl;
}
if (!CategoryName && IDecl->getImplementation()) {
@@ -1889,17 +1892,17 @@ Decl *Sema::ActOnStartCategoryInterface(
}
CheckObjCDeclScope(CDecl);
- return ActOnObjCContainerStartDefinition(CDecl);
+ ActOnObjCContainerStartDefinition(CDecl);
+ return CDecl;
}
/// ActOnStartCategoryImplementation - Perform semantic checks on the
/// category implementation declaration and build an ObjCCategoryImplDecl
/// object.
-Decl *Sema::ActOnStartCategoryImplementation(
- SourceLocation AtCatImplLoc,
- IdentifierInfo *ClassName, SourceLocation ClassLoc,
- IdentifierInfo *CatName, SourceLocation CatLoc,
- const ParsedAttributesView &Attrs) {
+ObjCCategoryImplDecl *Sema::ActOnStartCategoryImplementation(
+ SourceLocation AtCatImplLoc, IdentifierInfo *ClassName,
+ SourceLocation ClassLoc, IdentifierInfo *CatName, SourceLocation CatLoc,
+ const ParsedAttributesView &Attrs) {
ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc, true);
ObjCCategoryDecl *CatIDecl = nullptr;
if (IDecl && IDecl->hasDefinition()) {
@@ -1958,15 +1961,14 @@ Decl *Sema::ActOnStartCategoryImplementation(
}
CheckObjCDeclScope(CDecl);
- return ActOnObjCContainerStartDefinition(CDecl);
+ ActOnObjCContainerStartDefinition(CDecl);
+ return CDecl;
}
-Decl *Sema::ActOnStartClassImplementation(
- SourceLocation AtClassImplLoc,
- IdentifierInfo *ClassName, SourceLocation ClassLoc,
- IdentifierInfo *SuperClassname,
- SourceLocation SuperClassLoc,
- const ParsedAttributesView &Attrs) {
+ObjCImplementationDecl *Sema::ActOnStartClassImplementation(
+ SourceLocation AtClassImplLoc, IdentifierInfo *ClassName,
+ SourceLocation ClassLoc, IdentifierInfo *SuperClassname,
+ SourceLocation SuperClassLoc, const ParsedAttributesView &Attrs) {
ObjCInterfaceDecl *IDecl = nullptr;
// Check for another declaration kind with the same name.
NamedDecl *PrevDecl
@@ -2063,8 +2065,10 @@ Decl *Sema::ActOnStartClassImplementation(
ProcessDeclAttributeList(TUScope, IMPDecl, Attrs);
AddPragmaAttributes(TUScope, IMPDecl);
- if (CheckObjCDeclScope(IMPDecl))
- return ActOnObjCContainerStartDefinition(IMPDecl);
+ if (CheckObjCDeclScope(IMPDecl)) {
+ ActOnObjCContainerStartDefinition(IMPDecl);
+ return IMPDecl;
+ }
// Check that there is no duplicate implementation of this class.
if (IDecl->getImplementation()) {
@@ -2090,7 +2094,8 @@ Decl *Sema::ActOnStartClassImplementation(
<< IDecl->getSuperClass()->getDeclName();
}
- return ActOnObjCContainerStartDefinition(IMPDecl);
+ ActOnObjCContainerStartDefinition(IMPDecl);
+ return IMPDecl;
}
Sema::DeclGroupPtrTy
@@ -4532,7 +4537,7 @@ static QualType mergeTypeNullabilityForRedecl(Sema &S, SourceLocation loc,
auto prevNullability = prevType->getNullability(S.Context);
// Easy case: both have nullability.
- if (nullability.hasValue() == prevNullability.hasValue()) {
+ if (nullability.has_value() == prevNullability.has_value()) {
// Neither has nullability; continue.
if (!nullability)
return type;
diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
index 29cb4be7b1ba..d8344cfd01f9 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -342,8 +342,7 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
if (!MissingExceptionSpecification)
return ReturnValueOnError;
- const FunctionProtoType *NewProto =
- New->getType()->castAs<FunctionProtoType>();
+ const auto *NewProto = New->getType()->castAs<FunctionProtoType>();
// The new function declaration is only missing an empty exception
// specification "throw()". If the throw() specification came from a
@@ -353,7 +352,7 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
// specifications.
//
// Likewise if the old function is a builtin.
- if (MissingEmptyExceptionSpecification && NewProto &&
+ if (MissingEmptyExceptionSpecification &&
(Old->getLocation().isInvalid() ||
Context.getSourceManager().isInSystemHeader(Old->getLocation()) ||
Old->getBuiltinID()) &&
@@ -364,8 +363,7 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
return false;
}
- const FunctionProtoType *OldProto =
- Old->getType()->castAs<FunctionProtoType>();
+ const auto *OldProto = Old->getType()->castAs<FunctionProtoType>();
FunctionProtoType::ExceptionSpecInfo ESI = OldProto->getExceptionSpecType();
if (ESI.Type == EST_Dynamic) {
@@ -1455,15 +1453,20 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
case Stmt::OMPForSimdDirectiveClass:
case Stmt::OMPMasterDirectiveClass:
case Stmt::OMPMasterTaskLoopDirectiveClass:
+ case Stmt::OMPMaskedTaskLoopDirectiveClass:
case Stmt::OMPMasterTaskLoopSimdDirectiveClass:
+ case Stmt::OMPMaskedTaskLoopSimdDirectiveClass:
case Stmt::OMPOrderedDirectiveClass:
case Stmt::OMPCanonicalLoopClass:
case Stmt::OMPParallelDirectiveClass:
case Stmt::OMPParallelForDirectiveClass:
case Stmt::OMPParallelForSimdDirectiveClass:
case Stmt::OMPParallelMasterDirectiveClass:
+ case Stmt::OMPParallelMaskedDirectiveClass:
case Stmt::OMPParallelMasterTaskLoopDirectiveClass:
+ case Stmt::OMPParallelMaskedTaskLoopDirectiveClass:
case Stmt::OMPParallelMasterTaskLoopSimdDirectiveClass:
+ case Stmt::OMPParallelMaskedTaskLoopSimdDirectiveClass:
case Stmt::OMPParallelSectionsDirectiveClass:
case Stmt::OMPSectionDirectiveClass:
case Stmt::OMPSectionsDirectiveClass:
@@ -1501,6 +1504,10 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
case Stmt::OMPMaskedDirectiveClass:
case Stmt::OMPMetaDirectiveClass:
case Stmt::OMPGenericLoopDirectiveClass:
+ case Stmt::OMPTeamsGenericLoopDirectiveClass:
+ case Stmt::OMPTargetTeamsGenericLoopDirectiveClass:
+ case Stmt::OMPParallelGenericLoopDirectiveClass:
+ case Stmt::OMPTargetParallelGenericLoopDirectiveClass:
case Stmt::ReturnStmtClass:
case Stmt::SEHExceptStmtClass:
case Stmt::SEHFinallyStmtClass:
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 85553eccde83..b9ecde6f20a0 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -27,11 +27,13 @@
#include "clang/AST/OperationKinds.h"
#include "clang/AST/ParentMapContext.h"
#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/AST/Type.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/Specifiers.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/LiteralSupport.h"
#include "clang/Lex/Preprocessor.h"
@@ -50,8 +52,10 @@
#include "clang/Sema/Template.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Casting.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/SaveAndRestore.h"
+#include "llvm/Support/TypeSize.h"
using namespace clang;
using namespace sema;
@@ -773,6 +777,40 @@ ExprResult Sema::UsualUnaryConversions(Expr *E) {
QualType Ty = E->getType();
assert(!Ty.isNull() && "UsualUnaryConversions - missing type");
+ LangOptions::FPEvalMethodKind EvalMethod = CurFPFeatures.getFPEvalMethod();
+ if (EvalMethod != LangOptions::FEM_Source && Ty->isFloatingType() &&
+ (getLangOpts().getFPEvalMethod() !=
+ LangOptions::FPEvalMethodKind::FEM_UnsetOnCommandLine ||
+ PP.getLastFPEvalPragmaLocation().isValid())) {
+ switch (EvalMethod) {
+ default:
+ llvm_unreachable("Unrecognized float evaluation method");
+ break;
+ case LangOptions::FEM_UnsetOnCommandLine:
+ llvm_unreachable("Float evaluation method should be set by now");
+ break;
+ case LangOptions::FEM_Double:
+ if (Context.getFloatingTypeOrder(Context.DoubleTy, Ty) > 0)
+ // Widen the expression to double.
+ return Ty->isComplexType()
+ ? ImpCastExprToType(E,
+ Context.getComplexType(Context.DoubleTy),
+ CK_FloatingComplexCast)
+ : ImpCastExprToType(E, Context.DoubleTy, CK_FloatingCast);
+ break;
+ case LangOptions::FEM_Extended:
+ if (Context.getFloatingTypeOrder(Context.LongDoubleTy, Ty) > 0)
+ // Widen the expression to long double.
+ return Ty->isComplexType()
+ ? ImpCastExprToType(
+ E, Context.getComplexType(Context.LongDoubleTy),
+ CK_FloatingComplexCast)
+ : ImpCastExprToType(E, Context.LongDoubleTy,
+ CK_FloatingCast);
+ break;
+ }
+ }
+
// Half FP have to be promoted to float unless it is natively supported
if (Ty->isHalfType() && !getLangOpts().NativeHalfType)
return ImpCastExprToType(Res.get(), Context.FloatTy, CK_FloatingCast);
@@ -1615,18 +1653,18 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc,
ControllingExpr = R.get();
}
+ bool TypeErrorFound = false,
+ IsResultDependent = ControllingExpr->isTypeDependent(),
+ ContainsUnexpandedParameterPack
+ = ControllingExpr->containsUnexpandedParameterPack();
+
// The controlling expression is an unevaluated operand, so side effects are
// likely unintended.
- if (!inTemplateInstantiation() &&
+ if (!inTemplateInstantiation() && !IsResultDependent &&
ControllingExpr->HasSideEffects(Context, false))
Diag(ControllingExpr->getExprLoc(),
diag::warn_side_effects_unevaluated_context);
- bool TypeErrorFound = false,
- IsResultDependent = ControllingExpr->isTypeDependent(),
- ContainsUnexpandedParameterPack
- = ControllingExpr->containsUnexpandedParameterPack();
-
for (unsigned i = 0; i < NumAssocs; ++i) {
if (Exprs[i]->containsUnexpandedParameterPack())
ContainsUnexpandedParameterPack = true;
@@ -1647,6 +1685,34 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc,
D = diag::err_assoc_type_nonobject;
else if (Types[i]->getType()->isVariablyModifiedType())
D = diag::err_assoc_type_variably_modified;
+ else {
+ // Because the controlling expression undergoes lvalue conversion,
+ // array conversion, and function conversion, an association which is
+ // of array type, function type, or is qualified can never be
+ // reached. We will warn about this so users are less surprised by
+ // the unreachable association. However, we don't have to handle
+ // function types; that's not an object type, so it's handled above.
+ //
+ // The logic is somewhat different for C++ because C++ has different
+ // lvalue to rvalue conversion rules than C. [conv.lvalue]p1 says,
+ // If T is a non-class type, the type of the prvalue is the cv-
+ // unqualified version of T. Otherwise, the type of the prvalue is T.
+ // The result of these rules is that all qualified types in an
+ // association in C are unreachable, and in C++, only qualified non-
+ // class types are unreachable.
+ unsigned Reason = 0;
+ QualType QT = Types[i]->getType();
+ if (QT->isArrayType())
+ Reason = 1;
+ else if (QT.hasQualifiers() &&
+ (!LangOpts.CPlusPlus || !QT->isRecordType()))
+ Reason = 2;
+
+ if (Reason)
+ Diag(Types[i]->getTypeLoc().getBeginLoc(),
+ diag::warn_unreachable_association)
+ << QT << (Reason - 1);
+ }
if (D != 0) {
Diag(Types[i]->getTypeLoc().getBeginLoc(), D)
@@ -1687,10 +1753,14 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc,
SmallVector<unsigned, 1> CompatIndices;
unsigned DefaultIndex = -1U;
+ // Look at the canonical type of the controlling expression in case it was a
+ // deduced type like __auto_type. However, when issuing diagnostics, use the
+ // type the user wrote in source rather than the canonical one.
for (unsigned i = 0; i < NumAssocs; ++i) {
if (!Types[i])
DefaultIndex = i;
- else if (Context.typesAreCompatible(ControllingExpr->getType(),
+ else if (Context.typesAreCompatible(
+ ControllingExpr->getType().getCanonicalType(),
Types[i]->getType()))
CompatIndices.push_back(i);
}
@@ -1797,7 +1867,7 @@ Sema::ActOnStringLiteral(ArrayRef<Token> StringToks, Scope *UDLScope) {
StringTokLocs.push_back(Tok.getLocation());
QualType CharTy = Context.CharTy;
- StringLiteral::StringKind Kind = StringLiteral::Ascii;
+ StringLiteral::StringKind Kind = StringLiteral::Ordinary;
if (Literal.isWide()) {
CharTy = Context.getWideCharType();
Kind = StringLiteral::Wide;
@@ -2515,9 +2585,10 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
if (R.isAmbiguous())
return ExprError();
- // This could be an implicitly declared function reference (legal in C90,
- // extension in C99, forbidden in C++).
- if (R.empty() && HasTrailingLParen && II && !getLangOpts().CPlusPlus) {
+ // This could be an implicitly declared function reference if the language
+ // mode allows it as a feature.
+ if (R.empty() && HasTrailingLParen && II &&
+ getLangOpts().implicitFunctionsAllowed()) {
NamedDecl *D = ImplicitlyDefineFunction(NameLoc, *II, S);
if (D) R.addDecl(D);
}
@@ -3022,7 +3093,7 @@ Sema::PerformObjectMemberConversion(Expr *From,
QualType QType = QualType(Qualifier->getAsType(), 0);
assert(QType->isRecordType() && "lookup done with non-record type");
- QualType QRecordType = QualType(QType->getAs<RecordType>(), 0);
+ QualType QRecordType = QualType(QType->castAs<RecordType>(), 0);
// In C++98, the qualifier type doesn't actually have to be a base
// type of the object type, in which case we just ignore it.
@@ -3194,8 +3265,12 @@ ExprResult Sema::BuildDeclarationNameExpr(
"Cannot refer unambiguously to a function template");
SourceLocation Loc = NameInfo.getLoc();
- if (CheckDeclInExpr(*this, Loc, D))
- return ExprError();
+ if (CheckDeclInExpr(*this, Loc, D)) {
+ // Recovery from invalid cases (e.g. D is an invalid Decl).
+ // We use the dependent type for the RecoveryExpr to prevent bogus follow-up
+ // diagnostics, as invalid decls use int as a fallback type.
+ return CreateRecoveryExpr(NameInfo.getBeginLoc(), NameInfo.getEndLoc(), {});
+ }
if (TemplateDecl *Template = dyn_cast<TemplateDecl>(D)) {
// Specifically diagnose references to class templates that are missing
@@ -3353,7 +3428,7 @@ ExprResult Sema::BuildDeclarationNameExpr(
case Decl::Function: {
if (unsigned BID = cast<FunctionDecl>(VD)->getBuiltinID()) {
- if (!Context.BuiltinInfo.isPredefinedLibFunction(BID)) {
+ if (!Context.BuiltinInfo.isDirectlyAddressable(BID)) {
type = Context.BuiltinFnTy;
valueKind = VK_PRValue;
break;
@@ -3401,6 +3476,10 @@ ExprResult Sema::BuildDeclarationNameExpr(
valueKind = VK_LValue;
break;
+ case Decl::UnnamedGlobalConstant:
+ valueKind = VK_LValue;
+ break;
+
case Decl::CXXMethod:
// If we're referring to a method with an __unknown_anytype
// result type, make the entire expression __unknown_anytype.
@@ -3489,7 +3568,7 @@ ExprResult Sema::BuildPredefinedExpr(SourceLocation Loc,
ResTy = Context.getConstantArrayType(ResTy, LengthI, nullptr,
ArrayType::Normal,
/*IndexTypeQuals*/ 0);
- SL = StringLiteral::Create(Context, Str, StringLiteral::Ascii,
+ SL = StringLiteral::Create(Context, Str, StringLiteral::Ordinary,
/*Pascal*/ false, ResTy, Loc);
}
}
@@ -3551,6 +3630,8 @@ ExprResult Sema::ActOnCharacterConstant(const Token &Tok, Scope *UDLScope) {
QualType Ty;
if (Literal.isWide())
Ty = Context.WideCharTy; // L'x' -> wchar_t in C and C++.
+ else if (Literal.isUTF8() && getLangOpts().C2x)
+ Ty = Context.UnsignedCharTy; // u8'x' -> unsigned char in C2x
else if (Literal.isUTF8() && getLangOpts().Char8)
Ty = Context.Char8Ty; // u8'x' -> char8_t when it exists.
else if (Literal.isUTF16())
@@ -3560,7 +3641,8 @@ ExprResult Sema::ActOnCharacterConstant(const Token &Tok, Scope *UDLScope) {
else if (!getLangOpts().CPlusPlus || Literal.isMultiChar())
Ty = Context.IntTy; // 'x' -> int in C, 'wxyz' -> int in C++.
else
- Ty = Context.CharTy; // 'x' -> char in C++
+ Ty = Context.CharTy; // 'x' -> char in C++;
+ // u8'x' -> char in C11-C17 and in C++ without char8_t.
CharacterLiteral::CharacterKind Kind = CharacterLiteral::Ascii;
if (Literal.isWide())
@@ -3752,9 +3834,10 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
QualType StrTy = Context.getConstantArrayType(
Context.adjustStringLiteralBaseType(Context.CharTy.withConst()),
llvm::APInt(32, Length + 1), nullptr, ArrayType::Normal, 0);
- Expr *Lit = StringLiteral::Create(
- Context, StringRef(TokSpelling.data(), Length), StringLiteral::Ascii,
- /*Pascal*/false, StrTy, &TokLoc, 1);
+ Expr *Lit =
+ StringLiteral::Create(Context, StringRef(TokSpelling.data(), Length),
+ StringLiteral::Ordinary,
+ /*Pascal*/ false, StrTy, &TokLoc, 1);
return BuildLiteralOperatorCall(R, OpNameInfo, Lit, TokLoc);
}
@@ -3884,9 +3967,27 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
: diag::ext_cxx2b_size_t_suffix
: diag::err_cxx2b_size_t_suffix);
- // Get the value in the widest-possible width.
- unsigned MaxWidth = Context.getTargetInfo().getIntMaxTWidth();
- llvm::APInt ResultVal(MaxWidth, 0);
+ // 'wb/uwb' literals are a C2x feature. We support _BitInt as a type in C++,
+ // but we do not currently support the suffix in C++ mode because it's not
+ // entirely clear whether WG21 will prefer this suffix to return a library
+ // type such as std::bit_int instead of returning a _BitInt.
+ if (Literal.isBitInt && !getLangOpts().CPlusPlus)
+ PP.Diag(Tok.getLocation(), getLangOpts().C2x
+ ? diag::warn_c2x_compat_bitint_suffix
+ : diag::ext_c2x_bitint_suffix);
+
+ // Get the value in the widest-possible width. What is "widest" depends on
+ // whether the literal is a bit-precise integer or not. For a bit-precise
+ // integer type, try to scan the source to determine how many bits are
+ // needed to represent the value. This may seem a bit expensive, but trying
+ // to get the integer value from an overly-wide APInt is *extremely*
+ // expensive, so the naive approach of assuming
+ // llvm::IntegerType::MAX_INT_BITS is a big performance hit.
+ unsigned BitsNeeded =
+ Literal.isBitInt ? llvm::APInt::getSufficientBitsNeeded(
+ Literal.getLiteralDigits(), Literal.getRadix())
+ : Context.getTargetInfo().getIntMaxTWidth();
+ llvm::APInt ResultVal(BitsNeeded, 0);
if (Literal.GetIntegerValue(ResultVal)) {
// If this value didn't fit into uintmax_t, error and force to ull.
@@ -3918,6 +4019,32 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
}
}
+ // Bit-precise integer literals are automagically-sized based on the
+ // width required by the literal.
+ if (Literal.isBitInt) {
+ // The signed version has one more bit for the sign value. There are no
+ // zero-width bit-precise integers, even if the literal value is 0.
+ Width = std::max(ResultVal.getActiveBits(), 1u) +
+ (Literal.isUnsigned ? 0u : 1u);
+
+ // Diagnose if the width of the constant is larger than BITINT_MAXWIDTH,
+ // and reset the type to the largest supported width.
+ unsigned int MaxBitIntWidth =
+ Context.getTargetInfo().getMaxBitIntWidth();
+ if (Width > MaxBitIntWidth) {
+ Diag(Tok.getLocation(), diag::err_integer_literal_too_large)
+ << Literal.isUnsigned;
+ Width = MaxBitIntWidth;
+ }
+
+ // Reset the result value to the smaller APInt and select the correct
+ // type to be used. Note, we zext even for signed values because the
+ // literal itself is always an unsigned value (a preceeding - is a
+ // unary operator, not part of the literal).
+ ResultVal = ResultVal.zextOrTrunc(Width);
+ Ty = Context.getBitIntType(Literal.isUnsigned, Width);
+ }
+
// Check C++2b size_t literals.
if (Literal.isSizeT) {
assert(!Literal.MicrosoftInteger &&
@@ -4151,6 +4278,7 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E,
// FIXME: Should we consider instantiation-dependent operands to 'alignof'?
if (IsUnevaluatedOperand && !inTemplateInstantiation() &&
!E->isInstantiationDependent() &&
+ !E->getType()->isVariableArrayType() &&
E->HasSideEffects(Context, false))
Diag(E->getExprLoc(), diag::warn_side_effects_unevaluated_context);
@@ -4431,6 +4559,7 @@ static void captureVariablyModifiedType(ASTContext &Context, QualType T,
case Type::TypeOf:
case Type::UnaryTransform:
case Type::Attributed:
+ case Type::BTFTagAttributed:
case Type::SubstTemplateTypeParm:
case Type::MacroQualified:
// Keep walking after single level desugaring.
@@ -4681,19 +4810,24 @@ static QualType getDependentArraySubscriptType(Expr *LHS, Expr *RHS,
return Result->isDependentType() ? Result : Ctx.DependentTy;
}
-ExprResult
-Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc,
- Expr *idx, SourceLocation rbLoc) {
+static bool checkArgsForPlaceholders(Sema &S, MultiExprArg args);
+
+ExprResult Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base,
+ SourceLocation lbLoc,
+ MultiExprArg ArgExprs,
+ SourceLocation rbLoc) {
+
if (base && !base->getType().isNull() &&
base->hasPlaceholderType(BuiltinType::OMPArraySection))
- return ActOnOMPArraySectionExpr(base, lbLoc, idx, SourceLocation(),
+ return ActOnOMPArraySectionExpr(base, lbLoc, ArgExprs.front(), SourceLocation(),
SourceLocation(), /*Length*/ nullptr,
/*Stride=*/nullptr, rbLoc);
// Since this might be a postfix expression, get rid of ParenListExprs.
if (isa<ParenListExpr>(base)) {
ExprResult result = MaybeConvertParenListExprToParenExpr(S, base);
- if (result.isInvalid()) return ExprError();
+ if (result.isInvalid())
+ return ExprError();
base = result.get();
}
@@ -4721,13 +4855,15 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc,
// MatrixSubscriptExpr.
auto *matSubscriptE = dyn_cast<MatrixSubscriptExpr>(base);
if (matSubscriptE) {
- if (CheckAndReportCommaError(idx))
+ assert(ArgExprs.size() == 1);
+ if (CheckAndReportCommaError(ArgExprs.front()))
return ExprError();
assert(matSubscriptE->isIncomplete() &&
"base has to be an incomplete matrix subscript");
- return CreateBuiltinMatrixSubscriptExpr(
- matSubscriptE->getBase(), matSubscriptE->getRowIdx(), idx, rbLoc);
+ return CreateBuiltinMatrixSubscriptExpr(matSubscriptE->getBase(),
+ matSubscriptE->getRowIdx(),
+ ArgExprs.front(), rbLoc);
}
// Handle any non-overload placeholder types in the base and index
@@ -4748,32 +4884,42 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc,
// If the base is a matrix type, try to create a new MatrixSubscriptExpr.
if (base->getType()->isMatrixType()) {
- if (CheckAndReportCommaError(idx))
+ assert(ArgExprs.size() == 1);
+ if (CheckAndReportCommaError(ArgExprs.front()))
return ExprError();
- return CreateBuiltinMatrixSubscriptExpr(base, idx, nullptr, rbLoc);
+ return CreateBuiltinMatrixSubscriptExpr(base, ArgExprs.front(), nullptr,
+ rbLoc);
}
- // A comma-expression as the index is deprecated in C++2a onwards.
- if (getLangOpts().CPlusPlus20 &&
- ((isa<BinaryOperator>(idx) && cast<BinaryOperator>(idx)->isCommaOp()) ||
- (isa<CXXOperatorCallExpr>(idx) &&
- cast<CXXOperatorCallExpr>(idx)->getOperator() == OO_Comma))) {
- Diag(idx->getExprLoc(), diag::warn_deprecated_comma_subscript)
- << SourceRange(base->getBeginLoc(), rbLoc);
+ if (ArgExprs.size() == 1 && getLangOpts().CPlusPlus20) {
+ Expr *idx = ArgExprs[0];
+ if ((isa<BinaryOperator>(idx) && cast<BinaryOperator>(idx)->isCommaOp()) ||
+ (isa<CXXOperatorCallExpr>(idx) &&
+ cast<CXXOperatorCallExpr>(idx)->getOperator() == OO_Comma)) {
+ Diag(idx->getExprLoc(), diag::warn_deprecated_comma_subscript)
+ << SourceRange(base->getBeginLoc(), rbLoc);
+ }
}
- if (idx->getType()->isNonOverloadPlaceholderType()) {
- ExprResult result = CheckPlaceholderExpr(idx);
- if (result.isInvalid()) return ExprError();
- idx = result.get();
+ if (ArgExprs.size() == 1 &&
+ ArgExprs[0]->getType()->isNonOverloadPlaceholderType()) {
+ ExprResult result = CheckPlaceholderExpr(ArgExprs[0]);
+ if (result.isInvalid())
+ return ExprError();
+ ArgExprs[0] = result.get();
+ } else {
+ if (checkArgsForPlaceholders(*this, ArgExprs))
+ return ExprError();
}
// Build an unanalyzed expression if either operand is type-dependent.
- if (getLangOpts().CPlusPlus &&
- (base->isTypeDependent() || idx->isTypeDependent())) {
+ if (getLangOpts().CPlusPlus && ArgExprs.size() == 1 &&
+ (base->isTypeDependent() ||
+ Expr::hasAnyTypeDependentArguments(ArgExprs))) {
return new (Context) ArraySubscriptExpr(
- base, idx, getDependentArraySubscriptType(base, idx, getASTContext()),
+ base, ArgExprs.front(),
+ getDependentArraySubscriptType(base, ArgExprs.front(), getASTContext()),
VK_LValue, OK_Ordinary, rbLoc);
}
@@ -4786,10 +4932,12 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc,
// indices. In this case, i=p->x[a][b] will be turned into i=p->GetX(a, b),
// and p->x[a][b] = i will be turned into p->PutX(a, b, i);
if (IsMSPropertySubscript) {
+ assert(ArgExprs.size() == 1);
// Build MS property subscript expression if base is MS property reference
// or MS property subscript.
- return new (Context) MSPropertySubscriptExpr(
- base, idx, Context.PseudoObjectTy, VK_LValue, OK_Ordinary, rbLoc);
+ return new (Context)
+ MSPropertySubscriptExpr(base, ArgExprs.front(), Context.PseudoObjectTy,
+ VK_LValue, OK_Ordinary, rbLoc);
}
// Use C++ overloaded-operator rules if either operand has record
@@ -4800,14 +4948,14 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc,
//
// ObjC pointers have their own subscripting logic that is not tied
// to overload resolution and so should not take this path.
- if (getLangOpts().CPlusPlus &&
- (base->getType()->isRecordType() ||
- (!base->getType()->isObjCObjectPointerType() &&
- idx->getType()->isRecordType()))) {
- return CreateOverloadedArraySubscriptExpr(lbLoc, rbLoc, base, idx);
+ if (getLangOpts().CPlusPlus && !base->getType()->isObjCObjectPointerType() &&
+ ((base->getType()->isRecordType() ||
+ (ArgExprs.size() != 1 || ArgExprs[0]->getType()->isRecordType())))) {
+ return CreateOverloadedArraySubscriptExpr(lbLoc, rbLoc, base, ArgExprs);
}
- ExprResult Res = CreateBuiltinArraySubscriptExpr(base, lbLoc, idx, rbLoc);
+ ExprResult Res =
+ CreateBuiltinArraySubscriptExpr(base, lbLoc, ArgExprs.front(), rbLoc);
if (!Res.isInvalid() && isa<ArraySubscriptExpr>(Res.get()))
CheckSubscriptAccessOfNoDeref(cast<ArraySubscriptExpr>(Res.get()));
@@ -5581,6 +5729,33 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
Qualifiers Combined = BaseQuals + MemberQuals;
if (Combined != MemberQuals)
ResultType = Context.getQualifiedType(ResultType, Combined);
+ } else if (LHSTy->isBuiltinType() &&
+ LHSTy->getAs<BuiltinType>()->isVLSTBuiltinType()) {
+ const BuiltinType *BTy = LHSTy->getAs<BuiltinType>();
+ if (BTy->isSVEBool())
+ return ExprError(Diag(LLoc, diag::err_subscript_svbool_t)
+ << LHSExp->getSourceRange() << RHSExp->getSourceRange());
+
+ BaseExpr = LHSExp;
+ IndexExpr = RHSExp;
+ if (getLangOpts().CPlusPlus11 && LHSExp->isPRValue()) {
+ ExprResult Materialized = TemporaryMaterializationConversion(LHSExp);
+ if (Materialized.isInvalid())
+ return ExprError();
+ LHSExp = Materialized.get();
+ }
+ VK = LHSExp->getValueKind();
+ if (VK != VK_PRValue)
+ OK = OK_VectorComponent;
+
+ ResultType = BTy->getSveEltType(Context);
+
+ QualType BaseType = BaseExpr->getType();
+ Qualifiers BaseQuals = BaseType.getQualifiers();
+ Qualifiers MemberQuals = ResultType.getQualifiers();
+ Qualifiers Combined = BaseQuals + MemberQuals;
+ if (Combined != MemberQuals)
+ ResultType = Context.getQualifiedType(ResultType, Combined);
} else if (LHSTy->isArrayType()) {
// If we see an array that wasn't promoted by
// DefaultFunctionArrayLvalueConversion, it must be an array that
@@ -6397,6 +6572,37 @@ tryImplicitlyCaptureThisIfImplicitMemberFunctionAccessWithDependentArgs(
}
}
+// Once a call is fully resolved, warn for unqualified calls to specific
+// C++ standard functions, like move and forward.
+static void DiagnosedUnqualifiedCallsToStdFunctions(Sema &S, CallExpr *Call) {
+ // We are only checking unary move and forward so exit early here.
+ if (Call->getNumArgs() != 1)
+ return;
+
+ Expr *E = Call->getCallee()->IgnoreParenImpCasts();
+ if (!E || isa<UnresolvedLookupExpr>(E))
+ return;
+ DeclRefExpr *DRE = dyn_cast_or_null<DeclRefExpr>(E);
+ if (!DRE || !DRE->getLocation().isValid())
+ return;
+
+ if (DRE->getQualifier())
+ return;
+
+ const FunctionDecl *FD = Call->getDirectCallee();
+ if (!FD)
+ return;
+
+ // Only warn for some functions deemed more frequent or problematic.
+ unsigned BuiltinID = FD->getBuiltinID();
+ if (BuiltinID != Builtin::BImove && BuiltinID != Builtin::BIforward)
+ return;
+
+ S.Diag(DRE->getLocation(), diag::warn_unqualified_call_to_std_cast_function)
+ << FD->getQualifiedNameAsString()
+ << FixItHint::CreateInsertion(DRE->getLocation(), "std::");
+}
+
ExprResult Sema::ActOnCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
MultiExprArg ArgExprs, SourceLocation RParenLoc,
Expr *ExecConfig) {
@@ -6421,7 +6627,11 @@ ExprResult Sema::ActOnCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
if (LangOpts.OpenMP)
Call = ActOnOpenMPCall(Call, Scope, LParenLoc, ArgExprs, RParenLoc,
ExecConfig);
-
+ if (LangOpts.CPlusPlus) {
+ CallExpr *CE = dyn_cast<CallExpr>(Call.get());
+ if (CE)
+ DiagnosedUnqualifiedCallsToStdFunctions(*this, CE);
+ }
return Call;
}
@@ -6582,9 +6792,9 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
auto ArgAS = ArgPtTy.getAddressSpace();
// Add address space cast if target address spaces are different
- bool NeedImplicitASC =
+ bool NeedImplicitASC =
ParamAS != LangAS::Default && // Pointer params in generic AS don't need special handling.
- ( ArgAS == LangAS::Default || // We do allow implicit conversion from generic AS
+ ( ArgAS == LangAS::Default || // We do allow implicit conversion from generic AS
// or from specific AS which has target AS matching that of Param.
getASTContext().getTargetAddressSpace(ArgAS) == getASTContext().getTargetAddressSpace(ParamAS));
if (!NeedImplicitASC)
@@ -6903,6 +7113,23 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
Proto = FDecl->getType()->getAs<FunctionProtoType>();
}
+ // If we still haven't found a prototype to use but there are arguments to
+ // the call, diagnose this as calling a function without a prototype.
+ // However, if we found a function declaration, check to see if
+ // -Wdeprecated-non-prototype was disabled where the function was declared.
+ // If so, we will silence the diagnostic here on the assumption that this
+ // interface is intentional and the user knows what they're doing. We will
+ // also silence the diagnostic if there is a function declaration but it
+ // was implicitly defined (the user already gets diagnostics about the
+ // creation of the implicit function declaration, so the additional warning
+ // is not helpful).
+ if (!Proto && !Args.empty() &&
+ (!FDecl || (!FDecl->isImplicit() &&
+ !Diags.isIgnored(diag::warn_strict_uses_without_prototype,
+ FDecl->getLocation()))))
+ Diag(LParenLoc, diag::warn_strict_uses_without_prototype)
+ << (FDecl != nullptr) << FDecl;
+
// Promote the arguments (C99 6.5.2.2p6).
for (unsigned i = 0, e = Args.size(); i != e; i++) {
Expr *Arg = Args[i];
@@ -7507,6 +7734,36 @@ bool Sema::areVectorTypesSameSize(QualType SrcTy, QualType DestTy) {
return (SrcLen * SrcEltSize == DestLen * DestEltSize);
}
+// This returns true if at least one of the types is an altivec vector.
+bool Sema::anyAltivecTypes(QualType SrcTy, QualType DestTy) {
+ assert((DestTy->isVectorType() || SrcTy->isVectorType()) &&
+ "expected at least one type to be a vector here");
+
+ bool IsSrcTyAltivec =
+ SrcTy->isVectorType() && (SrcTy->castAs<VectorType>()->getVectorKind() ==
+ VectorType::AltiVecVector);
+ bool IsDestTyAltivec = DestTy->isVectorType() &&
+ (DestTy->castAs<VectorType>()->getVectorKind() ==
+ VectorType::AltiVecVector);
+
+ return (IsSrcTyAltivec || IsDestTyAltivec);
+}
+
+// This returns true if both vectors have the same element type.
+bool Sema::areSameVectorElemTypes(QualType SrcTy, QualType DestTy) {
+ assert((DestTy->isVectorType() || SrcTy->isVectorType()) &&
+ "expected at least one type to be a vector here");
+
+ uint64_t SrcLen, DestLen;
+ QualType SrcEltTy, DestEltTy;
+ if (!breakDownVectorType(SrcTy, SrcLen, SrcEltTy))
+ return false;
+ if (!breakDownVectorType(DestTy, DestLen, DestEltTy))
+ return false;
+
+ return (SrcEltTy == DestEltTy);
+}
+
/// Are the two types lax-compatible vector types? That is, given
/// that one of them is a vector, do they have equal storage sizes,
/// where the storage size is the number of elements times the element
@@ -8316,11 +8573,17 @@ OpenCLCheckVectorConditional(Sema &S, ExprResult &Cond,
// result as specified in OpenCL v1.1 s6.3.i.
if (LHS.get()->getType()->isVectorType() ||
RHS.get()->getType()->isVectorType()) {
- QualType VecResTy = S.CheckVectorOperands(LHS, RHS, QuestionLoc,
- /*isCompAssign*/false,
- /*AllowBothBool*/true,
- /*AllowBoolConversions*/false);
- if (VecResTy.isNull()) return QualType();
+ bool IsBoolVecLang =
+ !S.getLangOpts().OpenCL && !S.getLangOpts().OpenCLCPlusPlus;
+ QualType VecResTy =
+ S.CheckVectorOperands(LHS, RHS, QuestionLoc,
+ /*isCompAssign*/ false,
+ /*AllowBothBool*/ true,
+ /*AllowBoolConversions*/ false,
+ /*AllowBooleanOperation*/ IsBoolVecLang,
+ /*ReportInvalid*/ true);
+ if (VecResTy.isNull())
+ return QualType();
// The result type must match the condition type as specified in
// OpenCL v1.1 s6.11.6.
if (checkVectorResult(S, CondTy, VecResTy, QuestionLoc))
@@ -8393,9 +8656,11 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
// Now check the two expressions.
if (LHS.get()->getType()->isVectorType() ||
RHS.get()->getType()->isVectorType())
- return CheckVectorOperands(LHS, RHS, QuestionLoc, /*isCompAssign*/false,
- /*AllowBothBool*/true,
- /*AllowBoolConversions*/false);
+ return CheckVectorOperands(LHS, RHS, QuestionLoc, /*isCompAssign*/ false,
+ /*AllowBothBool*/ true,
+ /*AllowBoolConversions*/ false,
+ /*AllowBooleanOperation*/ false,
+ /*ReportInvalid*/ true);
QualType ResTy =
UsualArithmeticConversions(LHS, RHS, QuestionLoc, ACK_Conditional);
@@ -9253,6 +9518,15 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
return Compatible;
}
+ // If the LHS has an __auto_type, there are no additional type constraints
+ // to be worried about.
+ if (const auto *AT = dyn_cast<AutoType>(LHSType)) {
+ if (AT->isGNUAutoType()) {
+ Kind = CK_NoOp;
+ return Compatible;
+ }
+ }
+
// If we have an atomic type, try a non-atomic assignment, then just add an
// atomic qualification step.
if (const AtomicType *AtomicTy = dyn_cast<AtomicType>(LHSType)) {
@@ -9309,6 +9583,13 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
// vectors, the total size only needs to be the same. This is a bitcast;
// no bits are changed but the result type is different.
if (isLaxVectorConversion(RHSType, LHSType)) {
+ // The default for lax vector conversions with Altivec vectors will
+ // change, so if we are converting between vector types where
+ // at least one is an Altivec vector, emit a warning.
+ if (anyAltivecTypes(RHSType, LHSType) &&
+ !areSameVectorElemTypes(RHSType, LHSType))
+ Diag(RHS.get()->getExprLoc(), diag::warn_deprecated_lax_vec_conv_all)
+ << RHSType << LHSType;
Kind = CK_BitCast;
return IncompatibleVectors;
}
@@ -9322,6 +9603,9 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
const VectorType *VecType = RHSType->getAs<VectorType>();
if (VecType && VecType->getNumElements() == 1 &&
isLaxVectorConversion(RHSType, LHSType)) {
+ if (VecType->getVectorKind() == VectorType::AltiVecVector)
+ Diag(RHS.get()->getExprLoc(), diag::warn_deprecated_lax_vec_conv_all)
+ << RHSType << LHSType;
ExprResult *VecExpr = &RHS;
*VecExpr = ImpCastExprToType(VecExpr->get(), LHSType, CK_BitCast);
Kind = CK_BitCast;
@@ -9914,9 +10198,11 @@ static bool tryVectorConvertAndSplat(Sema &S, ExprResult *scalar,
static ExprResult convertVector(Expr *E, QualType ElementType, Sema &S) {
const auto *VecTy = E->getType()->getAs<VectorType>();
assert(VecTy && "Expression E must be a vector");
- QualType NewVecTy = S.Context.getVectorType(ElementType,
- VecTy->getNumElements(),
- VecTy->getVectorKind());
+ QualType NewVecTy =
+ VecTy->isExtVectorType()
+ ? S.Context.getExtVectorType(ElementType, VecTy->getNumElements())
+ : S.Context.getVectorType(ElementType, VecTy->getNumElements(),
+ VecTy->getVectorKind());
// Look through the implicit cast. Return the subexpression if its type is
// NewVecTy.
@@ -10016,12 +10302,18 @@ static bool tryGCCVectorConvertAndSplat(Sema &S, ExprResult *Scalar,
ExprResult *Vector) {
QualType ScalarTy = Scalar->get()->getType().getUnqualifiedType();
QualType VectorTy = Vector->get()->getType().getUnqualifiedType();
- const VectorType *VT = VectorTy->getAs<VectorType>();
-
- assert(!isa<ExtVectorType>(VT) &&
- "ExtVectorTypes should not be handled here!");
-
- QualType VectorEltTy = VT->getElementType();
+ QualType VectorEltTy;
+
+ if (const auto *VT = VectorTy->getAs<VectorType>()) {
+ assert(!isa<ExtVectorType>(VT) &&
+ "ExtVectorTypes should not be handled here!");
+ VectorEltTy = VT->getElementType();
+ } else if (VectorTy->isVLSTBuiltinType()) {
+ VectorEltTy =
+ VectorTy->castAs<BuiltinType>()->getSveEltType(S.getASTContext());
+ } else {
+ llvm_unreachable("Only Fixed-Length and SVE Vector types are handled here");
+ }
// Reject cases where the vector element type or the scalar element type are
// not integral or floating point types.
@@ -10103,7 +10395,9 @@ static bool tryGCCVectorConvertAndSplat(Sema &S, ExprResult *Scalar,
QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc, bool IsCompAssign,
bool AllowBothBool,
- bool AllowBoolConversions) {
+ bool AllowBoolConversions,
+ bool AllowBoolOperation,
+ bool ReportInvalid) {
if (!IsCompAssign) {
LHS = DefaultFunctionArrayLvalueConversion(LHS.get());
if (LHS.isInvalid())
@@ -10124,14 +10418,19 @@ QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS,
if ((LHSVecType && LHSVecType->getElementType()->isBFloat16Type()) ||
(RHSVecType && RHSVecType->getElementType()->isBFloat16Type()))
- return InvalidOperands(Loc, LHS, RHS);
+ return ReportInvalid ? InvalidOperands(Loc, LHS, RHS) : QualType();
// AltiVec-style "vector bool op vector bool" combinations are allowed
// for some operators but not others.
if (!AllowBothBool &&
LHSVecType && LHSVecType->getVectorKind() == VectorType::AltiVecBool &&
RHSVecType && RHSVecType->getVectorKind() == VectorType::AltiVecBool)
- return InvalidOperands(Loc, LHS, RHS);
+ return ReportInvalid ? InvalidOperands(Loc, LHS, RHS) : QualType();
+
+ // This operation may not be performed on boolean vectors.
+ if (!AllowBoolOperation &&
+ (LHSType->isExtVectorBoolType() || RHSType->isExtVectorBoolType()))
+ return ReportInvalid ? InvalidOperands(Loc, LHS, RHS) : QualType();
// If the vector types are identical, return.
if (Context.hasSameType(LHSType, RHSType))
@@ -10245,6 +10544,9 @@ QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS,
QualType OtherType = LHSVecType ? RHSType : LHSType;
ExprResult *OtherExpr = LHSVecType ? &RHS : &LHS;
if (isLaxVectorConversion(OtherType, VecType)) {
+ if (anyAltivecTypes(RHSType, LHSType) &&
+ !areSameVectorElemTypes(RHSType, LHSType))
+ Diag(Loc, diag::warn_deprecated_lax_vec_conv_all) << RHSType << LHSType;
// If we're allowing lax vector conversions, only the total (data) size
// needs to be the same. For non compound assignment, if one of the types is
// scalar, the result is always the vector type.
@@ -10310,6 +10612,81 @@ QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS,
return QualType();
}
+QualType Sema::CheckSizelessVectorOperands(ExprResult &LHS, ExprResult &RHS,
+ SourceLocation Loc,
+ bool IsCompAssign,
+ ArithConvKind OperationKind) {
+ if (!IsCompAssign) {
+ LHS = DefaultFunctionArrayLvalueConversion(LHS.get());
+ if (LHS.isInvalid())
+ return QualType();
+ }
+ RHS = DefaultFunctionArrayLvalueConversion(RHS.get());
+ if (RHS.isInvalid())
+ return QualType();
+
+ QualType LHSType = LHS.get()->getType().getUnqualifiedType();
+ QualType RHSType = RHS.get()->getType().getUnqualifiedType();
+
+ const BuiltinType *LHSBuiltinTy = LHSType->getAs<BuiltinType>();
+ const BuiltinType *RHSBuiltinTy = RHSType->getAs<BuiltinType>();
+
+ unsigned DiagID = diag::err_typecheck_invalid_operands;
+ if ((OperationKind == ACK_Arithmetic) &&
+ ((LHSBuiltinTy && LHSBuiltinTy->isSVEBool()) ||
+ (RHSBuiltinTy && RHSBuiltinTy->isSVEBool()))) {
+ Diag(Loc, DiagID) << LHSType << RHSType << LHS.get()->getSourceRange()
+ << RHS.get()->getSourceRange();
+ return QualType();
+ }
+
+ if (Context.hasSameType(LHSType, RHSType))
+ return LHSType;
+
+ if (LHSType->isVLSTBuiltinType() && !RHSType->isVLSTBuiltinType()) {
+ if (!tryGCCVectorConvertAndSplat(*this, &RHS, &LHS))
+ return LHSType;
+ }
+ if (RHSType->isVLSTBuiltinType() && !LHSType->isVLSTBuiltinType()) {
+ if (LHS.get()->isLValue() ||
+ !tryGCCVectorConvertAndSplat(*this, &LHS, &RHS))
+ return RHSType;
+ }
+
+ if ((!LHSType->isVLSTBuiltinType() && !LHSType->isRealType()) ||
+ (!RHSType->isVLSTBuiltinType() && !RHSType->isRealType())) {
+ Diag(Loc, diag::err_typecheck_vector_not_convertable_non_scalar)
+ << LHSType << RHSType << LHS.get()->getSourceRange()
+ << RHS.get()->getSourceRange();
+ return QualType();
+ }
+
+ if (LHSType->isVLSTBuiltinType() && RHSType->isVLSTBuiltinType() &&
+ Context.getBuiltinVectorTypeInfo(LHSBuiltinTy).EC !=
+ Context.getBuiltinVectorTypeInfo(RHSBuiltinTy).EC) {
+ Diag(Loc, diag::err_typecheck_vector_lengths_not_equal)
+ << LHSType << RHSType << LHS.get()->getSourceRange()
+ << RHS.get()->getSourceRange();
+ return QualType();
+ }
+
+ if (LHSType->isVLSTBuiltinType() || RHSType->isVLSTBuiltinType()) {
+ QualType Scalar = LHSType->isVLSTBuiltinType() ? RHSType : LHSType;
+ QualType Vector = LHSType->isVLSTBuiltinType() ? LHSType : RHSType;
+ bool ScalarOrVector =
+ LHSType->isVLSTBuiltinType() && RHSType->isVLSTBuiltinType();
+
+ Diag(Loc, diag::err_typecheck_vector_not_convertable_implict_truncation)
+ << ScalarOrVector << Scalar << Vector;
+
+ return QualType();
+ }
+
+ Diag(Loc, DiagID) << LHSType << RHSType << LHS.get()->getSourceRange()
+ << RHS.get()->getSourceRange();
+ return QualType();
+}
+
// checkArithmeticNull - Detect when a NULL constant is used improperly in an
// expression. These are mainly cases where the null pointer is used as an
// integer instead of a pointer.
@@ -10419,8 +10796,13 @@ QualType Sema::CheckMultiplyDivideOperands(ExprResult &LHS, ExprResult &RHS,
QualType RHSTy = RHS.get()->getType();
if (LHSTy->isVectorType() || RHSTy->isVectorType())
return CheckVectorOperands(LHS, RHS, Loc, IsCompAssign,
- /*AllowBothBool*/getLangOpts().AltiVec,
- /*AllowBoolConversions*/false);
+ /*AllowBothBool*/ getLangOpts().AltiVec,
+ /*AllowBoolConversions*/ false,
+ /*AllowBooleanOperation*/ false,
+ /*ReportInvalid*/ true);
+ if (LHSTy->isVLSTBuiltinType() || RHSTy->isVLSTBuiltinType())
+ return CheckSizelessVectorOperands(LHS, RHS, Loc, IsCompAssign,
+ ACK_Arithmetic);
if (!IsDiv &&
(LHSTy->isConstantMatrixType() || RHSTy->isConstantMatrixType()))
return CheckMatrixMultiplyOperands(LHS, RHS, Loc, IsCompAssign);
@@ -10453,8 +10835,20 @@ QualType Sema::CheckRemainderOperands(
if (LHS.get()->getType()->hasIntegerRepresentation() &&
RHS.get()->getType()->hasIntegerRepresentation())
return CheckVectorOperands(LHS, RHS, Loc, IsCompAssign,
- /*AllowBothBool*/getLangOpts().AltiVec,
- /*AllowBoolConversions*/false);
+ /*AllowBothBool*/ getLangOpts().AltiVec,
+ /*AllowBoolConversions*/ false,
+ /*AllowBooleanOperation*/ false,
+ /*ReportInvalid*/ true);
+ return InvalidOperands(Loc, LHS, RHS);
+ }
+
+ if (LHS.get()->getType()->isVLSTBuiltinType() ||
+ RHS.get()->getType()->isVLSTBuiltinType()) {
+ if (LHS.get()->getType()->hasIntegerRepresentation() &&
+ RHS.get()->getType()->hasIntegerRepresentation())
+ return CheckSizelessVectorOperands(LHS, RHS, Loc, IsCompAssign,
+ ACK_Arithmetic);
+
return InvalidOperands(Loc, LHS, RHS);
}
@@ -10515,8 +10909,10 @@ static void diagnoseSubtractionOnNullPointer(Sema &S, SourceLocation Loc,
if (S.Diags.getSuppressSystemWarnings() && S.SourceMgr.isInSystemMacro(Loc))
return;
- S.Diag(Loc, diag::warn_pointer_sub_null_ptr)
- << S.getLangOpts().CPlusPlus << Pointer->getSourceRange();
+ S.DiagRuntimeBehavior(Loc, Pointer,
+ S.PDiag(diag::warn_pointer_sub_null_ptr)
+ << S.getLangOpts().CPlusPlus
+ << Pointer->getSourceRange());
}
/// Diagnose invalid arithmetic on two function pointers.
@@ -10755,14 +11151,25 @@ QualType Sema::CheckAdditionOperands(ExprResult &LHS, ExprResult &RHS,
if (LHS.get()->getType()->isVectorType() ||
RHS.get()->getType()->isVectorType()) {
- QualType compType = CheckVectorOperands(
- LHS, RHS, Loc, CompLHSTy,
- /*AllowBothBool*/getLangOpts().AltiVec,
- /*AllowBoolConversions*/getLangOpts().ZVector);
+ QualType compType =
+ CheckVectorOperands(LHS, RHS, Loc, CompLHSTy,
+ /*AllowBothBool*/ getLangOpts().AltiVec,
+ /*AllowBoolConversions*/ getLangOpts().ZVector,
+ /*AllowBooleanOperation*/ false,
+ /*ReportInvalid*/ true);
if (CompLHSTy) *CompLHSTy = compType;
return compType;
}
+ if (LHS.get()->getType()->isVLSTBuiltinType() ||
+ RHS.get()->getType()->isVLSTBuiltinType()) {
+ QualType compType =
+ CheckSizelessVectorOperands(LHS, RHS, Loc, CompLHSTy, ACK_Arithmetic);
+ if (CompLHSTy)
+ *CompLHSTy = compType;
+ return compType;
+ }
+
if (LHS.get()->getType()->isConstantMatrixType() ||
RHS.get()->getType()->isConstantMatrixType()) {
QualType compType =
@@ -10859,14 +11266,25 @@ QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS,
if (LHS.get()->getType()->isVectorType() ||
RHS.get()->getType()->isVectorType()) {
- QualType compType = CheckVectorOperands(
- LHS, RHS, Loc, CompLHSTy,
- /*AllowBothBool*/getLangOpts().AltiVec,
- /*AllowBoolConversions*/getLangOpts().ZVector);
+ QualType compType =
+ CheckVectorOperands(LHS, RHS, Loc, CompLHSTy,
+ /*AllowBothBool*/ getLangOpts().AltiVec,
+ /*AllowBoolConversions*/ getLangOpts().ZVector,
+ /*AllowBooleanOperation*/ false,
+ /*ReportInvalid*/ true);
if (CompLHSTy) *CompLHSTy = compType;
return compType;
}
+ if (LHS.get()->getType()->isVLSTBuiltinType() ||
+ RHS.get()->getType()->isVLSTBuiltinType()) {
+ QualType compType =
+ CheckSizelessVectorOperands(LHS, RHS, Loc, CompLHSTy, ACK_Arithmetic);
+ if (CompLHSTy)
+ *CompLHSTy = compType;
+ return compType;
+ }
+
if (LHS.get()->getType()->isConstantMatrixType() ||
RHS.get()->getType()->isConstantMatrixType()) {
QualType compType =
@@ -11042,10 +11460,16 @@ static void DiagnoseBadShiftValues(Sema& S, ExprResult &LHS, ExprResult &RHS,
return;
llvm::APSInt Left = LHSResult.Val.getInt();
- // If LHS does not have a signed type and non-negative value
- // then, the behavior is undefined before C++2a. Warn about it.
- if (Left.isNegative() && !S.getLangOpts().isSignedOverflowDefined() &&
- !S.getLangOpts().CPlusPlus20) {
+ // Don't warn if signed overflow is defined, then all the rest of the
+ // diagnostics will not be triggered because the behavior is defined.
+ // Also don't warn in C++20 mode (and newer), as signed left shifts
+ // always wrap and never overflow.
+ if (S.getLangOpts().isSignedOverflowDefined() || S.getLangOpts().CPlusPlus20)
+ return;
+
+ // If LHS does not have a non-negative value then, the
+ // behavior is undefined before C++2a. Warn about it.
+ if (Left.isNegative()) {
S.DiagRuntimeBehavior(Loc, LHS.get(),
S.PDiag(diag::warn_shift_lhs_negative)
<< LHS.get()->getSourceRange());
@@ -11113,6 +11537,15 @@ static QualType checkVectorShift(Sema &S, ExprResult &LHS, ExprResult &RHS,
const VectorType *RHSVecTy = RHSType->getAs<VectorType>();
QualType RHSEleType = RHSVecTy ? RHSVecTy->getElementType() : RHSType;
+ // Do not allow shifts for boolean vectors.
+ if ((LHSVecTy && LHSVecTy->isExtVectorBoolType()) ||
+ (RHSVecTy && RHSVecTy->isExtVectorBoolType())) {
+ S.Diag(Loc, diag::err_typecheck_invalid_operands)
+ << LHS.get()->getType() << RHS.get()->getType()
+ << LHS.get()->getSourceRange();
+ return QualType();
+ }
+
// The operands need to be integers.
if (!LHSEleType->isIntegerType()) {
S.Diag(Loc, diag::err_typecheck_expect_int)
@@ -11168,6 +11601,97 @@ static QualType checkVectorShift(Sema &S, ExprResult &LHS, ExprResult &RHS,
return LHSType;
}
+static QualType checkSizelessVectorShift(Sema &S, ExprResult &LHS,
+ ExprResult &RHS, SourceLocation Loc,
+ bool IsCompAssign) {
+ if (!IsCompAssign) {
+ LHS = S.UsualUnaryConversions(LHS.get());
+ if (LHS.isInvalid())
+ return QualType();
+ }
+
+ RHS = S.UsualUnaryConversions(RHS.get());
+ if (RHS.isInvalid())
+ return QualType();
+
+ QualType LHSType = LHS.get()->getType();
+ const BuiltinType *LHSBuiltinTy = LHSType->getAs<BuiltinType>();
+ QualType LHSEleType = LHSType->isVLSTBuiltinType()
+ ? LHSBuiltinTy->getSveEltType(S.getASTContext())
+ : LHSType;
+
+ // Note that RHS might not be a vector
+ QualType RHSType = RHS.get()->getType();
+ const BuiltinType *RHSBuiltinTy = RHSType->getAs<BuiltinType>();
+ QualType RHSEleType = RHSType->isVLSTBuiltinType()
+ ? RHSBuiltinTy->getSveEltType(S.getASTContext())
+ : RHSType;
+
+ if ((LHSBuiltinTy && LHSBuiltinTy->isSVEBool()) ||
+ (RHSBuiltinTy && RHSBuiltinTy->isSVEBool())) {
+ S.Diag(Loc, diag::err_typecheck_invalid_operands)
+ << LHSType << RHSType << LHS.get()->getSourceRange();
+ return QualType();
+ }
+
+ if (!LHSEleType->isIntegerType()) {
+ S.Diag(Loc, diag::err_typecheck_expect_int)
+ << LHS.get()->getType() << LHS.get()->getSourceRange();
+ return QualType();
+ }
+
+ if (!RHSEleType->isIntegerType()) {
+ S.Diag(Loc, diag::err_typecheck_expect_int)
+ << RHS.get()->getType() << RHS.get()->getSourceRange();
+ return QualType();
+ }
+
+ if (LHSType->isVLSTBuiltinType() && RHSType->isVLSTBuiltinType() &&
+ (S.Context.getBuiltinVectorTypeInfo(LHSBuiltinTy).EC !=
+ S.Context.getBuiltinVectorTypeInfo(RHSBuiltinTy).EC)) {
+ S.Diag(Loc, diag::err_typecheck_invalid_operands)
+ << LHSType << RHSType << LHS.get()->getSourceRange()
+ << RHS.get()->getSourceRange();
+ return QualType();
+ }
+
+ if (!LHSType->isVLSTBuiltinType()) {
+ assert(RHSType->isVLSTBuiltinType());
+ if (IsCompAssign)
+ return RHSType;
+ if (LHSEleType != RHSEleType) {
+ LHS = S.ImpCastExprToType(LHS.get(), RHSEleType, clang::CK_IntegralCast);
+ LHSEleType = RHSEleType;
+ }
+ const llvm::ElementCount VecSize =
+ S.Context.getBuiltinVectorTypeInfo(RHSBuiltinTy).EC;
+ QualType VecTy =
+ S.Context.getScalableVectorType(LHSEleType, VecSize.getKnownMinValue());
+ LHS = S.ImpCastExprToType(LHS.get(), VecTy, clang::CK_VectorSplat);
+ LHSType = VecTy;
+ } else if (RHSBuiltinTy && RHSBuiltinTy->isVLSTBuiltinType()) {
+ if (S.Context.getTypeSize(RHSBuiltinTy) !=
+ S.Context.getTypeSize(LHSBuiltinTy)) {
+ S.Diag(Loc, diag::err_typecheck_vector_lengths_not_equal)
+ << LHSType << RHSType << LHS.get()->getSourceRange()
+ << RHS.get()->getSourceRange();
+ return QualType();
+ }
+ } else {
+ const llvm::ElementCount VecSize =
+ S.Context.getBuiltinVectorTypeInfo(LHSBuiltinTy).EC;
+ if (LHSEleType != RHSEleType) {
+ RHS = S.ImpCastExprToType(RHS.get(), LHSEleType, clang::CK_IntegralCast);
+ RHSEleType = LHSEleType;
+ }
+ QualType VecTy =
+ S.Context.getScalableVectorType(RHSEleType, VecSize.getKnownMinValue());
+ RHS = S.ImpCastExprToType(RHS.get(), VecTy, CK_VectorSplat);
+ }
+
+ return LHSType;
+}
+
// C99 6.5.7
QualType Sema::CheckShiftOperands(ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc, BinaryOperatorKind Opc,
@@ -11191,6 +11715,10 @@ QualType Sema::CheckShiftOperands(ExprResult &LHS, ExprResult &RHS,
return checkVectorShift(*this, LHS, RHS, Loc, IsCompAssign);
}
+ if (LHS.get()->getType()->isVLSTBuiltinType() ||
+ RHS.get()->getType()->isVLSTBuiltinType())
+ return checkSizelessVectorShift(*this, LHS, RHS, Loc, IsCompAssign);
+
// Shifts don't perform usual arithmetic conversions, they just do integer
// promotions on each operand. C99 6.5.7p3
@@ -11796,7 +12324,7 @@ static QualType checkArithmeticOrEnumeralCompare(Sema &S, ExprResult &LHS,
// Check for comparisons of floating point operands using != and ==.
if (Type->hasFloatingRepresentation() && BinaryOperator::isEqualityOp(Opc))
- S.CheckFloatComparison(Loc, LHS.get(), RHS.get());
+ S.CheckFloatComparison(Loc, LHS.get(), RHS.get(), Opc);
// The result of comparisons is 'bool' in C++, 'int' in C.
return S.Context.getLogicalOperationType();
@@ -11872,6 +12400,10 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
RHS.get()->getType()->isVectorType())
return CheckVectorCompareOperands(LHS, RHS, Loc, Opc);
+ if (LHS.get()->getType()->isVLSTBuiltinType() ||
+ RHS.get()->getType()->isVLSTBuiltinType())
+ return CheckSizelessVectorCompareOperands(LHS, RHS, Loc, Opc);
+
diagnoseLogicalNotOnLHSofCheck(*this, LHS, RHS, Loc, Opc);
diagnoseTautologicalComparison(*this, Loc, LHS.get(), RHS.get(), Opc);
@@ -12295,6 +12827,8 @@ QualType Sema::GetSignedVectorType(QualType V) {
unsigned TypeSize = Context.getTypeSize(VTy->getElementType());
if (isa<ExtVectorType>(VTy)) {
+ if (VTy->isExtVectorBoolType())
+ return Context.getExtVectorType(Context.BoolTy, VTy->getNumElements());
if (TypeSize == Context.getTypeSize(Context.CharTy))
return Context.getExtVectorType(Context.CharTy, VTy->getNumElements());
if (TypeSize == Context.getTypeSize(Context.ShortTy))
@@ -12331,6 +12865,18 @@ QualType Sema::GetSignedVectorType(QualType V) {
VectorType::GenericVector);
}
+QualType Sema::GetSignedSizelessVectorType(QualType V) {
+ const BuiltinType *VTy = V->castAs<BuiltinType>();
+ assert(VTy->isSizelessBuiltinType() && "expected sizeless type");
+
+ const QualType ETy = V->getSveEltType(Context);
+ const auto TypeSize = Context.getTypeSize(ETy);
+
+ const QualType IntTy = Context.getIntTypeForBitwidth(TypeSize, true);
+ const llvm::ElementCount VecSize = Context.getBuiltinVectorTypeInfo(VTy).EC;
+ return Context.getScalableVectorType(IntTy, VecSize.getKnownMinValue());
+}
+
/// CheckVectorCompareOperands - vector comparisons are a clang extension that
/// operates on extended vector types. Instead of producing an IntTy result,
/// like a scalar comparison, a vector comparison produces a vector of integer
@@ -12345,9 +12891,12 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS,
// Check to make sure we're operating on vectors of the same type and width,
// Allowing one side to be a scalar of element type.
- QualType vType = CheckVectorOperands(LHS, RHS, Loc, /*isCompAssign*/false,
- /*AllowBothBool*/true,
- /*AllowBoolConversions*/getLangOpts().ZVector);
+ QualType vType =
+ CheckVectorOperands(LHS, RHS, Loc, /*isCompAssign*/ false,
+ /*AllowBothBool*/ true,
+ /*AllowBoolConversions*/ getLangOpts().ZVector,
+ /*AllowBooleanOperation*/ true,
+ /*ReportInvalid*/ true);
if (vType.isNull())
return vType;
@@ -12387,13 +12936,55 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS,
if (BinaryOperator::isEqualityOp(Opc) &&
LHSType->hasFloatingRepresentation()) {
assert(RHS.get()->getType()->hasFloatingRepresentation());
- CheckFloatComparison(Loc, LHS.get(), RHS.get());
+ CheckFloatComparison(Loc, LHS.get(), RHS.get(), Opc);
}
// Return a signed type for the vector.
return GetSignedVectorType(vType);
}
+QualType Sema::CheckSizelessVectorCompareOperands(ExprResult &LHS,
+ ExprResult &RHS,
+ SourceLocation Loc,
+ BinaryOperatorKind Opc) {
+ if (Opc == BO_Cmp) {
+ Diag(Loc, diag::err_three_way_vector_comparison);
+ return QualType();
+ }
+
+ // Check to make sure we're operating on vectors of the same type and width,
+ // Allowing one side to be a scalar of element type.
+ QualType vType = CheckSizelessVectorOperands(
+ LHS, RHS, Loc, /*isCompAssign*/ false, ACK_Comparison);
+
+ if (vType.isNull())
+ return vType;
+
+ QualType LHSType = LHS.get()->getType();
+
+ // For non-floating point types, check for self-comparisons of the form
+ // x == x, x != x, x < x, etc. These always evaluate to a constant, and
+ // often indicate logic errors in the program.
+ diagnoseTautologicalComparison(*this, Loc, LHS.get(), RHS.get(), Opc);
+
+ // Check for comparisons of floating point operands using != and ==.
+ if (BinaryOperator::isEqualityOp(Opc) &&
+ LHSType->hasFloatingRepresentation()) {
+ assert(RHS.get()->getType()->hasFloatingRepresentation());
+ CheckFloatComparison(Loc, LHS.get(), RHS.get(), Opc);
+ }
+
+ const BuiltinType *LHSBuiltinTy = LHSType->getAs<BuiltinType>();
+ const BuiltinType *RHSBuiltinTy = RHS.get()->getType()->getAs<BuiltinType>();
+
+ if (LHSBuiltinTy && RHSBuiltinTy && LHSBuiltinTy->isSVEBool() &&
+ RHSBuiltinTy->isSVEBool())
+ return LHSType;
+
+ // Return a signed type for the vector.
+ return GetSignedSizelessVectorType(vType);
+}
+
static void diagnoseXorMisusedAsPow(Sema &S, const ExprResult &XorLHS,
const ExprResult &XorRHS,
const SourceLocation Loc) {
@@ -12521,8 +13112,10 @@ QualType Sema::CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS,
// Ensure that either both operands are of the same vector type, or
// one operand is of a vector type and the other is of its element type.
QualType vType = CheckVectorOperands(LHS, RHS, Loc, false,
- /*AllowBothBool*/true,
- /*AllowBoolConversions*/false);
+ /*AllowBothBool*/ true,
+ /*AllowBoolConversions*/ false,
+ /*AllowBooleanOperation*/ false,
+ /*ReportInvalid*/ false);
if (vType.isNull())
return InvalidOperands(Loc, LHS, RHS);
if (getLangOpts().OpenCL &&
@@ -12616,6 +13209,20 @@ QualType Sema::CheckMatrixMultiplyOperands(ExprResult &LHS, ExprResult &RHS,
return CheckMatrixElementwiseOperands(LHS, RHS, Loc, IsCompAssign);
}
+static bool isLegalBoolVectorBinaryOp(BinaryOperatorKind Opc) {
+ switch (Opc) {
+ default:
+ return false;
+ case BO_And:
+ case BO_AndAssign:
+ case BO_Or:
+ case BO_OrAssign:
+ case BO_Xor:
+ case BO_XorAssign:
+ return true;
+ }
+}
+
inline QualType Sema::CheckBitwiseOperands(ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc,
BinaryOperatorKind Opc) {
@@ -12624,13 +13231,35 @@ inline QualType Sema::CheckBitwiseOperands(ExprResult &LHS, ExprResult &RHS,
bool IsCompAssign =
Opc == BO_AndAssign || Opc == BO_OrAssign || Opc == BO_XorAssign;
+ bool LegalBoolVecOperator = isLegalBoolVectorBinaryOp(Opc);
+
if (LHS.get()->getType()->isVectorType() ||
RHS.get()->getType()->isVectorType()) {
if (LHS.get()->getType()->hasIntegerRepresentation() &&
RHS.get()->getType()->hasIntegerRepresentation())
return CheckVectorOperands(LHS, RHS, Loc, IsCompAssign,
- /*AllowBothBool*/true,
- /*AllowBoolConversions*/getLangOpts().ZVector);
+ /*AllowBothBool*/ true,
+ /*AllowBoolConversions*/ getLangOpts().ZVector,
+ /*AllowBooleanOperation*/ LegalBoolVecOperator,
+ /*ReportInvalid*/ true);
+ return InvalidOperands(Loc, LHS, RHS);
+ }
+
+ if (LHS.get()->getType()->isVLSTBuiltinType() ||
+ RHS.get()->getType()->isVLSTBuiltinType()) {
+ if (LHS.get()->getType()->hasIntegerRepresentation() &&
+ RHS.get()->getType()->hasIntegerRepresentation())
+ return CheckSizelessVectorOperands(LHS, RHS, Loc, IsCompAssign,
+ ACK_BitwiseOp);
+ return InvalidOperands(Loc, LHS, RHS);
+ }
+
+ if (LHS.get()->getType()->isVLSTBuiltinType() ||
+ RHS.get()->getType()->isVLSTBuiltinType()) {
+ if (LHS.get()->getType()->hasIntegerRepresentation() &&
+ RHS.get()->getType()->hasIntegerRepresentation())
+ return CheckSizelessVectorOperands(LHS, RHS, Loc, IsCompAssign,
+ ACK_BitwiseOp);
return InvalidOperands(Loc, LHS, RHS);
}
@@ -12662,7 +13291,8 @@ inline QualType Sema::CheckLogicalOperands(ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc,
BinaryOperatorKind Opc) {
// Check vector operands differently.
- if (LHS.get()->getType()->isVectorType() || RHS.get()->getType()->isVectorType())
+ if (LHS.get()->getType()->isVectorType() ||
+ RHS.get()->getType()->isVectorType())
return CheckVectorLogicalOperands(LHS, RHS, Loc);
bool EnumConstantInBoolContext = false;
@@ -12696,14 +13326,13 @@ inline QualType Sema::CheckLogicalOperands(ExprResult &LHS, ExprResult &RHS,
!RHS.get()->getExprLoc().isMacroID()) ||
(Result != 0 && Result != 1)) {
Diag(Loc, diag::warn_logical_instead_of_bitwise)
- << RHS.get()->getSourceRange()
- << (Opc == BO_LAnd ? "&&" : "||");
+ << RHS.get()->getSourceRange() << (Opc == BO_LAnd ? "&&" : "||");
// Suggest replacing the logical operator with the bitwise version
Diag(Loc, diag::note_logical_instead_of_bitwise_change_operator)
<< (Opc == BO_LAnd ? "&" : "|")
- << FixItHint::CreateReplacement(SourceRange(
- Loc, getLocForEndOfToken(Loc)),
- Opc == BO_LAnd ? "&" : "|");
+ << FixItHint::CreateReplacement(
+ SourceRange(Loc, getLocForEndOfToken(Loc)),
+ Opc == BO_LAnd ? "&" : "|");
if (Opc == BO_LAnd)
// Suggest replacing "Foo() && kNonZero" with "Foo()"
Diag(Loc, diag::note_logical_instead_of_bitwise_remove_constant)
@@ -13317,15 +13946,15 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
}
}
- // C99 6.5.16p3: The type of an assignment expression is the type of the
- // left operand unless the left operand has qualified type, in which case
- // it is the unqualified version of the type of the left operand.
- // C99 6.5.16.1p2: In simple assignment, the value of the right operand
- // is converted to the type of the assignment expression (above).
+ // C11 6.5.16p3: The type of an assignment expression is the type of the
+ // left operand would have after lvalue conversion.
+ // C11 6.3.2.1p2: ...this is called lvalue conversion. If the lvalue has
+ // qualified type, the value has the unqualified version of the type of the
+ // lvalue; additionally, if the lvalue has atomic type, the value has the
+ // non-atomic version of the type of the lvalue.
// C++ 5.17p1: the type of the assignment expression is that of its left
// operand.
- return (getLangOpts().CPlusPlus
- ? LHSType : LHSType.getUnqualifiedType());
+ return getLangOpts().CPlusPlus ? LHSType : LHSType.getAtomicUnqualifiedType();
}
// Only ignore explicit casts to void.
@@ -13805,8 +14434,8 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) {
return MPTy;
}
}
- } else if (!isa<FunctionDecl>(dcl) && !isa<NonTypeTemplateParmDecl>(dcl) &&
- !isa<BindingDecl>(dcl) && !isa<MSGuidDecl>(dcl))
+ } else if (!isa<FunctionDecl, NonTypeTemplateParmDecl, BindingDecl,
+ MSGuidDecl, UnnamedGlobalConstantDecl>(dcl))
llvm_unreachable("Unknown/unexpected decl type");
}
@@ -13845,8 +14474,7 @@ static void RecordModifiableNonNullParam(Sema &S, const Expr *Exp) {
if (!FD->hasAttr<NonNullAttr>() && !Param->hasAttr<NonNullAttr>())
return;
if (FunctionScopeInfo *FD = S.getCurFunction())
- if (!FD->ModifiedNonNullParams.count(Param))
- FD->ModifiedNonNullParams.insert(Param);
+ FD->ModifiedNonNullParams.insert(Param);
}
/// CheckIndirectionOperand - Type check unary indirection (prefix '*').
@@ -14865,6 +15493,13 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
}
}
+ if (getLangOpts().HLSL) {
+ if (Opc == UO_AddrOf)
+ return ExprError(Diag(OpLoc, diag::err_hlsl_operator_unsupported) << 0);
+ if (Opc == UO_Deref)
+ return ExprError(Diag(OpLoc, diag::err_hlsl_operator_unsupported) << 1);
+ }
+
switch (Opc) {
case UO_PreInc:
case UO_PreDec:
@@ -15990,18 +16625,111 @@ ExprResult Sema::ActOnGNUNullExpr(SourceLocation TokenLoc) {
return new (Context) GNUNullExpr(Ty, TokenLoc);
}
+static CXXRecordDecl *LookupStdSourceLocationImpl(Sema &S, SourceLocation Loc) {
+ CXXRecordDecl *ImplDecl = nullptr;
+
+ // Fetch the std::source_location::__impl decl.
+ if (NamespaceDecl *Std = S.getStdNamespace()) {
+ LookupResult ResultSL(S, &S.PP.getIdentifierTable().get("source_location"),
+ Loc, Sema::LookupOrdinaryName);
+ if (S.LookupQualifiedName(ResultSL, Std)) {
+ if (auto *SLDecl = ResultSL.getAsSingle<RecordDecl>()) {
+ LookupResult ResultImpl(S, &S.PP.getIdentifierTable().get("__impl"),
+ Loc, Sema::LookupOrdinaryName);
+ if ((SLDecl->isCompleteDefinition() || SLDecl->isBeingDefined()) &&
+ S.LookupQualifiedName(ResultImpl, SLDecl)) {
+ ImplDecl = ResultImpl.getAsSingle<CXXRecordDecl>();
+ }
+ }
+ }
+ }
+
+ if (!ImplDecl || !ImplDecl->isCompleteDefinition()) {
+ S.Diag(Loc, diag::err_std_source_location_impl_not_found);
+ return nullptr;
+ }
+
+ // Verify that __impl is a trivial struct type, with no base classes, and with
+ // only the four expected fields.
+ if (ImplDecl->isUnion() || !ImplDecl->isStandardLayout() ||
+ ImplDecl->getNumBases() != 0) {
+ S.Diag(Loc, diag::err_std_source_location_impl_malformed);
+ return nullptr;
+ }
+
+ unsigned Count = 0;
+ for (FieldDecl *F : ImplDecl->fields()) {
+ StringRef Name = F->getName();
+
+ if (Name == "_M_file_name") {
+ if (F->getType() !=
+ S.Context.getPointerType(S.Context.CharTy.withConst()))
+ break;
+ Count++;
+ } else if (Name == "_M_function_name") {
+ if (F->getType() !=
+ S.Context.getPointerType(S.Context.CharTy.withConst()))
+ break;
+ Count++;
+ } else if (Name == "_M_line") {
+ if (!F->getType()->isIntegerType())
+ break;
+ Count++;
+ } else if (Name == "_M_column") {
+ if (!F->getType()->isIntegerType())
+ break;
+ Count++;
+ } else {
+ Count = 100; // invalid
+ break;
+ }
+ }
+ if (Count != 4) {
+ S.Diag(Loc, diag::err_std_source_location_impl_malformed);
+ return nullptr;
+ }
+
+ return ImplDecl;
+}
+
ExprResult Sema::ActOnSourceLocExpr(SourceLocExpr::IdentKind Kind,
SourceLocation BuiltinLoc,
SourceLocation RPLoc) {
- return BuildSourceLocExpr(Kind, BuiltinLoc, RPLoc, CurContext);
+ QualType ResultTy;
+ switch (Kind) {
+ case SourceLocExpr::File:
+ case SourceLocExpr::Function: {
+ QualType ArrTy = Context.getStringLiteralArrayType(Context.CharTy, 0);
+ ResultTy =
+ Context.getPointerType(ArrTy->getAsArrayTypeUnsafe()->getElementType());
+ break;
+ }
+ case SourceLocExpr::Line:
+ case SourceLocExpr::Column:
+ ResultTy = Context.UnsignedIntTy;
+ break;
+ case SourceLocExpr::SourceLocStruct:
+ if (!StdSourceLocationImplDecl) {
+ StdSourceLocationImplDecl =
+ LookupStdSourceLocationImpl(*this, BuiltinLoc);
+ if (!StdSourceLocationImplDecl)
+ return ExprError();
+ }
+ ResultTy = Context.getPointerType(
+ Context.getRecordType(StdSourceLocationImplDecl).withConst());
+ break;
+ }
+
+ return BuildSourceLocExpr(Kind, ResultTy, BuiltinLoc, RPLoc, CurContext);
}
ExprResult Sema::BuildSourceLocExpr(SourceLocExpr::IdentKind Kind,
+ QualType ResultTy,
SourceLocation BuiltinLoc,
SourceLocation RPLoc,
DeclContext *ParentContext) {
return new (Context)
- SourceLocExpr(Context, Kind, BuiltinLoc, RPLoc, ParentContext);
+ SourceLocExpr(Context, Kind, ResultTy, BuiltinLoc, RPLoc, ParentContext);
}
bool Sema::CheckConversionToObjCLiteral(QualType DstType, Expr *&Exp,
@@ -16026,7 +16754,7 @@ bool Sema::CheckConversionToObjCLiteral(QualType DstType, Expr *&Exp,
if (!PT->isObjCIdType() &&
!(ID && ID->getIdentifier()->isStr("NSString")))
return false;
- if (!SL->isAscii())
+ if (!SL->isOrdinary())
return false;
if (Diagnose) {
@@ -16307,10 +17035,12 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
}
PartialDiagnostic FDiag = PDiag(DiagKind);
+ AssignmentAction ActionForDiag = Action;
if (Action == AA_Passing_CFAudited)
- FDiag << FirstType << SecondType << AA_Passing << SrcExpr->getSourceRange();
- else
- FDiag << FirstType << SecondType << Action << SrcExpr->getSourceRange();
+ ActionForDiag = AA_Passing;
+
+ FDiag << FirstType << SecondType << ActionForDiag
+ << SrcExpr->getSourceRange();
if (DiagKind == diag::ext_typecheck_convert_incompatible_pointer_sign ||
DiagKind == diag::err_typecheck_convert_incompatible_pointer_sign) {
@@ -16728,7 +17458,10 @@ ExprResult Sema::CheckForImmediateInvocation(ExprResult E, FunctionDecl *Decl) {
ConstantExpr::getStorageKind(Decl->getReturnType().getTypePtr(),
getASTContext()),
/*IsImmediateInvocation*/ true);
- ExprEvalContexts.back().ImmediateInvocationCandidates.emplace_back(Res, 0);
+ /// Value-dependent constant expressions should not be immediately
+ /// evaluated until they are instantiated.
+ if (!Res->isValueDependent())
+ ExprEvalContexts.back().ImmediateInvocationCandidates.emplace_back(Res, 0);
return Res;
}
@@ -17211,7 +17944,7 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
if (NeedDefinition &&
(Func->getTemplateSpecializationKind() != TSK_Undeclared ||
Func->getMemberSpecializationInfo()))
- checkSpecializationVisibility(Loc, Func);
+ checkSpecializationReachability(Loc, Func);
if (getLangOpts().CUDA)
CheckCUDACall(Loc, Func);
@@ -17408,7 +18141,7 @@ MarkVarDeclODRUsed(VarDecl *Var, SourceLocation Loc, Sema &SemaRef,
CaptureType, DeclRefType,
FunctionScopeIndexToStopAt);
- if (SemaRef.LangOpts.CUDA && Var && Var->hasGlobalStorage()) {
+ if (SemaRef.LangOpts.CUDA && Var->hasGlobalStorage()) {
auto *FD = dyn_cast_or_null<FunctionDecl>(SemaRef.CurContext);
auto VarTarget = SemaRef.IdentifyCUDATarget(Var);
auto UserTarget = SemaRef.IdentifyCUDATarget(FD);
@@ -17428,8 +18161,7 @@ MarkVarDeclODRUsed(VarDecl *Var, SourceLocation Loc, Sema &SemaRef,
}
} else if (VarTarget == Sema::CVT_Device &&
(UserTarget == Sema::CFT_Host ||
- UserTarget == Sema::CFT_HostDevice) &&
- !Var->hasExternalStorage()) {
+ UserTarget == Sema::CFT_HostDevice)) {
// Record a CUDA/HIP device side variable if it is ODR-used
// by host code. This is done conservatively, when the variable is
// referenced in any of the following contexts:
@@ -17440,7 +18172,10 @@ MarkVarDeclODRUsed(VarDecl *Var, SourceLocation Loc, Sema &SemaRef,
// be visible in the device compilation for the compiler to be able to
// emit template variables instantiated by host code only and to
// externalize the static device side variable ODR-used by host code.
- SemaRef.getASTContext().CUDADeviceVarODRUsedByHost.insert(Var);
+ if (!Var->hasExternalStorage())
+ SemaRef.getASTContext().CUDADeviceVarODRUsedByHost.insert(Var);
+ else if (SemaRef.LangOpts.GPURelocatableDeviceCode)
+ SemaRef.getASTContext().CUDAExternalDeviceDeclODRUsedByHost.insert(Var);
}
}
@@ -18940,11 +19675,17 @@ public:
}
void Visit(Expr *E) {
- if (std::find(StopAt.begin(), StopAt.end(), E) != StopAt.end())
+ if (llvm::is_contained(StopAt, E))
return;
Inherited::Visit(E);
}
+ void VisitConstantExpr(ConstantExpr *E) {
+ // Don't mark declarations within a ConstantExpression, as this expression
+ // will be evaluated and folded to a value.
+ return;
+ }
+
void VisitDeclRefExpr(DeclRefExpr *E) {
// If we were asked not to visit local variables, don't.
if (SkipLocalVariables) {
@@ -19848,7 +20589,8 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
auto *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts());
if (DRE) {
auto *FD = cast<FunctionDecl>(DRE->getDecl());
- if (FD->getBuiltinID() == Builtin::BI__noop) {
+ unsigned BuiltinID = FD->getBuiltinID();
+ if (BuiltinID == Builtin::BI__noop) {
E = ImpCastExprToType(E, Context.getPointerType(FD->getType()),
CK_BuiltinFnToFnPtr)
.get();
@@ -19856,6 +20598,36 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
VK_PRValue, SourceLocation(),
FPOptionsOverride());
}
+
+ if (Context.BuiltinInfo.isInStdNamespace(BuiltinID)) {
+ // Any use of these other than a direct call is ill-formed as of C++20,
+ // because they are not addressable functions. In earlier language
+ // modes, warn and force an instantiation of the real body.
+ Diag(E->getBeginLoc(),
+ getLangOpts().CPlusPlus20
+ ? diag::err_use_of_unaddressable_function
+ : diag::warn_cxx20_compat_use_of_unaddressable_function);
+ if (FD->isImplicitlyInstantiable()) {
+ // Require a definition here because a normal attempt at
+ // instantiation for a builtin will be ignored, and we won't try
+ // again later. We assume that the definition of the template
+ // precedes this use.
+ InstantiateFunctionDefinition(E->getBeginLoc(), FD,
+ /*Recursive=*/false,
+ /*DefinitionRequired=*/true,
+ /*AtEndOfTU=*/false);
+ }
+ // Produce a properly-typed reference to the function.
+ CXXScopeSpec SS;
+ SS.Adopt(DRE->getQualifierLoc());
+ TemplateArgumentListInfo TemplateArgs;
+ DRE->copyTemplateArgumentsInto(TemplateArgs);
+ return BuildDeclRefExpr(
+ FD, FD->getType(), VK_LValue, DRE->getNameInfo(),
+ DRE->hasQualifier() ? &SS : nullptr, DRE->getFoundDecl(),
+ DRE->getTemplateKeywordLoc(),
+ DRE->hasExplicitTemplateArgs() ? &TemplateArgs : nullptr);
+ }
}
Diag(E->getBeginLoc(), diag::err_builtin_fn_use);
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 7ce125f5ef82..0d73fcf8bf4e 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -11,8 +11,6 @@
///
//===----------------------------------------------------------------------===//
-#include "clang/Sema/Template.h"
-#include "clang/Sema/SemaInternal.h"
#include "TreeTransform.h"
#include "TypeLocBuilder.h"
#include "clang/AST/ASTContext.h"
@@ -25,8 +23,10 @@
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/AlignedAllocation.h"
+#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TypeTraits.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/Initialization.h"
@@ -34,11 +34,14 @@
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaLambda.h"
+#include "clang/Sema/Template.h"
#include "clang/Sema/TemplateDeduction.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/TypeSize.h"
using namespace clang;
using namespace sema;
@@ -840,10 +843,10 @@ Sema::ActOnCXXThrow(Scope *S, SourceLocation OpLoc, Expr *Ex) {
break;
}
+ // FIXME: Many of the scope checks here seem incorrect.
if (S->getFlags() &
(Scope::FnScope | Scope::ClassScope | Scope::BlockScope |
- Scope::FunctionPrototypeScope | Scope::ObjCMethodScope |
- Scope::TryScope))
+ Scope::ObjCMethodScope | Scope::TryScope))
break;
}
}
@@ -1467,6 +1470,9 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
// C++1z [expr.type.conv]p1:
// If the type is a placeholder for a deduced class type, [...perform class
// template argument deduction...]
+ // C++2b:
+ // Otherwise, if the type contains a placeholder type, it is replaced by the
+ // type determined by placeholder type deduction.
DeducedType *Deduced = Ty->getContainedDeducedType();
if (Deduced && isa<DeducedTemplateSpecializationType>(Deduced)) {
Ty = DeduceTemplateSpecializationFromInitializer(TInfo, Entity,
@@ -1474,6 +1480,41 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
if (Ty.isNull())
return ExprError();
Entity = InitializedEntity::InitializeTemporary(TInfo, Ty);
+ } else if (Deduced) {
+ MultiExprArg Inits = Exprs;
+ if (ListInitialization) {
+ auto *ILE = cast<InitListExpr>(Exprs[0]);
+ Inits = MultiExprArg(ILE->getInits(), ILE->getNumInits());
+ }
+
+ if (Inits.empty())
+ return ExprError(Diag(TyBeginLoc, diag::err_auto_expr_init_no_expression)
+ << Ty << FullRange);
+ if (Inits.size() > 1) {
+ Expr *FirstBad = Inits[1];
+ return ExprError(Diag(FirstBad->getBeginLoc(),
+ diag::err_auto_expr_init_multiple_expressions)
+ << Ty << FullRange);
+ }
+ if (getLangOpts().CPlusPlus2b) {
+ if (Ty->getAs<AutoType>())
+ Diag(TyBeginLoc, diag::warn_cxx20_compat_auto_expr) << FullRange;
+ }
+ Expr *Deduce = Inits[0];
+ if (isa<InitListExpr>(Deduce))
+ return ExprError(
+ Diag(Deduce->getBeginLoc(), diag::err_auto_expr_init_paren_braces)
+ << ListInitialization << Ty << FullRange);
+ QualType DeducedType;
+ if (DeduceAutoType(TInfo, Deduce, DeducedType) == DAR_Failed)
+ return ExprError(Diag(TyBeginLoc, diag::err_auto_expr_deduction_failure)
+ << Ty << Deduce->getType() << FullRange
+ << Deduce->getSourceRange());
+ if (DeducedType.isNull())
+ return ExprError();
+
+ Ty = DeducedType;
+ Entity = InitializedEntity::InitializeTemporary(TInfo, Ty);
}
if (Ty->isDependentType() || CallExpr::hasAnyTypeDependentArguments(Exprs)) {
@@ -1559,7 +1600,7 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
bool Sema::isUsualDeallocationFunction(const CXXMethodDecl *Method) {
// [CUDA] Ignore this function, if we can't call it.
- const FunctionDecl *Caller = dyn_cast<FunctionDecl>(CurContext);
+ const FunctionDecl *Caller = getCurFunctionDecl(/*AllowLambda=*/true);
if (getLangOpts().CUDA) {
auto CallPreference = IdentifyCUDAPreference(Caller, Method);
// If it's not callable at all, it's not the right function.
@@ -1653,7 +1694,7 @@ namespace {
// In CUDA, determine how much we'd like / dislike to call this.
if (S.getLangOpts().CUDA)
- if (auto *Caller = dyn_cast<FunctionDecl>(S.CurContext))
+ if (auto *Caller = S.getCurFunctionDecl(/*AllowLambda=*/true))
CUDAPref = S.IdentifyCUDAPreference(Caller, FD);
}
@@ -1885,7 +1926,7 @@ Sema::isUnavailableAlignedAllocationFunction(const FunctionDecl &FD) const {
return false;
Optional<unsigned> AlignmentParam;
if (FD.isReplaceableGlobalAllocationFunction(&AlignmentParam) &&
- AlignmentParam.hasValue())
+ AlignmentParam)
return true;
return false;
}
@@ -1936,12 +1977,10 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
initStyle = CXXNewExpr::NoInit;
}
- Expr **Inits = &Initializer;
- unsigned NumInits = Initializer ? 1 : 0;
+ MultiExprArg Exprs(&Initializer, Initializer ? 1 : 0);
if (ParenListExpr *List = dyn_cast_or_null<ParenListExpr>(Initializer)) {
assert(initStyle == CXXNewExpr::CallInit && "paren init for non-call init");
- Inits = List->getExprs();
- NumInits = List->getNumExprs();
+ Exprs = MultiExprArg(List->getExprs(), List->getNumExprs());
}
// C++11 [expr.new]p15:
@@ -1977,23 +2016,21 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
InitializedEntity Entity
= InitializedEntity::InitializeNew(StartLoc, AllocType);
AllocType = DeduceTemplateSpecializationFromInitializer(
- AllocTypeInfo, Entity, Kind, MultiExprArg(Inits, NumInits));
+ AllocTypeInfo, Entity, Kind, Exprs);
if (AllocType.isNull())
return ExprError();
} else if (Deduced) {
+ MultiExprArg Inits = Exprs;
bool Braced = (initStyle == CXXNewExpr::ListInit);
- if (NumInits == 1) {
- if (auto p = dyn_cast_or_null<InitListExpr>(Inits[0])) {
- Inits = p->getInits();
- NumInits = p->getNumInits();
- Braced = true;
- }
+ if (Braced) {
+ auto *ILE = cast<InitListExpr>(Exprs[0]);
+ Inits = MultiExprArg(ILE->getInits(), ILE->getNumInits());
}
- if (initStyle == CXXNewExpr::NoInit || NumInits == 0)
+ if (initStyle == CXXNewExpr::NoInit || Inits.empty())
return ExprError(Diag(StartLoc, diag::err_auto_new_requires_ctor_arg)
<< AllocType << TypeRange);
- if (NumInits > 1) {
+ if (Inits.size() > 1) {
Expr *FirstBad = Inits[1];
return ExprError(Diag(FirstBad->getBeginLoc(),
diag::err_auto_new_ctor_multiple_expressions)
@@ -2003,6 +2040,10 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
Diag(Initializer->getBeginLoc(), diag::ext_auto_new_list_init)
<< AllocType << TypeRange;
Expr *Deduce = Inits[0];
+ if (isa<InitListExpr>(Deduce))
+ return ExprError(
+ Diag(Deduce->getBeginLoc(), diag::err_auto_expr_init_paren_braces)
+ << Braced << AllocType << TypeRange);
QualType DeducedType;
if (DeduceAutoType(AllocTypeInfo, Deduce, DeducedType) == DAR_Failed)
return ExprError(Diag(StartLoc, diag::err_auto_new_deduction_failure)
@@ -2190,7 +2231,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
!Expr::hasAnyTypeDependentArguments(PlacementArgs) &&
FindAllocationFunctions(
StartLoc, SourceRange(PlacementLParen, PlacementRParen), Scope, Scope,
- AllocType, ArraySize.hasValue(), PassAlignment, PlacementArgs,
+ AllocType, ArraySize.has_value(), PassAlignment, PlacementArgs,
OperatorNew, OperatorDelete))
return ExprError();
@@ -2233,10 +2274,10 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
// How many bytes do we want to allocate here?
llvm::Optional<llvm::APInt> AllocationSize;
- if (!ArraySize.hasValue() && !AllocType->isDependentType()) {
+ if (!ArraySize && !AllocType->isDependentType()) {
// For non-array operator new, we only want to allocate one element.
AllocationSize = SingleEltSize;
- } else if (KnownArraySize.hasValue() && !AllocType->isDependentType()) {
+ } else if (KnownArraySize && !AllocType->isDependentType()) {
// For array operator new, only deal with static array size case.
bool Overflow;
AllocationSize = llvm::APInt(SizeTyWidth, *KnownArraySize)
@@ -2248,7 +2289,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
}
IntegerLiteral AllocationSizeLiteral(
- Context, AllocationSize.getValueOr(llvm::APInt::getZero(SizeTyWidth)),
+ Context, AllocationSize.value_or(llvm::APInt::getZero(SizeTyWidth)),
SizeTy, SourceLocation());
// Otherwise, if we failed to constant-fold the allocation size, we'll
// just give up and pass-in something opaque, that isn't a null pointer.
@@ -2273,7 +2314,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
// Adjust placement args by prepending conjured size and alignment exprs.
llvm::SmallVector<Expr *, 8> CallArgs;
CallArgs.reserve(NumImplicitArgs + PlacementArgs.size());
- CallArgs.emplace_back(AllocationSize.hasValue()
+ CallArgs.emplace_back(AllocationSize
? static_cast<Expr *>(&AllocationSizeLiteral)
: &OpaqueAllocationSize);
if (PassAlignment)
@@ -2303,8 +2344,8 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
// Initializer lists are also allowed, in C++11. Rely on the parser for the
// dialect distinction.
if (ArraySize && !isLegalArrayNewInitializer(initStyle, Initializer)) {
- SourceRange InitRange(Inits[0]->getBeginLoc(),
- Inits[NumInits - 1]->getEndLoc());
+ SourceRange InitRange(Exprs.front()->getBeginLoc(),
+ Exprs.back()->getEndLoc());
Diag(StartLoc, diag::err_new_array_init_args) << InitRange;
return ExprError();
}
@@ -2312,8 +2353,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
// If we can perform the initialization, and we've not already done so,
// do it now.
if (!AllocType->isDependentType() &&
- !Expr::hasAnyTypeDependentArguments(
- llvm::makeArrayRef(Inits, NumInits))) {
+ !Expr::hasAnyTypeDependentArguments(Exprs)) {
// The type we initialize is the complete type, including the array bound.
QualType InitType;
if (KnownArraySize)
@@ -2330,10 +2370,8 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
InitializedEntity Entity
= InitializedEntity::InitializeNew(StartLoc, InitType);
- InitializationSequence InitSeq(*this, Entity, Kind,
- MultiExprArg(Inits, NumInits));
- ExprResult FullInit = InitSeq.Perform(*this, Entity, Kind,
- MultiExprArg(Inits, NumInits));
+ InitializationSequence InitSeq(*this, Entity, Kind, Exprs);
+ ExprResult FullInit = InitSeq.Perform(*this, Entity, Kind, Exprs);
if (FullInit.isInvalid())
return ExprError();
@@ -2795,7 +2833,8 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
}
if (getLangOpts().CUDA)
- EraseUnwantedCUDAMatches(dyn_cast<FunctionDecl>(CurContext), Matches);
+ EraseUnwantedCUDAMatches(getCurFunctionDecl(/*AllowLambda=*/true),
+ Matches);
} else {
// C++1y [expr.new]p22:
// For a non-placement allocation function, the normal deallocation
@@ -3706,7 +3745,7 @@ static bool resolveBuiltinNewDeleteOverload(Sema &S, CallExpr *TheCall,
// We do our own custom access checks below.
R.suppressDiagnostics();
- SmallVector<Expr *, 8> Args(TheCall->arg_begin(), TheCall->arg_end());
+ SmallVector<Expr *, 8> Args(TheCall->arguments());
OverloadCandidateSet Candidates(R.getNameLoc(),
OverloadCandidateSet::CSK_Normal);
for (LookupResult::iterator FnOvl = R.begin(), FnOvlEnd = R.end();
@@ -3970,7 +4009,7 @@ Sema::IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType) {
case StringLiteral::UTF32:
// We don't allow UTF literals to be implicitly converted
break;
- case StringLiteral::Ascii:
+ case StringLiteral::Ordinary:
return (ToPointeeType->getKind() == BuiltinType::Char_U ||
ToPointeeType->getKind() == BuiltinType::Char_S);
case StringLiteral::Wide:
@@ -4201,6 +4240,14 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
return ExprError();
From = FixOverloadedFunctionReference(From, Found, Fn);
+
+ // We might get back another placeholder expression if we resolved to a
+ // builtin.
+ ExprResult Checked = CheckPlaceholderExpr(From);
+ if (Checked.isInvalid())
+ return ExprError();
+
+ From = Checked.get();
FromType = From->getType();
}
@@ -4605,6 +4652,13 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
From->getType()->getPointeeType().getAddressSpace())
CK = CK_AddressSpaceConversion;
+ if (!isCast(CCK) &&
+ !ToType->getPointeeType().getQualifiers().hasUnaligned() &&
+ From->getType()->getPointeeType().getQualifiers().hasUnaligned()) {
+ Diag(From->getBeginLoc(), diag::warn_imp_cast_drops_unaligned)
+ << InitialFromType << ToType;
+ }
+
From = ImpCastExprToType(From, ToType.getNonLValueExprType(Context), CK, VK,
/*BasePath=*/nullptr, CCK)
.get();
@@ -4746,6 +4800,8 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
case UTT_IsStandardLayout:
case UTT_IsPOD:
case UTT_IsLiteral:
+ // By analogy, is_trivially_relocatable imposes the same constraints.
+ case UTT_IsTriviallyRelocatable:
// Per the GCC type traits documentation, T shall be a complete type, cv void,
// or an array of unknown bound. But GCC actually imposes the same constraints
// as above.
@@ -5210,6 +5266,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
return !T->isIncompleteType();
case UTT_HasUniqueObjectRepresentations:
return C.hasUniqueObjectRepresentations(T);
+ case UTT_IsTriviallyRelocatable:
+ return T.isTriviallyRelocatableType(C);
}
}
@@ -6048,8 +6106,17 @@ static bool isValidVectorForConditionalCondition(ASTContext &Ctx,
return false;
const QualType EltTy =
cast<VectorType>(CondTy.getCanonicalType())->getElementType();
- assert(!EltTy->isBooleanType() && !EltTy->isEnumeralType() &&
- "Vectors cant be boolean or enum types");
+ assert(!EltTy->isEnumeralType() && "Vectors cant be enum types");
+ return EltTy->isIntegralType(Ctx);
+}
+
+static bool isValidSizelessVectorForConditionalCondition(ASTContext &Ctx,
+ QualType CondTy) {
+ if (!CondTy->isVLSTBuiltinType())
+ return false;
+ const QualType EltTy =
+ cast<BuiltinType>(CondTy.getCanonicalType())->getSveEltType(Ctx);
+ assert(!EltTy->isEnumeralType() && "Vectors cant be enum types");
return EltTy->isIntegralType(Ctx);
}
@@ -6088,7 +6155,9 @@ QualType Sema::CheckVectorConditionalTypes(ExprResult &Cond, ExprResult &LHS,
} else if (LHSVT || RHSVT) {
ResultType = CheckVectorOperands(
LHS, RHS, QuestionLoc, /*isCompAssign*/ false, /*AllowBothBool*/ true,
- /*AllowBoolConversions*/ false);
+ /*AllowBoolConversions*/ false,
+ /*AllowBoolOperation*/ true,
+ /*ReportInvalid*/ true);
if (ResultType.isNull())
return {};
} else {
@@ -6142,6 +6211,89 @@ QualType Sema::CheckVectorConditionalTypes(ExprResult &Cond, ExprResult &LHS,
return ResultType;
}
+QualType Sema::CheckSizelessVectorConditionalTypes(ExprResult &Cond,
+ ExprResult &LHS,
+ ExprResult &RHS,
+ SourceLocation QuestionLoc) {
+ LHS = DefaultFunctionArrayLvalueConversion(LHS.get());
+ RHS = DefaultFunctionArrayLvalueConversion(RHS.get());
+
+ QualType CondType = Cond.get()->getType();
+ const auto *CondBT = CondType->castAs<BuiltinType>();
+ QualType CondElementTy = CondBT->getSveEltType(Context);
+ llvm::ElementCount CondElementCount =
+ Context.getBuiltinVectorTypeInfo(CondBT).EC;
+
+ QualType LHSType = LHS.get()->getType();
+ const auto *LHSBT =
+ LHSType->isVLSTBuiltinType() ? LHSType->getAs<BuiltinType>() : nullptr;
+ QualType RHSType = RHS.get()->getType();
+ const auto *RHSBT =
+ RHSType->isVLSTBuiltinType() ? RHSType->getAs<BuiltinType>() : nullptr;
+
+ QualType ResultType;
+
+ if (LHSBT && RHSBT) {
+ // If both are sizeless vector types, they must be the same type.
+ if (!Context.hasSameType(LHSType, RHSType)) {
+ Diag(QuestionLoc, diag::err_conditional_vector_mismatched)
+ << LHSType << RHSType;
+ return QualType();
+ }
+ ResultType = LHSType;
+ } else if (LHSBT || RHSBT) {
+ ResultType = CheckSizelessVectorOperands(
+ LHS, RHS, QuestionLoc, /*IsCompAssign*/ false, ACK_Conditional);
+ if (ResultType.isNull())
+ return QualType();
+ } else {
+ // Both are scalar so splat
+ QualType ResultElementTy;
+ LHSType = LHSType.getCanonicalType().getUnqualifiedType();
+ RHSType = RHSType.getCanonicalType().getUnqualifiedType();
+
+ if (Context.hasSameType(LHSType, RHSType))
+ ResultElementTy = LHSType;
+ else
+ ResultElementTy =
+ UsualArithmeticConversions(LHS, RHS, QuestionLoc, ACK_Conditional);
+
+ if (ResultElementTy->isEnumeralType()) {
+ Diag(QuestionLoc, diag::err_conditional_vector_operand_type)
+ << ResultElementTy;
+ return QualType();
+ }
+
+ ResultType = Context.getScalableVectorType(
+ ResultElementTy, CondElementCount.getKnownMinValue());
+
+ LHS = ImpCastExprToType(LHS.get(), ResultType, CK_VectorSplat);
+ RHS = ImpCastExprToType(RHS.get(), ResultType, CK_VectorSplat);
+ }
+
+ assert(!ResultType.isNull() && ResultType->isVLSTBuiltinType() &&
+ "Result should have been a vector type");
+ auto *ResultBuiltinTy = ResultType->castAs<BuiltinType>();
+ QualType ResultElementTy = ResultBuiltinTy->getSveEltType(Context);
+ llvm::ElementCount ResultElementCount =
+ Context.getBuiltinVectorTypeInfo(ResultBuiltinTy).EC;
+
+ if (ResultElementCount != CondElementCount) {
+ Diag(QuestionLoc, diag::err_conditional_vector_size)
+ << CondType << ResultType;
+ return QualType();
+ }
+
+ if (Context.getTypeSize(ResultElementTy) !=
+ Context.getTypeSize(CondElementTy)) {
+ Diag(QuestionLoc, diag::err_conditional_vector_element_size)
+ << CondType << ResultType;
+ return QualType();
+ }
+
+ return ResultType;
+}
+
/// Check the operands of ?: under C++ semantics.
///
/// See C++ [expr.cond]. Note that LHS is never null, even for the GNU x ?: y
@@ -6175,10 +6327,14 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
bool IsVectorConditional =
isValidVectorForConditionalCondition(Context, Cond.get()->getType());
+ bool IsSizelessVectorConditional =
+ isValidSizelessVectorForConditionalCondition(Context,
+ Cond.get()->getType());
+
// C++11 [expr.cond]p1
// The first expression is contextually converted to bool.
if (!Cond.get()->isTypeDependent()) {
- ExprResult CondRes = IsVectorConditional
+ ExprResult CondRes = IsVectorConditional || IsSizelessVectorConditional
? DefaultFunctionArrayLvalueConversion(Cond.get())
: CheckCXXBooleanCondition(Cond.get());
if (CondRes.isInvalid())
@@ -6247,6 +6403,9 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
if (IsVectorConditional)
return CheckVectorConditionalTypes(Cond, LHS, RHS, QuestionLoc);
+ if (IsSizelessVectorConditional)
+ return CheckSizelessVectorConditionalTypes(Cond, LHS, RHS, QuestionLoc);
+
// C++11 [expr.cond]p3
// Otherwise, if the second and third operand have different types, and
// either has (cv) class type [...] an attempt is made to convert each of
@@ -6415,9 +6574,11 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
// Extension: conditional operator involving vector types.
if (LTy->isVectorType() || RTy->isVectorType())
- return CheckVectorOperands(LHS, RHS, QuestionLoc, /*isCompAssign*/false,
- /*AllowBothBool*/true,
- /*AllowBoolConversions*/false);
+ return CheckVectorOperands(LHS, RHS, QuestionLoc, /*isCompAssign*/ false,
+ /*AllowBothBool*/ true,
+ /*AllowBoolConversions*/ false,
+ /*AllowBoolOperation*/ false,
+ /*ReportInvalid*/ true);
// -- The second and third operands have arithmetic or enumeration type;
// the usual arithmetic conversions are performed to bring them to a
@@ -7134,8 +7295,9 @@ Stmt *Sema::MaybeCreateStmtWithCleanups(Stmt *SubStmt) {
// a StmtExpr; currently this is only used for asm statements.
// This is hacky, either create a new CXXStmtWithTemporaries statement or
// a new AsmStmtWithTemporaries.
- CompoundStmt *CompStmt = CompoundStmt::Create(
- Context, SubStmt, SourceLocation(), SourceLocation());
+ CompoundStmt *CompStmt =
+ CompoundStmt::Create(Context, SubStmt, FPOptionsOverride(),
+ SourceLocation(), SourceLocation());
Expr *E = new (Context)
StmtExpr(CompStmt, Context.VoidTy, SourceLocation(), SourceLocation(),
/*FIXME TemplateDepth=*/0);
@@ -7875,6 +8037,8 @@ ExprResult Sema::ActOnNoexceptExpr(SourceLocation KeyLoc, SourceLocation,
static void MaybeDecrementCount(
Expr *E, llvm::DenseMap<const VarDecl *, int> &RefsMinusAssignments) {
DeclRefExpr *LHS = nullptr;
+ bool IsCompoundAssign = false;
+ bool isIncrementDecrementUnaryOp = false;
if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
if (BO->getLHS()->getType()->isDependentType() ||
BO->getRHS()->getType()->isDependentType()) {
@@ -7882,17 +8046,30 @@ static void MaybeDecrementCount(
return;
} else if (!BO->isAssignmentOp())
return;
+ else
+ IsCompoundAssign = BO->isCompoundAssignmentOp();
LHS = dyn_cast<DeclRefExpr>(BO->getLHS());
} else if (CXXOperatorCallExpr *COCE = dyn_cast<CXXOperatorCallExpr>(E)) {
if (COCE->getOperator() != OO_Equal)
return;
LHS = dyn_cast<DeclRefExpr>(COCE->getArg(0));
+ } else if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
+ if (!UO->isIncrementDecrementOp())
+ return;
+ isIncrementDecrementUnaryOp = true;
+ LHS = dyn_cast<DeclRefExpr>(UO->getSubExpr());
}
if (!LHS)
return;
VarDecl *VD = dyn_cast<VarDecl>(LHS->getDecl());
if (!VD)
return;
+ // Don't decrement RefsMinusAssignments if volatile variable with compound
+ // assignment (+=, ...) or increment/decrement unary operator to avoid
+ // potential unused-but-set-variable warning.
+ if ((IsCompoundAssign || isIncrementDecrementUnaryOp) &&
+ VD->getType().isVolatileQualified())
+ return;
auto iter = RefsMinusAssignments.find(VD);
if (iter == RefsMinusAssignments.end())
return;
@@ -8063,8 +8240,7 @@ static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures(
if (const Optional<unsigned> Index =
getStackIndexOfNearestEnclosingCaptureCapableLambda(
S.FunctionScopes, Var, S))
- S.MarkCaptureUsedInEnclosingContext(Var, VarExpr->getExprLoc(),
- Index.getValue());
+ S.MarkCaptureUsedInEnclosingContext(Var, VarExpr->getExprLoc(), *Index);
const bool IsVarNeverAConstantExpression =
VariableCanNeverBeAConstantExpression(Var, S.Context);
if (!IsFullExprInstantiationDependent || IsVarNeverAConstantExpression) {
@@ -8097,7 +8273,7 @@ static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures(
if (const Optional<unsigned> Index =
getStackIndexOfNearestEnclosingCaptureCapableLambda(
S.FunctionScopes, /*0 is 'this'*/ nullptr, S)) {
- const unsigned FunctionScopeIndexOfCapturableLambda = Index.getValue();
+ const unsigned FunctionScopeIndexOfCapturableLambda = *Index;
S.CheckCXXThisCapture(CurrentLSI->PotentialThisCaptureLocation,
/*Explicit*/ false, /*BuildAndDiagnose*/ true,
&FunctionScopeIndexOfCapturableLambda);
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index dfd93aa4638d..c9d9ef31f3ee 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -940,7 +940,7 @@ static bool IsInFnTryBlockHandler(const Scope *S) {
// function scope. If a FnTryCatchScope is found, check whether the TryScope
// flag is set. If it is not, it's a function-try-block handler.
for (; S != S->getFnParent(); S = S->getParent()) {
- if (S->getFlags() & Scope::FnTryCatchScope)
+ if (S->isFnTryCatchScope())
return (S->getFlags() & Scope::TryScope) != Scope::TryScope;
}
return false;
@@ -1292,6 +1292,21 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
}
}
+ // If the base type is an atomic type, this access is undefined behavior per
+ // C11 6.5.2.3p5. Instead of giving a typecheck error, we'll warn the user
+ // about the UB and recover by converting the atomic lvalue into a non-atomic
+ // lvalue. Because this is inherently unsafe as an atomic operation, the
+ // warning defaults to an error.
+ if (const auto *ATy = BaseType->getAs<AtomicType>()) {
+ S.DiagRuntimeBehavior(OpLoc, nullptr,
+ S.PDiag(diag::warn_atomic_member_access));
+ BaseType = ATy->getValueType().getUnqualifiedType();
+ BaseExpr = ImplicitCastExpr::Create(
+ S.Context, IsArrow ? S.Context.getPointerType(BaseType) : BaseType,
+ CK_AtomicToNonAtomic, BaseExpr.get(), nullptr,
+ BaseExpr.get()->getValueKind(), FPOptionsOverride());
+ }
+
// Handle field access to simple records.
if (const RecordType *RTy = BaseType->getAs<RecordType>()) {
TypoExpr *TE = nullptr;
@@ -1592,6 +1607,16 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
false);
}
+ if (BaseType->isExtVectorBoolType()) {
+ // We disallow element access for ext_vector_type bool. There is no way to
+ // materialize a reference to a vector element as a pointer (each element is
+ // one bit in the vector).
+ S.Diag(R.getNameLoc(), diag::err_ext_vector_component_name_illegal)
+ << MemberName
+ << (BaseExpr.get() ? BaseExpr.get()->getSourceRange() : SourceRange());
+ return ExprError();
+ }
+
// Handle 'field access' to vectors, such as 'V.xx'.
if (BaseType->isExtVectorType()) {
// FIXME: this expr should store IsArrow.
@@ -1711,6 +1736,9 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
DeclarationName Name = NameInfo.getName();
bool IsArrow = (OpKind == tok::arrow);
+ if (getLangOpts().HLSL && IsArrow)
+ return ExprError(Diag(OpLoc, diag::err_hlsl_operator_unsupported) << 2);
+
NamedDecl *FirstQualifierInScope
= (!SS.isSet() ? nullptr : FindFirstQualifierInScope(S, SS.getScopeRep()));
diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp
index 4702c405fb4e..a6c92d1a338d 100644
--- a/clang/lib/Sema/SemaExprObjC.cpp
+++ b/clang/lib/Sema/SemaExprObjC.cpp
@@ -50,7 +50,7 @@ ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs,
S = cast<StringLiteral>(E);
// ObjC strings can't be wide or UTF.
- if (!S->isAscii()) {
+ if (!S->isOrdinary()) {
Diag(S->getBeginLoc(), diag::err_cfstring_literal_not_string_constant)
<< S->getSourceRange();
return true;
@@ -70,7 +70,7 @@ ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs,
QualType StrTy = Context.getConstantArrayType(
CAT->getElementType(), llvm::APInt(32, StrBuf.size() + 1), nullptr,
CAT->getSizeModifier(), CAT->getIndexTypeCVRQualifiers());
- S = StringLiteral::Create(Context, StrBuf, StringLiteral::Ascii,
+ S = StringLiteral::Create(Context, StrBuf, StringLiteral::Ordinary,
/*Pascal=*/false, StrTy, &StrLocs[0],
StrLocs.size());
}
@@ -448,7 +448,7 @@ static ExprResult CheckObjCCollectionLiteralElement(Sema &S, Expr *Element,
}
// If this is potentially an Objective-C string literal, add the '@'.
else if (StringLiteral *String = dyn_cast<StringLiteral>(OrigElement)) {
- if (String->isAscii()) {
+ if (String->isOrdinary()) {
S.Diag(OrigElement->getBeginLoc(), diag::err_box_literal_collection)
<< 0 << OrigElement->getSourceRange()
<< FixItHint::CreateInsertion(OrigElement->getBeginLoc(), "@");
@@ -533,7 +533,7 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
if (CE->getCastKind() == CK_ArrayToPointerDecay)
if (auto *SL =
dyn_cast<StringLiteral>(CE->getSubExpr()->IgnoreParens())) {
- assert((SL->isAscii() || SL->isUTF8()) &&
+ assert((SL->isOrdinary() || SL->isUTF8()) &&
"unexpected character encoding");
StringRef Str = SL->getString();
const llvm::UTF8 *StrBegin = Str.bytes_begin();
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 119a90deb9c2..d3b454843234 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -87,7 +87,7 @@ static StringInitFailureKind IsStringInit(Expr *Init, const ArrayType *AT,
if (ElemTy->isChar8Type())
return SIF_None;
LLVM_FALLTHROUGH;
- case StringLiteral::Ascii:
+ case StringLiteral::Ordinary:
// char array can be initialized with a narrow string.
// Only allow char x[] = "foo"; not char x[] = L"foo";
if (ElemTy->isCharType())
@@ -1696,7 +1696,7 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
return;
}
- if (!SemaRef.getLangOpts().OpenCL) {
+ if (!SemaRef.getLangOpts().OpenCL && !SemaRef.getLangOpts().HLSL ) {
// If the initializing element is a vector, try to copy-initialize
// instead of breaking it apart (which is doomed to failure anyway).
Expr *Init = IList->getInit(Index);
@@ -1790,7 +1790,7 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
InitializedEntity ElementEntity =
InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity);
- // OpenCL initializers allows vectors to be constructed from vectors.
+ // OpenCL and HLSL initializers allow vectors to be constructed from vectors.
for (unsigned i = 0; i < maxElements; ++i) {
// Don't attempt to go past the end of the init list
if (Index >= IList->getNumInits())
@@ -1819,7 +1819,7 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
}
}
- // OpenCL requires all elements to be initialized.
+ // OpenCL and HLSL require all elements to be initialized.
if (numEltsInit != maxElements) {
if (!VerifyOnly)
SemaRef.Diag(IList->getBeginLoc(),
@@ -2004,10 +2004,6 @@ bool InitListChecker::CheckFlexibleArrayInit(const InitializedEntity &Entity,
cast<InitListExpr>(InitExpr)->getNumInits() == 0) {
// Empty flexible array init always allowed as an extension
FlexArrayDiag = diag::ext_flexible_array_init;
- } else if (SemaRef.getLangOpts().CPlusPlus) {
- // Disallow flexible array init in C++; it is not required for gcc
- // compatibility, and it needs work to IRGen correctly in general.
- FlexArrayDiag = diag::err_flexible_array_init;
} else if (!TopLevelObject) {
// Disallow flexible array init on non-top-level object
FlexArrayDiag = diag::err_flexible_array_init;
@@ -2127,6 +2123,9 @@ void InitListChecker::CheckStructUnionTypes(
// worthwhile to skip over the rest of the initializer, though.
RecordDecl *RD = DeclType->castAs<RecordType>()->getDecl();
RecordDecl::field_iterator FieldEnd = RD->field_end();
+ size_t NumRecordDecls = llvm::count_if(RD->decls(), [&](const Decl *D) {
+ return isa<FieldDecl>(D) || isa<RecordDecl>(D);
+ });
bool CheckForMissingFields =
!IList->isIdiomaticZeroInitializer(SemaRef.getLangOpts());
bool HasDesignatedInit = false;
@@ -2171,6 +2170,35 @@ void InitListChecker::CheckStructUnionTypes(
continue;
}
+ // Check if this is an initializer of forms:
+ //
+ // struct foo f = {};
+ // struct foo g = {0};
+ //
+ // These are okay for randomized structures. [C99 6.7.8p19]
+ //
+ // Also, if there is only one element in the structure, we allow something
+ // like this, because it's really not randomized in the tranditional sense.
+ //
+ // struct foo h = {bar};
+ auto IsZeroInitializer = [&](const Expr *I) {
+ if (IList->getNumInits() == 1) {
+ if (NumRecordDecls == 1)
+ return true;
+ if (const auto *IL = dyn_cast<IntegerLiteral>(I))
+ return IL->getValue().isZero();
+ }
+ return false;
+ };
+
+ // Don't allow non-designated initializers on randomized structures.
+ if (RD->isRandomized() && !IsZeroInitializer(Init)) {
+ if (!VerifyOnly)
+ SemaRef.Diag(InitLoc, diag::err_non_designated_init_used);
+ hadError = true;
+ break;
+ }
+
if (Field == FieldEnd) {
// We've run out of fields. We're done.
break;
@@ -3441,7 +3469,7 @@ unsigned InitializedEntity::dumpImpl(raw_ostream &OS) const {
D->printQualifiedName(OS);
}
- OS << " '" << getType().getAsString() << "'\n";
+ OS << " '" << getType() << "'\n";
return Depth + 1;
}
@@ -4475,13 +4503,13 @@ static void TryListInitialization(Sema &S,
Kind.getKind() == InitializationKind::IK_DirectList &&
ET && ET->getDecl()->isFixed() &&
!S.Context.hasSameUnqualifiedType(E->getType(), DestType) &&
- (E->getType()->isIntegralOrEnumerationType() ||
+ (E->getType()->isIntegralOrUnscopedEnumerationType() ||
E->getType()->isFloatingType())) {
// There are two ways that T(v) can work when T is an enumeration type.
// If there is either an implicit conversion sequence from v to T or
// a conversion function that can convert from v to T, then we use that.
- // Otherwise, if v is of integral, enumeration, or floating-point type,
- // it is converted to the enumeration type via its underlying type.
+ // Otherwise, if v is of integral, unscoped enumeration, or floating-point
+ // type, it is converted to the enumeration type via its underlying type.
// There is no overlap possible between these two cases (except when the
// source value is already of the destination type), and the first
// case is handled by the general case for single-element lists below.
@@ -5941,6 +5969,37 @@ void InitializationSequence::InitializeFrom(Sema &S,
assert(Args.size() >= 1 && "Zero-argument case handled above");
+ // For HLSL ext vector types we allow list initialization behavior for C++
+ // constructor syntax. This is accomplished by converting initialization
+ // arguments an InitListExpr late.
+ if (S.getLangOpts().HLSL && DestType->isExtVectorType() &&
+ (SourceType.isNull() ||
+ !Context.hasSameUnqualifiedType(SourceType, DestType))) {
+
+ llvm::SmallVector<Expr *> InitArgs;
+ for (auto Arg : Args) {
+ if (Arg->getType()->isExtVectorType()) {
+ const auto *VTy = Arg->getType()->castAs<ExtVectorType>();
+ unsigned Elm = VTy->getNumElements();
+ for (unsigned Idx = 0; Idx < Elm; ++Idx) {
+ InitArgs.emplace_back(new (Context) ArraySubscriptExpr(
+ Arg,
+ IntegerLiteral::Create(
+ Context, llvm::APInt(Context.getIntWidth(Context.IntTy), Idx),
+ Context.IntTy, SourceLocation()),
+ VTy->getElementType(), Arg->getValueKind(), Arg->getObjectKind(),
+ SourceLocation()));
+ }
+ } else
+ InitArgs.emplace_back(Arg);
+ }
+ InitListExpr *ILE = new (Context) InitListExpr(
+ S.getASTContext(), SourceLocation(), InitArgs, SourceLocation());
+ Args[0] = ILE;
+ AddListInitializationStep(DestType);
+ return;
+ }
+
// The remaining cases all need a source type.
if (Args.size() > 1) {
SetFailed(FK_TooManyInitsForScalar);
@@ -8101,6 +8160,12 @@ ExprResult InitializationSequence::Perform(Sema &S,
ExprResult CurInit((Expr *)nullptr);
SmallVector<Expr*, 4> ArrayLoopCommonExprs;
+ // HLSL allows vector initialization to function like list initialization, but
+ // use the syntax of a C++-like constructor.
+ bool IsHLSLVectorInit = S.getLangOpts().HLSL && DestType->isExtVectorType() &&
+ isa<InitListExpr>(Args[0]);
+ (void)IsHLSLVectorInit;
+
// For initialization steps that start with a single initializer,
// grab the only argument out the Args and place it into the "current"
// initializer.
@@ -8138,7 +8203,7 @@ ExprResult InitializationSequence::Perform(Sema &S,
case SK_StdInitializerList:
case SK_OCLSamplerInit:
case SK_OCLZeroOpaqueType: {
- assert(Args.size() == 1);
+ assert(Args.size() == 1 || IsHLSLVectorInit);
CurInit = Args[0];
if (!CurInit.get()) return ExprError();
break;
@@ -8189,6 +8254,10 @@ ExprResult InitializationSequence::Perform(Sema &S,
CurInit = S.FixOverloadedFunctionReference(CurInit,
Step->Function.FoundDecl,
Step->Function.Function);
+ // We might get back another placeholder expression if we resolved to a
+ // builtin.
+ if (!CurInit.isInvalid())
+ CurInit = S.CheckPlaceholderExpr(CurInit.get());
break;
case SK_CastDerivedToBasePRValue:
@@ -9770,7 +9839,7 @@ void InitializationSequence::dump(raw_ostream &OS) const {
break;
}
- OS << " [" << S->Type.getAsString() << ']';
+ OS << " [" << S->Type << ']';
}
OS << '\n';
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index b05e0b5cc0f1..afc2f3ef4d76 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -182,7 +182,7 @@ Optional<unsigned> clang::getStackIndexOfNearestEnclosingCaptureCapableLambda(
if (!OptionalStackIndex)
return NoLambdaIsCaptureCapable;
- const unsigned IndexOfCaptureReadyLambda = OptionalStackIndex.getValue();
+ const unsigned IndexOfCaptureReadyLambda = *OptionalStackIndex;
assert(((IndexOfCaptureReadyLambda != (FunctionScopes.size() - 1)) ||
S.getCurGenericLambda()) &&
"The capture ready lambda for a potential capture can only be the "
@@ -238,21 +238,19 @@ getGenericLambdaTemplateParameterList(LambdaScopeInfo *LSI, Sema &SemaRef) {
return LSI->GLTemplateParameterList;
}
-CXXRecordDecl *Sema::createLambdaClosureType(SourceRange IntroducerRange,
- TypeSourceInfo *Info,
- bool KnownDependent,
- LambdaCaptureDefault CaptureDefault) {
+CXXRecordDecl *
+Sema::createLambdaClosureType(SourceRange IntroducerRange, TypeSourceInfo *Info,
+ unsigned LambdaDependencyKind,
+ LambdaCaptureDefault CaptureDefault) {
DeclContext *DC = CurContext;
while (!(DC->isFunctionOrMethod() || DC->isRecord() || DC->isFileContext()))
DC = DC->getParent();
bool IsGenericLambda = getGenericLambdaTemplateParameterList(getCurLambda(),
*this);
// Start constructing the lambda class.
- CXXRecordDecl *Class = CXXRecordDecl::CreateLambda(Context, DC, Info,
- IntroducerRange.getBegin(),
- KnownDependent,
- IsGenericLambda,
- CaptureDefault);
+ CXXRecordDecl *Class = CXXRecordDecl::CreateLambda(
+ Context, DC, Info, IntroducerRange.getBegin(), LambdaDependencyKind,
+ IsGenericLambda, CaptureDefault);
DC->addDecl(Class);
return Class;
@@ -435,7 +433,7 @@ void Sema::handleLambdaNumbering(
unsigned ManglingNumber, DeviceManglingNumber;
Decl *ManglingContextDecl;
std::tie(HasKnownInternalLinkage, ManglingNumber, DeviceManglingNumber,
- ManglingContextDecl) = Mangling.getValue();
+ ManglingContextDecl) = *Mangling;
Class->setLambdaMangling(ManglingNumber, ManglingContextDecl,
HasKnownInternalLinkage);
Class->setDeviceLambdaManglingNumber(DeviceManglingNumber);
@@ -898,17 +896,18 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
// Determine if we're within a context where we know that the lambda will
// be dependent, because there are template parameters in scope.
- bool KnownDependent;
+ CXXRecordDecl::LambdaDependencyKind LambdaDependencyKind =
+ CXXRecordDecl::LDK_Unknown;
if (LSI->NumExplicitTemplateParams > 0) {
auto *TemplateParamScope = CurScope->getTemplateParamParent();
assert(TemplateParamScope &&
"Lambda with explicit template param list should establish a "
"template param scope");
assert(TemplateParamScope->getParent());
- KnownDependent = TemplateParamScope->getParent()
- ->getTemplateParamParent() != nullptr;
- } else {
- KnownDependent = CurScope->getTemplateParamParent() != nullptr;
+ if (TemplateParamScope->getParent()->getTemplateParamParent() != nullptr)
+ LambdaDependencyKind = CXXRecordDecl::LDK_AlwaysDependent;
+ } else if (CurScope->getTemplateParamParent() != nullptr) {
+ LambdaDependencyKind = CXXRecordDecl::LDK_AlwaysDependent;
}
// Determine the signature of the call operator.
@@ -977,8 +976,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
UPPC_DeclarationType);
}
- CXXRecordDecl *Class = createLambdaClosureType(Intro.Range, MethodTyInfo,
- KnownDependent, Intro.Default);
+ CXXRecordDecl *Class = createLambdaClosureType(
+ Intro.Range, MethodTyInfo, LambdaDependencyKind, Intro.Default);
CXXMethodDecl *Method =
startLambdaDefinition(Class, Intro.Range, MethodTyInfo, EndLoc, Params,
ParamInfo.getDeclSpec().getConstexprSpecifier(),
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index af6ee24240ce..47c7a61f8072 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -930,9 +930,11 @@ bool Sema::LookupBuiltin(LookupResult &R) {
// If this is a builtin on this (or all) targets, create the decl.
if (unsigned BuiltinID = II->getBuiltinID()) {
- // In C++ and OpenCL (spec v1.2 s6.9.f), we don't have any predefined
- // library functions like 'malloc'. Instead, we'll just error.
- if ((getLangOpts().CPlusPlus || getLangOpts().OpenCL) &&
+ // In C++, C2x, and OpenCL (spec v1.2 s6.9.f), we don't have any
+ // predefined library functions like 'malloc'. Instead, we'll just
+ // error.
+ if ((getLangOpts().CPlusPlus || getLangOpts().OpenCL ||
+ getLangOpts().C2x) &&
Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
return false;
@@ -1556,13 +1558,39 @@ llvm::DenseSet<Module*> &Sema::getLookupModules() {
return LookupModulesCache;
}
-/// Determine whether the module M is part of the current module from the
-/// perspective of a module-private visibility check.
-static bool isInCurrentModule(const Module *M, const LangOptions &LangOpts) {
- // If M is the global module fragment of a module that we've not yet finished
- // parsing, then it must be part of the current module.
- return M->getTopLevelModuleName() == LangOpts.CurrentModule ||
- (M->Kind == Module::GlobalModuleFragment && !M->Parent);
+/// Determine if we could use all the declarations in the module.
+bool Sema::isUsableModule(const Module *M) {
+ assert(M && "We shouldn't check nullness for module here");
+ // Return quickly if we cached the result.
+ if (UsableModuleUnitsCache.count(M))
+ return true;
+
+ // If M is the global module fragment of the current translation unit. So it
+ // should be usable.
+ // [module.global.frag]p1:
+ // The global module fragment can be used to provide declarations that are
+ // attached to the global module and usable within the module unit.
+ if (M == GlobalModuleFragment ||
+ // If M is the module we're parsing, it should be usable. This covers the
+ // private module fragment. The private module fragment is usable only if
+ // it is within the current module unit. And it must be the current
+ // parsing module unit if it is within the current module unit according
+ // to the grammar of the private module fragment. NOTE: This is covered by
+ // the following condition. The intention of the check is to avoid string
+ // comparison as much as possible.
+ M == getCurrentModule() ||
+ // The module unit which is in the same module with the current module
+ // unit is usable.
+ //
+ // FIXME: Here we judge if they are in the same module by comparing the
+ // string. Is there any better solution?
+ M->getPrimaryModuleInterfaceName() ==
+ llvm::StringRef(getLangOpts().CurrentModule).split(':').first) {
+ UsableModuleUnitsCache.insert(M);
+ return true;
+ }
+
+ return false;
}
bool Sema::hasVisibleMergedDefinition(NamedDecl *Def) {
@@ -1574,21 +1602,22 @@ bool Sema::hasVisibleMergedDefinition(NamedDecl *Def) {
bool Sema::hasMergedDefinitionInCurrentModule(NamedDecl *Def) {
for (const Module *Merged : Context.getModulesWithMergedDefinition(Def))
- if (isInCurrentModule(Merged, getLangOpts()))
+ if (isUsableModule(Merged))
return true;
return false;
}
-template<typename ParmDecl>
+template <typename ParmDecl>
static bool
-hasVisibleDefaultArgument(Sema &S, const ParmDecl *D,
- llvm::SmallVectorImpl<Module *> *Modules) {
+hasAcceptableDefaultArgument(Sema &S, const ParmDecl *D,
+ llvm::SmallVectorImpl<Module *> *Modules,
+ Sema::AcceptableKind Kind) {
if (!D->hasDefaultArgument())
return false;
while (D) {
auto &DefaultArg = D->getDefaultArgStorage();
- if (!DefaultArg.isInherited() && S.isVisible(D))
+ if (!DefaultArg.isInherited() && S.isAcceptable(D, Kind))
return true;
if (!DefaultArg.isInherited() && Modules) {
@@ -1602,20 +1631,36 @@ hasVisibleDefaultArgument(Sema &S, const ParmDecl *D,
return false;
}
-bool Sema::hasVisibleDefaultArgument(const NamedDecl *D,
- llvm::SmallVectorImpl<Module *> *Modules) {
+bool Sema::hasAcceptableDefaultArgument(
+ const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules,
+ Sema::AcceptableKind Kind) {
if (auto *P = dyn_cast<TemplateTypeParmDecl>(D))
- return ::hasVisibleDefaultArgument(*this, P, Modules);
+ return ::hasAcceptableDefaultArgument(*this, P, Modules, Kind);
+
if (auto *P = dyn_cast<NonTypeTemplateParmDecl>(D))
- return ::hasVisibleDefaultArgument(*this, P, Modules);
- return ::hasVisibleDefaultArgument(*this, cast<TemplateTemplateParmDecl>(D),
- Modules);
+ return ::hasAcceptableDefaultArgument(*this, P, Modules, Kind);
+
+ return ::hasAcceptableDefaultArgument(
+ *this, cast<TemplateTemplateParmDecl>(D), Modules, Kind);
+}
+
+bool Sema::hasVisibleDefaultArgument(const NamedDecl *D,
+ llvm::SmallVectorImpl<Module *> *Modules) {
+ return hasAcceptableDefaultArgument(D, Modules,
+ Sema::AcceptableKind::Visible);
+}
+
+bool Sema::hasReachableDefaultArgument(
+ const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules) {
+ return hasAcceptableDefaultArgument(D, Modules,
+ Sema::AcceptableKind::Reachable);
}
-template<typename Filter>
-static bool hasVisibleDeclarationImpl(Sema &S, const NamedDecl *D,
- llvm::SmallVectorImpl<Module *> *Modules,
- Filter F) {
+template <typename Filter>
+static bool
+hasAcceptableDeclarationImpl(Sema &S, const NamedDecl *D,
+ llvm::SmallVectorImpl<Module *> *Modules, Filter F,
+ Sema::AcceptableKind Kind) {
bool HasFilteredRedecls = false;
for (auto *Redecl : D->redecls()) {
@@ -1623,7 +1668,7 @@ static bool hasVisibleDeclarationImpl(Sema &S, const NamedDecl *D,
if (!F(R))
continue;
- if (S.isVisible(R))
+ if (S.isAcceptable(R, Kind))
return true;
HasFilteredRedecls = true;
@@ -1639,74 +1684,115 @@ static bool hasVisibleDeclarationImpl(Sema &S, const NamedDecl *D,
return true;
}
+static bool
+hasAcceptableExplicitSpecialization(Sema &S, const NamedDecl *D,
+ llvm::SmallVectorImpl<Module *> *Modules,
+ Sema::AcceptableKind Kind) {
+ return hasAcceptableDeclarationImpl(
+ S, D, Modules,
+ [](const NamedDecl *D) {
+ if (auto *RD = dyn_cast<CXXRecordDecl>(D))
+ return RD->getTemplateSpecializationKind() ==
+ TSK_ExplicitSpecialization;
+ if (auto *FD = dyn_cast<FunctionDecl>(D))
+ return FD->getTemplateSpecializationKind() ==
+ TSK_ExplicitSpecialization;
+ if (auto *VD = dyn_cast<VarDecl>(D))
+ return VD->getTemplateSpecializationKind() ==
+ TSK_ExplicitSpecialization;
+ llvm_unreachable("unknown explicit specialization kind");
+ },
+ Kind);
+}
+
bool Sema::hasVisibleExplicitSpecialization(
const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules) {
- return hasVisibleDeclarationImpl(*this, D, Modules, [](const NamedDecl *D) {
- if (auto *RD = dyn_cast<CXXRecordDecl>(D))
- return RD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization;
- if (auto *FD = dyn_cast<FunctionDecl>(D))
- return FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization;
- if (auto *VD = dyn_cast<VarDecl>(D))
- return VD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization;
- llvm_unreachable("unknown explicit specialization kind");
- });
+ return ::hasAcceptableExplicitSpecialization(*this, D, Modules,
+ Sema::AcceptableKind::Visible);
}
-bool Sema::hasVisibleMemberSpecialization(
+bool Sema::hasReachableExplicitSpecialization(
const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules) {
+ return ::hasAcceptableExplicitSpecialization(*this, D, Modules,
+ Sema::AcceptableKind::Reachable);
+}
+
+static bool
+hasAcceptableMemberSpecialization(Sema &S, const NamedDecl *D,
+ llvm::SmallVectorImpl<Module *> *Modules,
+ Sema::AcceptableKind Kind) {
assert(isa<CXXRecordDecl>(D->getDeclContext()) &&
"not a member specialization");
- return hasVisibleDeclarationImpl(*this, D, Modules, [](const NamedDecl *D) {
- // If the specialization is declared at namespace scope, then it's a member
- // specialization declaration. If it's lexically inside the class
- // definition then it was instantiated.
- //
- // FIXME: This is a hack. There should be a better way to determine this.
- // FIXME: What about MS-style explicit specializations declared within a
- // class definition?
- return D->getLexicalDeclContext()->isFileContext();
- });
+ return hasAcceptableDeclarationImpl(
+ S, D, Modules,
+ [](const NamedDecl *D) {
+ // If the specialization is declared at namespace scope, then it's a
+ // member specialization declaration. If it's lexically inside the class
+ // definition then it was instantiated.
+ //
+ // FIXME: This is a hack. There should be a better way to determine
+ // this.
+ // FIXME: What about MS-style explicit specializations declared within a
+ // class definition?
+ return D->getLexicalDeclContext()->isFileContext();
+ },
+ Kind);
}
-/// Determine whether a declaration is visible to name lookup.
+bool Sema::hasVisibleMemberSpecialization(
+ const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules) {
+ return hasAcceptableMemberSpecialization(*this, D, Modules,
+ Sema::AcceptableKind::Visible);
+}
+
+bool Sema::hasReachableMemberSpecialization(
+ const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules) {
+ return hasAcceptableMemberSpecialization(*this, D, Modules,
+ Sema::AcceptableKind::Reachable);
+}
+
+/// Determine whether a declaration is acceptable to name lookup.
///
-/// This routine determines whether the declaration D is visible in the current
-/// lookup context, taking into account the current template instantiation
-/// stack. During template instantiation, a declaration is visible if it is
-/// visible from a module containing any entity on the template instantiation
-/// path (by instantiating a template, you allow it to see the declarations that
-/// your module can see, including those later on in your module).
-bool LookupResult::isVisibleSlow(Sema &SemaRef, NamedDecl *D) {
+/// This routine determines whether the declaration D is acceptable in the
+/// current lookup context, taking into account the current template
+/// instantiation stack. During template instantiation, a declaration is
+/// acceptable if it is acceptable from a module containing any entity on the
+/// template instantiation path (by instantiating a template, you allow it to
+/// see the declarations that your module can see, including those later on in
+/// your module).
+bool LookupResult::isAcceptableSlow(Sema &SemaRef, NamedDecl *D,
+ Sema::AcceptableKind Kind) {
assert(!D->isUnconditionallyVisible() &&
"should not call this: not in slow case");
Module *DeclModule = SemaRef.getOwningModule(D);
assert(DeclModule && "hidden decl has no owning module");
- // If the owning module is visible, the decl is visible.
- if (SemaRef.isModuleVisible(DeclModule, D->isModulePrivate()))
+ // If the owning module is visible, the decl is acceptable.
+ if (SemaRef.isModuleVisible(DeclModule,
+ D->isInvisibleOutsideTheOwningModule()))
return true;
// Determine whether a decl context is a file context for the purpose of
- // visibility. This looks through some (export and linkage spec) transparent
- // contexts, but not others (enums).
+ // visibility/reachability. This looks through some (export and linkage spec)
+ // transparent contexts, but not others (enums).
auto IsEffectivelyFileContext = [](const DeclContext *DC) {
return DC->isFileContext() || isa<LinkageSpecDecl>(DC) ||
isa<ExportDecl>(DC);
};
// If this declaration is not at namespace scope
- // then it is visible if its lexical parent has a visible definition.
+ // then it is acceptable if its lexical parent has a acceptable definition.
DeclContext *DC = D->getLexicalDeclContext();
if (DC && !IsEffectivelyFileContext(DC)) {
// For a parameter, check whether our current template declaration's
- // lexical context is visible, not whether there's some other visible
+ // lexical context is acceptable, not whether there's some other acceptable
// definition of it, because parameters aren't "within" the definition.
//
- // In C++ we need to check for a visible definition due to ODR merging,
+ // In C++ we need to check for a acceptable definition due to ODR merging,
// and in C we must not because each declaration of a function gets its own
// set of declarations for tags in prototype scope.
- bool VisibleWithinParent;
+ bool AcceptableWithinParent;
if (D->isTemplateParameter()) {
bool SearchDefinitions = true;
if (const auto *DCD = dyn_cast<Decl>(DC)) {
@@ -1717,51 +1803,72 @@ bool LookupResult::isVisibleSlow(Sema &SemaRef, NamedDecl *D) {
}
}
if (SearchDefinitions)
- VisibleWithinParent = SemaRef.hasVisibleDefinition(cast<NamedDecl>(DC));
+ AcceptableWithinParent =
+ SemaRef.hasAcceptableDefinition(cast<NamedDecl>(DC), Kind);
else
- VisibleWithinParent = isVisible(SemaRef, cast<NamedDecl>(DC));
+ AcceptableWithinParent =
+ isAcceptable(SemaRef, cast<NamedDecl>(DC), Kind);
} else if (isa<ParmVarDecl>(D) ||
(isa<FunctionDecl>(DC) && !SemaRef.getLangOpts().CPlusPlus))
- VisibleWithinParent = isVisible(SemaRef, cast<NamedDecl>(DC));
+ AcceptableWithinParent = isAcceptable(SemaRef, cast<NamedDecl>(DC), Kind);
else if (D->isModulePrivate()) {
- // A module-private declaration is only visible if an enclosing lexical
+ // A module-private declaration is only acceptable if an enclosing lexical
// parent was merged with another definition in the current module.
- VisibleWithinParent = false;
+ AcceptableWithinParent = false;
do {
if (SemaRef.hasMergedDefinitionInCurrentModule(cast<NamedDecl>(DC))) {
- VisibleWithinParent = true;
+ AcceptableWithinParent = true;
break;
}
DC = DC->getLexicalParent();
} while (!IsEffectivelyFileContext(DC));
} else {
- VisibleWithinParent = SemaRef.hasVisibleDefinition(cast<NamedDecl>(DC));
+ AcceptableWithinParent =
+ SemaRef.hasAcceptableDefinition(cast<NamedDecl>(DC), Kind);
}
- if (VisibleWithinParent && SemaRef.CodeSynthesisContexts.empty() &&
+ if (AcceptableWithinParent && SemaRef.CodeSynthesisContexts.empty() &&
+ Kind == Sema::AcceptableKind::Visible &&
// FIXME: Do something better in this case.
!SemaRef.getLangOpts().ModulesLocalVisibility) {
// Cache the fact that this declaration is implicitly visible because
// its parent has a visible definition.
D->setVisibleDespiteOwningModule();
}
- return VisibleWithinParent;
+ return AcceptableWithinParent;
}
- return false;
+ if (Kind == Sema::AcceptableKind::Visible)
+ return false;
+
+ assert(Kind == Sema::AcceptableKind::Reachable &&
+ "Additional Sema::AcceptableKind?");
+ return isReachableSlow(SemaRef, D);
}
bool Sema::isModuleVisible(const Module *M, bool ModulePrivate) {
+ // [module.global.frag]p2:
+ // A global-module-fragment specifies the contents of the global module
+ // fragment for a module unit. The global module fragment can be used to
+ // provide declarations that are attached to the global module and usable
+ // within the module unit.
+ //
+ // Global module fragment is special. Global Module fragment is only usable
+ // within the module unit it got defined [module.global.frag]p2. So here we
+ // check if the Module is the global module fragment in current translation
+ // unit.
+ if (M->isGlobalModule() && M != this->GlobalModuleFragment)
+ return false;
+
// The module might be ordinarily visible. For a module-private query, that
- // means it is part of the current module. For any other query, that means it
- // is in our visible module set.
- if (ModulePrivate) {
- if (isInCurrentModule(M, getLangOpts()))
- return true;
- } else {
- if (VisibleModules.isVisible(M))
- return true;
- }
+ // means it is part of the current module.
+ if (ModulePrivate && isUsableModule(M))
+ return true;
+
+ // For a query which is not module-private, that means it is in our visible
+ // module set.
+ if (!ModulePrivate && VisibleModules.isVisible(M))
+ return true;
// Otherwise, it might be visible by virtue of the query being within a
// template instantiation or similar that is permitted to look inside M.
@@ -1785,8 +1892,74 @@ bool Sema::isModuleVisible(const Module *M, bool ModulePrivate) {
});
}
-bool Sema::isVisibleSlow(const NamedDecl *D) {
- return LookupResult::isVisible(*this, const_cast<NamedDecl*>(D));
+// FIXME: Return false directly if we don't have an interface dependency on the
+// translation unit containing D.
+bool LookupResult::isReachableSlow(Sema &SemaRef, NamedDecl *D) {
+ assert(!isVisible(SemaRef, D) && "Shouldn't call the slow case.\n");
+
+ Module *DeclModule = SemaRef.getOwningModule(D);
+ assert(DeclModule && "hidden decl has no owning module");
+
+ // Entities in module map modules are reachable only if they're visible.
+ if (DeclModule->isModuleMapModule())
+ return false;
+
+ // If D comes from a module and SemaRef doesn't own a module, it implies D
+ // comes from another TU. In case SemaRef owns a module, we could judge if D
+ // comes from another TU by comparing the module unit.
+ //
+ // FIXME: It would look better if we have direct method to judge whether D is
+ // in another TU.
+ if (SemaRef.getCurrentModule() &&
+ SemaRef.getCurrentModule()->getTopLevelModule() ==
+ DeclModule->getTopLevelModule())
+ return true;
+
+ // [module.reach]/p3:
+ // A declaration D is reachable from a point P if:
+ // ...
+ // - D is not discarded ([module.global.frag]), appears in a translation unit
+ // that is reachable from P, and does not appear within a private module
+ // fragment.
+ //
+ // A declaration that's discarded in the GMF should be module-private.
+ if (D->isModulePrivate())
+ return false;
+
+ // [module.reach]/p1
+ // A translation unit U is necessarily reachable from a point P if U is a
+ // module interface unit on which the translation unit containing P has an
+ // interface dependency, or the translation unit containing P imports U, in
+ // either case prior to P ([module.import]).
+ //
+ // [module.import]/p10
+ // A translation unit has an interface dependency on a translation unit U if
+ // it contains a declaration (possibly a module-declaration) that imports U
+ // or if it has an interface dependency on a translation unit that has an
+ // interface dependency on U.
+ //
+ // So we could conclude the module unit U is necessarily reachable if:
+ // (1) The module unit U is module interface unit.
+ // (2) The current unit has an interface dependency on the module unit U.
+ //
+ // Here we only check for the first condition. Since we couldn't see
+ // DeclModule if it isn't (transitively) imported.
+ if (DeclModule->getTopLevelModule()->isModuleInterfaceUnit())
+ return true;
+
+ // [module.reach]/p2
+ // Additional translation units on
+ // which the point within the program has an interface dependency may be
+ // considered reachable, but it is unspecified which are and under what
+ // circumstances.
+ //
+ // The decision here is to treat all additional tranditional units as
+ // unreachable.
+ return false;
+}
+
+bool Sema::isAcceptableSlow(const NamedDecl *D, Sema::AcceptableKind Kind) {
+ return LookupResult::isAcceptable(*this, const_cast<NamedDecl *>(D), Kind);
}
bool Sema::shouldLinkPossiblyHiddenDecl(LookupResult &R, const NamedDecl *New) {
@@ -1835,7 +2008,7 @@ bool Sema::shouldLinkPossiblyHiddenDecl(LookupResult &R, const NamedDecl *New) {
/// and visible. If no declaration of D is visible, returns null.
static NamedDecl *findAcceptableDecl(Sema &SemaRef, NamedDecl *D,
unsigned IDNS) {
- assert(!LookupResult::isVisible(SemaRef, D) && "not in slow case");
+ assert(!LookupResult::isAvailableForLookup(SemaRef, D) && "not in slow case");
for (auto RD : D->redecls()) {
// Don't bother with extra checks if we already know this one isn't visible.
@@ -1847,7 +2020,7 @@ static NamedDecl *findAcceptableDecl(Sema &SemaRef, NamedDecl *D,
// visible in the same scope as D. This needs to be done much more
// carefully.
if (ND->isInIdentifierNamespace(IDNS) &&
- LookupResult::isVisible(SemaRef, ND))
+ LookupResult::isAvailableForLookup(SemaRef, ND))
return ND;
}
@@ -1857,8 +2030,17 @@ static NamedDecl *findAcceptableDecl(Sema &SemaRef, NamedDecl *D,
bool Sema::hasVisibleDeclarationSlow(const NamedDecl *D,
llvm::SmallVectorImpl<Module *> *Modules) {
assert(!isVisible(D) && "not in slow case");
- return hasVisibleDeclarationImpl(*this, D, Modules,
- [](const NamedDecl *) { return true; });
+ return hasAcceptableDeclarationImpl(
+ *this, D, Modules, [](const NamedDecl *) { return true; },
+ Sema::AcceptableKind::Visible);
+}
+
+bool Sema::hasReachableDeclarationSlow(
+ const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules) {
+ assert(!isReachable(D) && "not in slow case");
+ return hasAcceptableDeclarationImpl(
+ *this, D, Modules, [](const NamedDecl *) { return true; },
+ Sema::AcceptableKind::Reachable);
}
NamedDecl *LookupResult::getAcceptableDeclSlow(NamedDecl *D) const {
@@ -1883,6 +2065,60 @@ NamedDecl *LookupResult::getAcceptableDeclSlow(NamedDecl *D) const {
return findAcceptableDecl(getSema(), D, IDNS);
}
+bool LookupResult::isVisible(Sema &SemaRef, NamedDecl *D) {
+ // If this declaration is already visible, return it directly.
+ if (D->isUnconditionallyVisible())
+ return true;
+
+ // During template instantiation, we can refer to hidden declarations, if
+ // they were visible in any module along the path of instantiation.
+ return isAcceptableSlow(SemaRef, D, Sema::AcceptableKind::Visible);
+}
+
+bool LookupResult::isReachable(Sema &SemaRef, NamedDecl *D) {
+ if (D->isUnconditionallyVisible())
+ return true;
+
+ return isAcceptableSlow(SemaRef, D, Sema::AcceptableKind::Reachable);
+}
+
+bool LookupResult::isAvailableForLookup(Sema &SemaRef, NamedDecl *ND) {
+ // We should check the visibility at the callsite already.
+ if (isVisible(SemaRef, ND))
+ return true;
+
+ auto *DC = ND->getDeclContext();
+ // If ND is not visible and it is at namespace scope, it shouldn't be found
+ // by name lookup.
+ if (DC->isFileContext())
+ return false;
+
+ // [module.interface]p7
+ // Class and enumeration member names can be found by name lookup in any
+ // context in which a definition of the type is reachable.
+ //
+ // FIXME: The current implementation didn't consider about scope. For example,
+ // ```
+ // // m.cppm
+ // export module m;
+ // enum E1 { e1 };
+ // // Use.cpp
+ // import m;
+ // void test() {
+ // auto a = E1::e1; // Error as expected.
+ // auto b = e1; // Should be error. namespace-scope name e1 is not visible
+ // }
+ // ```
+ // For the above example, the current implementation would emit error for `a`
+ // correctly. However, the implementation wouldn't diagnose about `b` now.
+ // Since we only check the reachability for the parent only.
+ // See clang/test/CXX/module/module.interface/p7.cpp for example.
+ if (auto *TD = dyn_cast<TagDecl>(DC))
+ return SemaRef.hasReachableDefinition(TD);
+
+ return false;
+}
+
/// Perform unqualified name lookup starting from a given
/// scope.
///
@@ -1911,13 +2147,14 @@ NamedDecl *LookupResult::getAcceptableDeclSlow(NamedDecl *D) const {
/// used to diagnose ambiguities.
///
/// @returns \c true if lookup succeeded and false otherwise.
-bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) {
+bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation,
+ bool ForceNoCPlusPlus) {
DeclarationName Name = R.getLookupName();
if (!Name) return false;
LookupNameKind NameKind = R.getLookupKind();
- if (!getLangOpts().CPlusPlus) {
+ if (!getLangOpts().CPlusPlus || ForceNoCPlusPlus) {
// Unqualified name lookup in C/Objective-C is purely lexical, so
// search in the declarations attached to the name.
if (NameKind == Sema::LookupRedeclarationWithLinkage) {
@@ -3613,7 +3850,16 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, SourceLocation Loc,
}
} else if (D->getFriendObjectKind()) {
auto *RD = cast<CXXRecordDecl>(D->getLexicalDeclContext());
- if (AssociatedClasses.count(RD) && isVisible(D)) {
+ // [basic.lookup.argdep]p4:
+ // Argument-dependent lookup finds all declarations of functions and
+ // function templates that
+ // - ...
+ // - are declared as a friend ([class.friend]) of any class with a
+ // reachable definition in the set of associated entities,
+ //
+ // FIXME: If there's a merged definition of D that is reachable, then
+ // the friend declaration should be considered.
+ if (AssociatedClasses.count(RD) && isReachable(D)) {
Visible = true;
break;
}
diff --git a/clang/lib/Sema/SemaModule.cpp b/clang/lib/Sema/SemaModule.cpp
index 747734f2d0ff..3aa124d457b0 100644
--- a/clang/lib/Sema/SemaModule.cpp
+++ b/clang/lib/Sema/SemaModule.cpp
@@ -54,6 +54,23 @@ static void checkModuleImportContext(Sema &S, Module *M,
}
}
+// We represent the primary and partition names as 'Paths' which are sections
+// of the hierarchical access path for a clang module. However for C++20
+// the periods in a name are just another character, and we will need to
+// flatten them into a string.
+static std::string stringFromPath(ModuleIdPath Path) {
+ std::string Name;
+ if (Path.empty())
+ return Name;
+
+ for (auto &Piece : Path) {
+ if (!Name.empty())
+ Name += ".";
+ Name += Piece.first->getName();
+ }
+ return Name;
+}
+
Sema::DeclGroupPtrTy
Sema::ActOnGlobalModuleFragmentDecl(SourceLocation ModuleLoc) {
if (!ModuleScopes.empty() &&
@@ -73,22 +90,91 @@ Sema::ActOnGlobalModuleFragmentDecl(SourceLocation ModuleLoc) {
// All declarations created from now on are owned by the global module.
auto *TU = Context.getTranslationUnitDecl();
- TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::Visible);
+ // [module.global.frag]p2
+ // A global-module-fragment specifies the contents of the global module
+ // fragment for a module unit. The global module fragment can be used to
+ // provide declarations that are attached to the global module and usable
+ // within the module unit.
+ //
+ // So the declations in the global module shouldn't be visible by default.
+ TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ReachableWhenImported);
TU->setLocalOwningModule(GlobalModule);
// FIXME: Consider creating an explicit representation of this declaration.
return nullptr;
}
+void Sema::HandleStartOfHeaderUnit() {
+ assert(getLangOpts().CPlusPlusModules &&
+ "Header units are only valid for C++20 modules");
+ SourceLocation StartOfTU =
+ SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID());
+
+ StringRef HUName = getLangOpts().CurrentModule;
+ if (HUName.empty()) {
+ HUName = SourceMgr.getFileEntryForID(SourceMgr.getMainFileID())->getName();
+ const_cast<LangOptions &>(getLangOpts()).CurrentModule = HUName.str();
+ }
+
+ // TODO: Make the C++20 header lookup independent.
+ // When the input is pre-processed source, we need a file ref to the original
+ // file for the header map.
+ auto F = SourceMgr.getFileManager().getFile(HUName);
+ // For the sake of error recovery (if someone has moved the original header
+ // after creating the pre-processed output) fall back to obtaining the file
+ // ref for the input file, which must be present.
+ if (!F)
+ F = SourceMgr.getFileEntryForID(SourceMgr.getMainFileID());
+ assert(F && "failed to find the header unit source?");
+ Module::Header H{HUName.str(), HUName.str(), *F};
+ auto &Map = PP.getHeaderSearchInfo().getModuleMap();
+ Module *Mod = Map.createHeaderUnit(StartOfTU, HUName, H);
+ assert(Mod && "module creation should not fail");
+ ModuleScopes.push_back({}); // No GMF
+ ModuleScopes.back().BeginLoc = StartOfTU;
+ ModuleScopes.back().Module = Mod;
+ ModuleScopes.back().ModuleInterface = true;
+ ModuleScopes.back().IsPartition = false;
+ VisibleModules.setVisible(Mod, StartOfTU);
+
+ // From now on, we have an owning module for all declarations we see.
+ // All of these are implicitly exported.
+ auto *TU = Context.getTranslationUnitDecl();
+ TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::Visible);
+ TU->setLocalOwningModule(Mod);
+}
+
Sema::DeclGroupPtrTy
Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
- ModuleDeclKind MDK, ModuleIdPath Path, bool IsFirstDecl) {
+ ModuleDeclKind MDK, ModuleIdPath Path,
+ ModuleIdPath Partition, ModuleImportState &ImportState) {
assert((getLangOpts().ModulesTS || getLangOpts().CPlusPlusModules) &&
"should only have module decl in Modules TS or C++20");
- // A module implementation unit requires that we are not compiling a module
- // of any kind. A module interface unit requires that we are not compiling a
- // module map.
+ bool IsFirstDecl = ImportState == ModuleImportState::FirstDecl;
+ bool SeenGMF = ImportState == ModuleImportState::GlobalFragment;
+ // If any of the steps here fail, we count that as invalidating C++20
+ // module state;
+ ImportState = ModuleImportState::NotACXX20Module;
+
+ bool IsPartition = !Partition.empty();
+ if (IsPartition)
+ switch (MDK) {
+ case ModuleDeclKind::Implementation:
+ MDK = ModuleDeclKind::PartitionImplementation;
+ break;
+ case ModuleDeclKind::Interface:
+ MDK = ModuleDeclKind::PartitionInterface;
+ break;
+ default:
+ llvm_unreachable("how did we get a partition type set?");
+ }
+
+ // A (non-partition) module implementation unit requires that we are not
+ // compiling a module of any kind. A partition implementation emits an
+ // interface (and the AST for the implementation), which will subsequently
+ // be consumed to emit a binary.
+ // A module interface unit requires that we are not compiling a module map.
switch (getLangOpts().getCompilingModule()) {
case LangOptions::CMK_None:
// It's OK to compile a module interface as a normal translation unit.
@@ -99,7 +185,7 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
break;
// We were asked to compile a module interface unit but this is a module
- // implementation unit. That indicates the 'export' is missing.
+ // implementation unit.
Diag(ModuleLoc, diag::err_module_interface_implementation_mismatch)
<< FixItHint::CreateInsertion(ModuleLoc, "export ");
MDK = ModuleDeclKind::Interface;
@@ -110,6 +196,7 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
return nullptr;
case LangOptions::CMK_HeaderModule:
+ case LangOptions::CMK_HeaderUnit:
Diag(ModuleLoc, diag::err_module_decl_in_header_module);
return nullptr;
}
@@ -134,9 +221,13 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
ModuleScopes.back().Module->Kind == Module::GlobalModuleFragment)
GlobalModuleFragment = ModuleScopes.back().Module;
+ assert((!getLangOpts().CPlusPlusModules || getLangOpts().ModulesTS ||
+ SeenGMF == (bool)GlobalModuleFragment) &&
+ "mismatched global module state");
+
// In C++20, the module-declaration must be the first declaration if there
// is no global module fragment.
- if (getLangOpts().CPlusPlusModules && !IsFirstDecl && !GlobalModuleFragment) {
+ if (getLangOpts().CPlusPlusModules && !IsFirstDecl && !SeenGMF) {
Diag(ModuleLoc, diag::err_module_decl_not_at_start);
SourceLocation BeginLoc =
ModuleScopes.empty()
@@ -151,19 +242,19 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
// Flatten the dots in a module name. Unlike Clang's hierarchical module map
// modules, the dots here are just another character that can appear in a
// module name.
- std::string ModuleName;
- for (auto &Piece : Path) {
- if (!ModuleName.empty())
- ModuleName += ".";
- ModuleName += Piece.first->getName();
+ std::string ModuleName = stringFromPath(Path);
+ if (IsPartition) {
+ ModuleName += ":";
+ ModuleName += stringFromPath(Partition);
}
-
// If a module name was explicitly specified on the command line, it must be
// correct.
if (!getLangOpts().CurrentModule.empty() &&
getLangOpts().CurrentModule != ModuleName) {
Diag(Path.front().second, diag::err_current_module_name_mismatch)
- << SourceRange(Path.front().second, Path.back().second)
+ << SourceRange(Path.front().second, IsPartition
+ ? Partition.back().second
+ : Path.back().second)
<< getLangOpts().CurrentModule;
return nullptr;
}
@@ -173,7 +264,8 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
Module *Mod;
switch (MDK) {
- case ModuleDeclKind::Interface: {
+ case ModuleDeclKind::Interface:
+ case ModuleDeclKind::PartitionInterface: {
// We can't have parsed or imported a definition of this module or parsed a
// module map defining it already.
if (auto *M = Map.findModule(ModuleName)) {
@@ -190,13 +282,19 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
// Create a Module for the module that we're defining.
Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName,
GlobalModuleFragment);
+ if (MDK == ModuleDeclKind::PartitionInterface)
+ Mod->Kind = Module::ModulePartitionInterface;
assert(Mod && "module creation should not fail");
break;
}
- case ModuleDeclKind::Implementation:
+ case ModuleDeclKind::Implementation: {
std::pair<IdentifierInfo *, SourceLocation> ModuleNameLoc(
PP.getIdentifierInfo(ModuleName), Path[0].second);
+ // C++20 A module-declaration that contains neither an export-
+ // keyword nor a module-partition implicitly imports the primary
+ // module interface unit of the module as if by a module-import-
+ // declaration.
Mod = getModuleLoader().loadModule(ModuleLoc, {ModuleNameLoc},
Module::AllVisible,
/*IsInclusionDirective=*/false);
@@ -206,6 +304,14 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName,
GlobalModuleFragment);
}
+ } break;
+
+ case ModuleDeclKind::PartitionImplementation:
+ // Create an interface, but note that it is an implementation
+ // unit.
+ Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName,
+ GlobalModuleFragment);
+ Mod->Kind = Module::ModulePartitionImplementation;
break;
}
@@ -222,15 +328,22 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
ModuleScopes.back().BeginLoc = StartLoc;
ModuleScopes.back().Module = Mod;
ModuleScopes.back().ModuleInterface = MDK != ModuleDeclKind::Implementation;
+ ModuleScopes.back().IsPartition = IsPartition;
VisibleModules.setVisible(Mod, ModuleLoc);
// From now on, we have an owning module for all declarations we see.
- // However, those declarations are module-private unless explicitly
+ // In C++20 modules, those declaration would be reachable when imported
+ // unless explicitily exported.
+ // Otherwise, those declarations are module-private unless explicitly
// exported.
auto *TU = Context.getTranslationUnitDecl();
- TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ModulePrivate);
+ TU->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ReachableWhenImported);
TU->setLocalOwningModule(Mod);
+ // We are in the module purview, but before any other (non import)
+ // statements, so imports are allowed.
+ ImportState = ModuleImportState::ImportAllowed;
+
// FIXME: Create a ModuleDecl.
return nullptr;
}
@@ -245,6 +358,9 @@ Sema::ActOnPrivateModuleFragmentDecl(SourceLocation ModuleLoc,
: ModuleScopes.back().Module->Kind) {
case Module::ModuleMapModule:
case Module::GlobalModuleFragment:
+ case Module::ModulePartitionImplementation:
+ case Module::ModulePartitionInterface:
+ case Module::ModuleHeaderUnit:
Diag(PrivateLoc, diag::err_private_module_fragment_not_module);
return nullptr;
@@ -299,24 +415,50 @@ Sema::ActOnPrivateModuleFragmentDecl(SourceLocation ModuleLoc,
DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
SourceLocation ExportLoc,
- SourceLocation ImportLoc,
- ModuleIdPath Path) {
- // Flatten the module path for a Modules TS module name.
+ SourceLocation ImportLoc, ModuleIdPath Path,
+ bool IsPartition) {
+
+ bool Cxx20Mode = getLangOpts().CPlusPlusModules || getLangOpts().ModulesTS;
+ assert((!IsPartition || Cxx20Mode) && "partition seen in non-C++20 code?");
+
+ // For a C++20 module name, flatten into a single identifier with the source
+ // location of the first component.
std::pair<IdentifierInfo *, SourceLocation> ModuleNameLoc;
- if (getLangOpts().ModulesTS) {
- std::string ModuleName;
- for (auto &Piece : Path) {
- if (!ModuleName.empty())
- ModuleName += ".";
- ModuleName += Piece.first->getName();
- }
+
+ std::string ModuleName;
+ if (IsPartition) {
+ // We already checked that we are in a module purview in the parser.
+ assert(!ModuleScopes.empty() && "in a module purview, but no module?");
+ Module *NamedMod = ModuleScopes.back().Module;
+ // If we are importing into a partition, find the owning named module,
+ // otherwise, the name of the importing named module.
+ ModuleName = NamedMod->getPrimaryModuleInterfaceName().str();
+ ModuleName += ":";
+ ModuleName += stringFromPath(Path);
+ ModuleNameLoc = {PP.getIdentifierInfo(ModuleName), Path[0].second};
+ Path = ModuleIdPath(ModuleNameLoc);
+ } else if (Cxx20Mode) {
+ ModuleName = stringFromPath(Path);
ModuleNameLoc = {PP.getIdentifierInfo(ModuleName), Path[0].second};
Path = ModuleIdPath(ModuleNameLoc);
}
- Module *Mod =
- getModuleLoader().loadModule(ImportLoc, Path, Module::AllVisible,
- /*IsInclusionDirective=*/false);
+ // Diagnose self-import before attempting a load.
+ // [module.import]/9
+ // A module implementation unit of a module M that is not a module partition
+ // shall not contain a module-import-declaration nominating M.
+ // (for an implementation, the module interface is imported implicitly,
+ // but that's handled in the module decl code).
+
+ if (getLangOpts().CPlusPlusModules && isCurrentModulePurview() &&
+ getCurrentModule()->Name == ModuleName) {
+ Diag(ImportLoc, diag::err_module_self_import_cxx20)
+ << ModuleName << !ModuleScopes.back().ModuleInterface;
+ return true;
+ }
+
+ Module *Mod = getModuleLoader().loadModule(
+ ImportLoc, Path, Module::AllVisible, /*IsInclusionDirective=*/false);
if (!Mod)
return true;
@@ -333,8 +475,8 @@ static const ExportDecl *getEnclosingExportDecl(const Decl *D) {
DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
SourceLocation ExportLoc,
- SourceLocation ImportLoc,
- Module *Mod, ModuleIdPath Path) {
+ SourceLocation ImportLoc, Module *Mod,
+ ModuleIdPath Path) {
VisibleModules.setVisible(Mod, ImportLoc);
checkModuleImportContext(*this, Mod, ImportLoc, CurContext);
@@ -342,10 +484,7 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
// FIXME: we should support importing a submodule within a different submodule
// of the same top-level module. Until we do, make it an error rather than
// silently ignoring the import.
- // Import-from-implementation is valid in the Modules TS. FIXME: Should we
- // warn on a redundant import of the current module?
- // FIXME: Import of a module from an implementation partition of the same
- // module is permitted.
+ // FIXME: Should we warn on a redundant import of the current module?
if (Mod->getTopLevelModuleName() == getLangOpts().CurrentModule &&
(getLangOpts().isCompilingModule() || !getLangOpts().ModulesTS)) {
Diag(ImportLoc, getLangOpts().isCompilingModule()
@@ -355,22 +494,26 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
}
SmallVector<SourceLocation, 2> IdentifierLocs;
- Module *ModCheck = Mod;
- for (unsigned I = 0, N = Path.size(); I != N; ++I) {
- // If we've run out of module parents, just drop the remaining identifiers.
- // We need the length to be consistent.
- if (!ModCheck)
- break;
- ModCheck = ModCheck->Parent;
- IdentifierLocs.push_back(Path[I].second);
- }
-
- // If this was a header import, pad out with dummy locations.
- // FIXME: Pass in and use the location of the header-name token in this case.
if (Path.empty()) {
- for (; ModCheck; ModCheck = ModCheck->Parent) {
+ // If this was a header import, pad out with dummy locations.
+ // FIXME: Pass in and use the location of the header-name token in this
+ // case.
+ for (Module *ModCheck = Mod; ModCheck; ModCheck = ModCheck->Parent)
IdentifierLocs.push_back(SourceLocation());
+ } else if (getLangOpts().CPlusPlusModules && !Mod->Parent) {
+ // A single identifier for the whole name.
+ IdentifierLocs.push_back(Path[0].second);
+ } else {
+ Module *ModCheck = Mod;
+ for (unsigned I = 0, N = Path.size(); I != N; ++I) {
+ // If we've run out of module parents, just drop the remaining
+ // identifiers. We need the length to be consistent.
+ if (!ModCheck)
+ break;
+ ModCheck = ModCheck->Parent;
+
+ IdentifierLocs.push_back(Path[I].second);
}
}
@@ -383,7 +526,18 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
if (!ModuleScopes.empty())
Context.addModuleInitializer(ModuleScopes.back().Module, Import);
- if (!ModuleScopes.empty() && ModuleScopes.back().ModuleInterface) {
+ // A module (partition) implementation unit shall not be exported.
+ if (getLangOpts().CPlusPlusModules && ExportLoc.isValid() &&
+ Mod->Kind == Module::ModuleKind::ModulePartitionImplementation) {
+ Diag(ExportLoc, diag::err_export_partition_impl)
+ << SourceRange(ExportLoc, Path.back().second);
+ } else if (!ModuleScopes.empty() &&
+ (ModuleScopes.back().ModuleInterface ||
+ (getLangOpts().CPlusPlusModules &&
+ ModuleScopes.back().Module->isGlobalModule()))) {
+ assert((!ModuleScopes.back().Module->isGlobalModule() ||
+ Mod->Kind == Module::ModuleKind::ModuleHeaderUnit) &&
+ "should only be importing a header unit into the GMF");
// Re-export the module if the imported module is exported.
// Note that we don't need to add re-exported module to Imports field
// since `Exports` implies the module is imported already.
@@ -395,9 +549,21 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
// [module.interface]p1:
// An export-declaration shall inhabit a namespace scope and appear in the
// purview of a module interface unit.
- Diag(ExportLoc, diag::err_export_not_in_module_interface) << 0;
+ Diag(ExportLoc, diag::err_export_not_in_module_interface)
+ << (!ModuleScopes.empty() &&
+ !ModuleScopes.back().ImplicitGlobalModuleFragment);
+ } else if (getLangOpts().isCompilingModule()) {
+ Module *ThisModule = PP.getHeaderSearchInfo().lookupModule(
+ getLangOpts().CurrentModule, ExportLoc, false, false);
+ (void)ThisModule;
+ assert(ThisModule && "was expecting a module if building one");
}
+ // In some cases we need to know if an entity was present in a directly-
+ // imported module (as opposed to a transitive import). This avoids
+ // searching both Imports and Exports.
+ DirectModuleImports.insert(Mod);
+
return Import;
}
@@ -433,6 +599,13 @@ void Sema::BuildModuleInclude(SourceLocation DirectiveLoc, Module *Mod) {
getModuleLoader().makeModuleVisible(Mod, Module::AllVisible, DirectiveLoc);
VisibleModules.setVisible(Mod, DirectiveLoc);
+
+ if (getLangOpts().isCompilingModule()) {
+ Module *ThisModule = PP.getHeaderSearchInfo().lookupModule(
+ getLangOpts().CurrentModule, DirectiveLoc, false, false);
+ (void)ThisModule;
+ assert(ThisModule && "was expecting a module if building one");
+ }
}
void Sema::ActOnModuleBegin(SourceLocation DirectiveLoc, Module *Mod) {
@@ -598,6 +771,7 @@ enum class UnnamedDeclKind {
StaticAssert,
Asm,
UsingDirective,
+ Namespace,
Context
};
}
@@ -627,6 +801,10 @@ unsigned getUnnamedDeclDiag(UnnamedDeclKind UDK, bool InBlock) {
// Allow exporting using-directives as an extension.
return diag::ext_export_using_directive;
+ case UnnamedDeclKind::Namespace:
+ // Anonymous namespace with no content.
+ return diag::introduces_no_names;
+
case UnnamedDeclKind::Context:
// Allow exporting DeclContexts that transitively contain no declarations
// as an extension.
@@ -654,10 +832,12 @@ static bool checkExportedDecl(Sema &S, Decl *D, SourceLocation BlockStart) {
diagExportedUnnamedDecl(S, *UDK, D, BlockStart);
// [...] shall not declare a name with internal linkage.
+ bool HasName = false;
if (auto *ND = dyn_cast<NamedDecl>(D)) {
// Don't diagnose anonymous union objects; we'll diagnose their members
// instead.
- if (ND->getDeclName() && ND->getFormalLinkage() == InternalLinkage) {
+ HasName = (bool)ND->getDeclName();
+ if (HasName && ND->getFormalLinkage() == InternalLinkage) {
S.Diag(ND->getLocation(), diag::err_export_internal) << ND;
if (BlockStart.isValid())
S.Diag(BlockStart, diag::note_export);
@@ -669,8 +849,10 @@ static bool checkExportedDecl(Sema &S, Decl *D, SourceLocation BlockStart) {
// shall have been introduced with a name having external linkage
if (auto *USD = dyn_cast<UsingShadowDecl>(D)) {
NamedDecl *Target = USD->getUnderlyingDecl();
- if (Target->getFormalLinkage() == InternalLinkage) {
- S.Diag(USD->getLocation(), diag::err_export_using_internal) << Target;
+ Linkage Lk = Target->getFormalLinkage();
+ if (Lk == InternalLinkage || Lk == ModuleLinkage) {
+ S.Diag(USD->getLocation(), diag::err_export_using_internal)
+ << (Lk == InternalLinkage ? 0 : 1) << Target;
S.Diag(Target->getLocation(), diag::note_using_decl_target);
if (BlockStart.isValid())
S.Diag(BlockStart, diag::note_export);
@@ -678,10 +860,17 @@ static bool checkExportedDecl(Sema &S, Decl *D, SourceLocation BlockStart) {
}
// Recurse into namespace-scope DeclContexts. (Only namespace-scope
- // declarations are exported.)
- if (auto *DC = dyn_cast<DeclContext>(D))
- if (DC->getRedeclContext()->isFileContext() && !isa<EnumDecl>(D))
+ // declarations are exported.).
+ if (auto *DC = dyn_cast<DeclContext>(D)) {
+ if (isa<NamespaceDecl>(D) && DC->decls().empty()) {
+ if (!HasName)
+ // We don't allow an empty anonymous namespace (we don't allow decls
+ // in them either, but that's handled in the recursion).
+ diagExportedUnnamedDecl(S, UnnamedDeclKind::Namespace, D, BlockStart);
+ // We allow an empty named namespace decl.
+ } else if (DC->getRedeclContext()->isFileContext() && !isa<EnumDecl>(D))
return checkExportedDeclContext(S, DC, BlockStart);
+ }
return false;
}
@@ -720,19 +909,25 @@ Decl *Sema::ActOnFinishExportDecl(Scope *S, Decl *D, SourceLocation RBraceLoc) {
Module *Sema::PushGlobalModuleFragment(SourceLocation BeginLoc,
bool IsImplicit) {
- ModuleMap &Map = PP.getHeaderSearchInfo().getModuleMap();
- Module *GlobalModule =
- Map.createGlobalModuleFragmentForModuleUnit(BeginLoc, getCurrentModule());
- assert(GlobalModule && "module creation should not fail");
+ // We shouldn't create new global module fragment if there is already
+ // one.
+ if (!GlobalModuleFragment) {
+ ModuleMap &Map = PP.getHeaderSearchInfo().getModuleMap();
+ GlobalModuleFragment = Map.createGlobalModuleFragmentForModuleUnit(
+ BeginLoc, getCurrentModule());
+ }
+
+ assert(GlobalModuleFragment && "module creation should not fail");
// Enter the scope of the global module.
- ModuleScopes.push_back({BeginLoc, GlobalModule,
+ ModuleScopes.push_back({BeginLoc, GlobalModuleFragment,
/*ModuleInterface=*/false,
+ /*IsPartition=*/false,
/*ImplicitGlobalModuleFragment=*/IsImplicit,
- /*VisibleModuleSet*/{}});
- VisibleModules.setVisible(GlobalModule, BeginLoc);
+ /*OuterVisibleModules=*/{}});
+ VisibleModules.setVisible(GlobalModuleFragment, BeginLoc);
- return GlobalModule;
+ return GlobalModuleFragment;
}
void Sema::PopGlobalModuleFragment() {
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index a500ad4f0220..6f501965552e 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -35,6 +35,7 @@
#include "llvm/ADT/IndexedMap.h"
#include "llvm/ADT/PointerEmbeddedInt.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Frontend/OpenMP/OMPAssume.h"
#include "llvm/Frontend/OpenMP/OMPConstants.h"
@@ -58,7 +59,8 @@ enum DefaultDataSharingAttributes {
DSA_unspecified = 0, /// Data sharing attribute not specified.
DSA_none = 1 << 0, /// Default data sharing attribute 'none'.
DSA_shared = 1 << 1, /// Default data sharing attribute 'shared'.
- DSA_firstprivate = 1 << 2, /// Default data sharing attribute 'firstprivate'.
+ DSA_private = 1 << 2, /// Default data sharing attribute 'private'.
+ DSA_firstprivate = 1 << 3, /// Default data sharing attribute 'firstprivate'.
};
/// Stack for tracking declarations used in OpenMP directives and
@@ -175,6 +177,7 @@ private:
bool HasMutipleLoops = false;
const Decl *PossiblyLoopCounter = nullptr;
bool NowaitRegion = false;
+ bool UntiedRegion = false;
bool CancelRegion = false;
bool LoopStart = false;
bool BodyComplete = false;
@@ -193,6 +196,22 @@ private:
llvm::DenseSet<CanonicalDeclPtr<Decl>> UsedInScanDirective;
llvm::DenseMap<CanonicalDeclPtr<const Decl>, UsesAllocatorsDeclKind>
UsesAllocatorsDecls;
+ /// Data is required on creating capture fields for implicit
+ /// default first|private clause.
+ struct ImplicitDefaultFDInfoTy {
+ /// Field decl.
+ const FieldDecl *FD = nullptr;
+ /// Nesting stack level
+ size_t StackLevel = 0;
+ /// Capture variable decl.
+ VarDecl *VD = nullptr;
+ ImplicitDefaultFDInfoTy(const FieldDecl *FD, size_t StackLevel,
+ VarDecl *VD)
+ : FD(FD), StackLevel(StackLevel), VD(VD) {}
+ };
+ /// List of captured fields
+ llvm::SmallVector<ImplicitDefaultFDInfoTy, 8>
+ ImplicitDefaultFirstprivateFDs;
Expr *DeclareMapperVar = nullptr;
SharingMapTy(OpenMPDirectiveKind DKind, DeclarationNameInfo Name,
Scope *CurScope, SourceLocation Loc)
@@ -574,7 +593,9 @@ public:
/// predicate.
const DSAVarData
hasDSA(ValueDecl *D,
- const llvm::function_ref<bool(OpenMPClauseKind, bool)> CPred,
+ const llvm::function_ref<bool(OpenMPClauseKind, bool,
+ DefaultDataSharingAttributes)>
+ CPred,
const llvm::function_ref<bool(OpenMPDirectiveKind)> DPred,
bool FromParent) const;
/// Checks if the specified variables has data-sharing attributes which
@@ -693,6 +714,11 @@ public:
getTopOfStack().DefaultAttr = DSA_shared;
getTopOfStack().DefaultAttrLoc = Loc;
}
+ /// Set default data sharing attribute to private.
+ void setDefaultDSAPrivate(SourceLocation Loc) {
+ getTopOfStack().DefaultAttr = DSA_private;
+ getTopOfStack().DefaultAttrLoc = Loc;
+ }
/// Set default data sharing attribute to firstprivate.
void setDefaultDSAFirstPrivate(SourceLocation Loc) {
getTopOfStack().DefaultAttr = DSA_firstprivate;
@@ -820,7 +846,7 @@ public:
/// Returns optional parameter for the ordered region.
std::pair<const Expr *, OMPOrderedClause *> getOrderedRegionParam() const {
if (const SharingMapTy *Top = getTopOfStackOrNull())
- if (Top->OrderedRegion.hasValue())
+ if (Top->OrderedRegion)
return Top->OrderedRegion.getValue();
return std::make_pair(nullptr, nullptr);
}
@@ -835,7 +861,7 @@ public:
std::pair<const Expr *, OMPOrderedClause *>
getParentOrderedRegionParam() const {
if (const SharingMapTy *Parent = getSecondOnStackOrNull())
- if (Parent->OrderedRegion.hasValue())
+ if (Parent->OrderedRegion)
return Parent->OrderedRegion.getValue();
return std::make_pair(nullptr, nullptr);
}
@@ -850,6 +876,15 @@ public:
return Parent->NowaitRegion;
return false;
}
+ /// Marks current region as untied (it has a 'untied' clause).
+ void setUntiedRegion(bool IsUntied = true) {
+ getTopOfStack().UntiedRegion = IsUntied;
+ }
+ /// Return true if current region is untied.
+ bool isUntiedRegion() const {
+ const SharingMapTy *Top = getTopOfStackOrNull();
+ return Top ? Top->UntiedRegion : false;
+ }
/// Marks parent region as cancel region.
void setParentCancelRegion(bool Cancel = true) {
if (SharingMapTy *Parent = getSecondOnStackOrNull())
@@ -1103,6 +1138,52 @@ public:
const SharingMapTy *Top = getTopOfStackOrNull();
return Top ? Top->DeclareMapperVar : nullptr;
}
+ /// get captured field from ImplicitDefaultFirstprivateFDs
+ VarDecl *getImplicitFDCapExprDecl(const FieldDecl *FD) const {
+ const_iterator I = begin();
+ const_iterator EndI = end();
+ size_t StackLevel = getStackSize();
+ for (; I != EndI; ++I) {
+ if (I->DefaultAttr == DSA_firstprivate || I->DefaultAttr == DSA_private)
+ break;
+ StackLevel--;
+ }
+ assert((StackLevel > 0 && I != EndI) || (StackLevel == 0 && I == EndI));
+ if (I == EndI)
+ return nullptr;
+ for (const auto &IFD : I->ImplicitDefaultFirstprivateFDs)
+ if (IFD.FD == FD && IFD.StackLevel == StackLevel)
+ return IFD.VD;
+ return nullptr;
+ }
+ /// Check if capture decl is field captured in ImplicitDefaultFirstprivateFDs
+ bool isImplicitDefaultFirstprivateFD(VarDecl *VD) const {
+ const_iterator I = begin();
+ const_iterator EndI = end();
+ for (; I != EndI; ++I)
+ if (I->DefaultAttr == DSA_firstprivate || I->DefaultAttr == DSA_private)
+ break;
+ if (I == EndI)
+ return false;
+ for (const auto &IFD : I->ImplicitDefaultFirstprivateFDs)
+ if (IFD.VD == VD)
+ return true;
+ return false;
+ }
+ /// Store capture FD info in ImplicitDefaultFirstprivateFDs
+ void addImplicitDefaultFirstprivateFD(const FieldDecl *FD, VarDecl *VD) {
+ iterator I = begin();
+ const_iterator EndI = end();
+ size_t StackLevel = getStackSize();
+ for (; I != EndI; ++I) {
+ if (I->DefaultAttr == DSA_private || I->DefaultAttr == DSA_firstprivate) {
+ I->ImplicitDefaultFirstprivateFDs.emplace_back(FD, StackLevel, VD);
+ break;
+ }
+ StackLevel--;
+ }
+ assert((StackLevel > 0 && I != EndI) || (StackLevel == 0 && I == EndI));
+ }
};
bool isImplicitTaskingRegion(OpenMPDirectiveKind DKind) {
@@ -1222,7 +1303,7 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(const_iterator &Iter,
case DSA_none:
return DVar;
case DSA_firstprivate:
- if (VD->getStorageDuration() == SD_Static &&
+ if (VD && VD->getStorageDuration() == SD_Static &&
VD->getDeclContext()->isFileContext()) {
DVar.CKind = OMPC_unknown;
} else {
@@ -1230,6 +1311,18 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(const_iterator &Iter,
}
DVar.ImplicitDSALoc = Iter->DefaultAttrLoc;
return DVar;
+ case DSA_private:
+ // each variable with static storage duration that is declared
+ // in a namespace or global scope and referenced in the construct,
+ // and that does not have a predetermined data-sharing attribute
+ if (VD && VD->getStorageDuration() == SD_Static &&
+ VD->getDeclContext()->isFileContext()) {
+ DVar.CKind = OMPC_unknown;
+ } else {
+ DVar.CKind = OMPC_private;
+ }
+ DVar.ImplicitDSALoc = Iter->DefaultAttrLoc;
+ return DVar;
case DSA_unspecified:
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a Construct, implicitly determined, p.2]
@@ -1786,7 +1879,9 @@ const DSAStackTy::DSAVarData DSAStackTy::getImplicitDSA(ValueDecl *D,
const DSAStackTy::DSAVarData
DSAStackTy::hasDSA(ValueDecl *D,
- const llvm::function_ref<bool(OpenMPClauseKind, bool)> CPred,
+ const llvm::function_ref<bool(OpenMPClauseKind, bool,
+ DefaultDataSharingAttributes)>
+ CPred,
const llvm::function_ref<bool(OpenMPDirectiveKind)> DPred,
bool FromParent) const {
if (isStackEmpty())
@@ -1802,7 +1897,7 @@ DSAStackTy::hasDSA(ValueDecl *D,
continue;
const_iterator NewI = I;
DSAVarData DVar = getDSA(NewI, D);
- if (I == NewI && CPred(DVar.CKind, DVar.AppliedToPointee))
+ if (I == NewI && CPred(DVar.CKind, DVar.AppliedToPointee, I->DefaultAttr))
return DVar;
}
return {};
@@ -2131,7 +2226,8 @@ bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level,
!cast<OMPCapturedExprDecl>(D)->getInit()->isGLValue()) &&
// If the variable is implicitly firstprivate and scalar - capture by
// copy
- !(DSAStack->getDefaultDSA() == DSA_firstprivate &&
+ !((DSAStack->getDefaultDSA() == DSA_firstprivate ||
+ DSAStack->getDefaultDSA() == DSA_private) &&
!DSAStack->hasExplicitDSA(
D, [](OpenMPClauseKind K, bool) { return K != OMPC_unknown; },
Level) &&
@@ -2157,6 +2253,11 @@ unsigned Sema::getOpenMPNestingLevel() const {
return DSAStack->getNestingLevel();
}
+bool Sema::isInOpenMPTaskUntiedContext() const {
+ return isOpenMPTaskingDirective(DSAStack->getCurrentDirective()) &&
+ DSAStack->isUntiedRegion();
+}
+
bool Sema::isInOpenMPTargetExecutionDirective() const {
return (isOpenMPTargetExecutionDirective(DSAStack->getCurrentDirective()) &&
!DSAStack->isClauseParsingMode()) ||
@@ -2168,6 +2269,26 @@ bool Sema::isInOpenMPTargetExecutionDirective() const {
false);
}
+bool Sema::isOpenMPRebuildMemberExpr(ValueDecl *D) {
+ DSAStackTy::DSAVarData DVarPrivate = DSAStack->hasDSA(
+ D,
+ [](OpenMPClauseKind C, bool AppliedToPointee,
+ DefaultDataSharingAttributes DefaultAttr) {
+ return isOpenMPPrivate(C) && !AppliedToPointee &&
+ (DefaultAttr == DSA_firstprivate || DefaultAttr == DSA_private);
+ },
+ [](OpenMPDirectiveKind) { return true; },
+ DSAStack->isClauseParsingMode());
+ if (DVarPrivate.CKind != OMPC_unknown)
+ return true;
+ return false;
+}
+
+static OMPCapturedExprDecl *buildCaptureDecl(Sema &S, IdentifierInfo *Id,
+ Expr *CaptureExpr, bool WithInit,
+ DeclContext *CurContext,
+ bool AsExpression);
+
VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D, bool CheckScopeInfo,
unsigned StopAt) {
assert(LangOpts.OpenMP && "OpenMP is not allowed");
@@ -2266,7 +2387,7 @@ VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D, bool CheckScopeInfo,
// default(none) clause and not used in any clause.
DSAStackTy::DSAVarData DVarPrivate = DSAStack->hasDSA(
D,
- [](OpenMPClauseKind C, bool AppliedToPointee) {
+ [](OpenMPClauseKind C, bool AppliedToPointee, bool) {
return isOpenMPPrivate(C) && !AppliedToPointee;
},
[](OpenMPDirectiveKind) { return true; },
@@ -2274,11 +2395,52 @@ VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D, bool CheckScopeInfo,
// Global shared must not be captured.
if (VD && !VD->hasLocalStorage() && DVarPrivate.CKind == OMPC_unknown &&
((DSAStack->getDefaultDSA() != DSA_none &&
+ DSAStack->getDefaultDSA() != DSA_private &&
DSAStack->getDefaultDSA() != DSA_firstprivate) ||
DVarTop.CKind == OMPC_shared))
return nullptr;
+ auto *FD = dyn_cast<FieldDecl>(D);
+ if (DVarPrivate.CKind != OMPC_unknown && !VD && FD &&
+ !DVarPrivate.PrivateCopy) {
+ DSAStackTy::DSAVarData DVarPrivate = DSAStack->hasDSA(
+ D,
+ [](OpenMPClauseKind C, bool AppliedToPointee,
+ DefaultDataSharingAttributes DefaultAttr) {
+ return isOpenMPPrivate(C) && !AppliedToPointee &&
+ (DefaultAttr == DSA_firstprivate ||
+ DefaultAttr == DSA_private);
+ },
+ [](OpenMPDirectiveKind) { return true; },
+ DSAStack->isClauseParsingMode());
+ if (DVarPrivate.CKind == OMPC_unknown)
+ return nullptr;
+
+ VarDecl *VD = DSAStack->getImplicitFDCapExprDecl(FD);
+ if (VD)
+ return VD;
+ if (getCurrentThisType().isNull())
+ return nullptr;
+ Expr *ThisExpr = BuildCXXThisExpr(SourceLocation(), getCurrentThisType(),
+ /*IsImplicit=*/true);
+ const CXXScopeSpec CS = CXXScopeSpec();
+ Expr *ME = BuildMemberExpr(ThisExpr, /*IsArrow=*/true, SourceLocation(),
+ NestedNameSpecifierLoc(), SourceLocation(), FD,
+ DeclAccessPair::make(FD, FD->getAccess()),
+ /*HadMultipleCandidates=*/false,
+ DeclarationNameInfo(), FD->getType(),
+ VK_LValue, OK_Ordinary);
+ OMPCapturedExprDecl *CD = buildCaptureDecl(
+ *this, FD->getIdentifier(), ME, DVarPrivate.CKind != OMPC_private,
+ CurContext->getParent(), /*AsExpression=*/false);
+ DeclRefExpr *VDPrivateRefExpr = buildDeclRefExpr(
+ *this, CD, CD->getType().getNonReferenceType(), SourceLocation());
+ VD = cast<VarDecl>(VDPrivateRefExpr->getDecl());
+ DSAStack->addImplicitDefaultFirstprivateFD(FD, VD);
+ return VD;
+ }
if (DVarPrivate.CKind != OMPC_unknown ||
(VD && (DSAStack->getDefaultDSA() == DSA_none ||
+ DSAStack->getDefaultDSA() == DSA_private ||
DSAStack->getDefaultDSA() == DSA_firstprivate)))
return VD ? VD : cast<VarDecl>(DVarPrivate.PrivateCopy->getDecl());
}
@@ -2307,6 +2469,23 @@ void Sema::startOpenMPCXXRangeFor() {
OpenMPClauseKind Sema::isOpenMPPrivateDecl(ValueDecl *D, unsigned Level,
unsigned CapLevel) const {
assert(LangOpts.OpenMP && "OpenMP is not allowed");
+ if (DSAStack->getCurrentDirective() != OMPD_unknown &&
+ (!DSAStack->isClauseParsingMode() ||
+ DSAStack->getParentDirective() != OMPD_unknown)) {
+ DSAStackTy::DSAVarData DVarPrivate = DSAStack->hasDSA(
+ D,
+ [](OpenMPClauseKind C, bool AppliedToPointee,
+ DefaultDataSharingAttributes DefaultAttr) {
+ return isOpenMPPrivate(C) && !AppliedToPointee &&
+ DefaultAttr == DSA_private;
+ },
+ [](OpenMPDirectiveKind) { return true; },
+ DSAStack->isClauseParsingMode());
+ if (DVarPrivate.CKind == OMPC_private && isa<OMPCapturedExprDecl>(D) &&
+ DSAStack->isImplicitDefaultFirstprivateFD(cast<VarDecl>(D)) &&
+ !DSAStack->isLoopControlVariable(D).first)
+ return OMPC_private;
+ }
if (DSAStack->hasExplicitDirective(isOpenMPTaskingDirective, Level)) {
bool IsTriviallyCopyable =
D->getType().getNonReferenceType().isTriviallyCopyableType(Context) &&
@@ -2358,7 +2537,7 @@ OpenMPClauseKind Sema::isOpenMPPrivateDecl(ValueDecl *D, unsigned Level,
// User-defined allocators are private since they must be defined in the
// context of target region.
if (DSAStack->hasExplicitDirective(isOpenMPTargetExecutionDirective, Level) &&
- DSAStack->isUsesAllocatorsDecl(Level, D).getValueOr(
+ DSAStack->isUsesAllocatorsDecl(Level, D).value_or(
DSAStackTy::UsesAllocatorsDeclKind::AllocatorTrait) ==
DSAStackTy::UsesAllocatorsDeclKind::UserDefinedAllocator)
return OMPC_private;
@@ -2448,7 +2627,11 @@ bool Sema::isOpenMPGlobalCapturedDecl(ValueDecl *D, unsigned Level,
unsigned NumLevels =
getOpenMPCaptureLevels(DSAStack->getDirective(Level));
if (Level == 0)
- return (NumLevels == CaptureLevel + 1) && TopDVar.CKind != OMPC_shared;
+ // non-file scope static variale with default(firstprivate)
+ // should be gloabal captured.
+ return (NumLevels == CaptureLevel + 1 &&
+ (TopDVar.CKind != OMPC_shared ||
+ DSAStack->getDefaultDSA() == DSA_firstprivate));
do {
--Level;
DSAStackTy::DSAVarData DVar = DSAStack->getImplicitDSA(D, Level);
@@ -2501,7 +2684,7 @@ void Sema::finalizeOpenMPDelayedAnalysis(const FunctionDecl *Caller,
<< HostDevTy;
return;
}
- if (!LangOpts.OpenMPIsDevice && DevTy &&
+ if (!LangOpts.OpenMPIsDevice && !LangOpts.OpenMPOffloadMandatory && DevTy &&
*DevTy == OMPDeclareTargetDeclAttr::DT_NoHost) {
// Diagnose nohost function called during host codegen.
StringRef NoHostDevTy = getOpenMPSimpleClauseTypeName(
@@ -3263,8 +3446,7 @@ void Sema::ActOnOpenMPAssumesDirective(SourceLocation Loc,
continue;
if (auto *CTD = dyn_cast<ClassTemplateDecl>(SubDC)) {
DeclContexts.push_back(CTD->getTemplatedDecl());
- for (auto *S : CTD->specializations())
- DeclContexts.push_back(S);
+ llvm::append_range(DeclContexts, CTD->specializations());
continue;
}
if (auto *DC = dyn_cast<DeclContext>(SubDC))
@@ -3429,6 +3611,7 @@ class DSAAttrChecker final : public StmtVisitor<DSAAttrChecker, void> {
CapturedStmt *CS = nullptr;
const static unsigned DefaultmapKindNum = OMPC_DEFAULTMAP_pointer + 1;
llvm::SmallVector<Expr *, 4> ImplicitFirstprivate;
+ llvm::SmallVector<Expr *, 4> ImplicitPrivate;
llvm::SmallVector<Expr *, 4> ImplicitMap[DefaultmapKindNum][OMPC_MAP_delete];
llvm::SmallVector<OpenMPMapModifierKind, NumberOfOMPMapClauseModifiers>
ImplicitMapModifier[DefaultmapKindNum];
@@ -3483,7 +3666,8 @@ public:
if (auto *VD = dyn_cast<VarDecl>(E->getDecl())) {
// Check the datasharing rules for the expressions in the clauses.
if (!CS || (isa<OMPCapturedExprDecl>(VD) && !CS->capturesVariable(VD) &&
- !Stack->getTopDSA(VD, /*FromParent=*/false).RefExpr)) {
+ !Stack->getTopDSA(VD, /*FromParent=*/false).RefExpr &&
+ !Stack->isImplicitDefaultFirstprivateFD(VD))) {
if (auto *CED = dyn_cast<OMPCapturedExprDecl>(VD))
if (!CED->hasAttr<OMPCaptureNoInitAttr>()) {
Visit(CED->getInit());
@@ -3492,14 +3676,16 @@ public:
} else if (VD->isImplicit() || isa<OMPCapturedExprDecl>(VD))
// Do not analyze internal variables and do not enclose them into
// implicit clauses.
- return;
+ if (!Stack->isImplicitDefaultFirstprivateFD(VD))
+ return;
VD = VD->getCanonicalDecl();
// Skip internally declared variables.
if (VD->hasLocalStorage() && CS && !CS->capturesVariable(VD) &&
+ !Stack->isImplicitDefaultFirstprivateFD(VD) &&
!Stack->isImplicitTaskFirstprivate(VD))
return;
// Skip allocators in uses_allocators clauses.
- if (Stack->isUsesAllocatorsDecl(VD).hasValue())
+ if (Stack->isUsesAllocatorsDecl(VD))
return;
DSAStackTy::DSAVarData DVar = Stack->getTopDSA(VD, /*FromParent=*/false);
@@ -3513,6 +3699,7 @@ public:
if (VD->hasGlobalStorage() && CS && !CS->capturesVariable(VD) &&
(Stack->hasRequiresDeclWithClause<OMPUnifiedSharedMemoryClause>() ||
!Res || *Res != OMPDeclareTargetDeclAttr::MT_Link) &&
+ !Stack->isImplicitDefaultFirstprivateFD(VD) &&
!Stack->isImplicitTaskFirstprivate(VD))
return;
@@ -3524,18 +3711,21 @@ public:
// by being listed in a data-sharing attribute clause.
if (DVar.CKind == OMPC_unknown &&
(Stack->getDefaultDSA() == DSA_none ||
+ Stack->getDefaultDSA() == DSA_private ||
Stack->getDefaultDSA() == DSA_firstprivate) &&
isImplicitOrExplicitTaskingRegion(DKind) &&
VarsWithInheritedDSA.count(VD) == 0) {
bool InheritedDSA = Stack->getDefaultDSA() == DSA_none;
- if (!InheritedDSA && Stack->getDefaultDSA() == DSA_firstprivate) {
+ if (!InheritedDSA && (Stack->getDefaultDSA() == DSA_firstprivate ||
+ Stack->getDefaultDSA() == DSA_private)) {
DSAStackTy::DSAVarData DVar =
Stack->getImplicitDSA(VD, /*FromParent=*/false);
InheritedDSA = DVar.CKind == OMPC_unknown;
}
if (InheritedDSA)
VarsWithInheritedDSA[VD] = E;
- return;
+ if (Stack->getDefaultDSA() == DSA_none)
+ return;
}
// OpenMP 5.0 [2.19.7.2, defaultmap clause, Description]
@@ -3543,7 +3733,7 @@ public:
// construct that does not have a predetermined data-sharing attribute
// and does not appear in a to or link clause on a declare target
// directive must be listed in a data-mapping attribute clause, a
- // data-haring attribute clause (including a data-sharing attribute
+ // data-sharing attribute clause (including a data-sharing attribute
// clause on a combined construct where target. is one of the
// constituent constructs), or an is_device_ptr clause.
OpenMPDefaultmapClauseKind ClauseKind =
@@ -3654,10 +3844,16 @@ public:
// Define implicit data-sharing attributes for task.
DVar = Stack->getImplicitDSA(VD, /*FromParent=*/false);
if (((isOpenMPTaskingDirective(DKind) && DVar.CKind != OMPC_shared) ||
- (Stack->getDefaultDSA() == DSA_firstprivate &&
- DVar.CKind == OMPC_firstprivate && !DVar.RefExpr)) &&
+ (((Stack->getDefaultDSA() == DSA_firstprivate &&
+ DVar.CKind == OMPC_firstprivate) ||
+ (Stack->getDefaultDSA() == DSA_private &&
+ DVar.CKind == OMPC_private)) &&
+ !DVar.RefExpr)) &&
!Stack->isLoopControlVariable(VD).first) {
- ImplicitFirstprivate.push_back(E);
+ if (Stack->getDefaultDSA() == DSA_private)
+ ImplicitPrivate.push_back(E);
+ else
+ ImplicitFirstprivate.push_back(E);
return;
}
@@ -3873,6 +4069,7 @@ public:
ArrayRef<Expr *> getImplicitFirstprivate() const {
return ImplicitFirstprivate;
}
+ ArrayRef<Expr *> getImplicitPrivate() const { return ImplicitPrivate; }
ArrayRef<Expr *> getImplicitMap(OpenMPDefaultmapClauseKind DK,
OpenMPMapClauseKind MK) const {
return ImplicitMap[DK][MK];
@@ -3920,6 +4117,8 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
case OMPD_parallel_for_simd:
case OMPD_parallel_sections:
case OMPD_parallel_master:
+ case OMPD_parallel_masked:
+ case OMPD_parallel_loop:
case OMPD_teams:
case OMPD_teams_distribute:
case OMPD_teams_distribute_simd: {
@@ -3939,6 +4138,8 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
case OMPD_target_parallel:
case OMPD_target_parallel_for:
case OMPD_target_parallel_for_simd:
+ case OMPD_target_teams_loop:
+ case OMPD_target_parallel_loop:
case OMPD_target_teams_distribute:
case OMPD_target_teams_distribute_simd: {
QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1).withConst();
@@ -4078,6 +4279,8 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
case OMPD_taskloop:
case OMPD_taskloop_simd:
case OMPD_master_taskloop:
+ case OMPD_masked_taskloop:
+ case OMPD_masked_taskloop_simd:
case OMPD_master_taskloop_simd: {
QualType KmpInt32Ty =
Context.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1)
@@ -4120,6 +4323,8 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
AlwaysInlineAttr::Keyword_forceinline));
break;
}
+ case OMPD_parallel_masked_taskloop:
+ case OMPD_parallel_masked_taskloop_simd:
case OMPD_parallel_master_taskloop:
case OMPD_parallel_master_taskloop_simd: {
QualType KmpInt32Ty =
@@ -4246,6 +4451,22 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
break;
}
+ case OMPD_teams_loop: {
+ QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1).withConst();
+ QualType KmpInt32PtrTy =
+ Context.getPointerType(KmpInt32Ty).withConst().withRestrict();
+
+ Sema::CapturedParamNameType ParamsTeams[] = {
+ std::make_pair(".global_tid.", KmpInt32PtrTy),
+ std::make_pair(".bound_tid.", KmpInt32PtrTy),
+ std::make_pair(StringRef(), QualType()) // __context with shared vars
+ };
+ // Start a captured region for 'teams'.
+ ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
+ ParamsTeams, /*OpenMPCaptureLevel=*/0);
+ break;
+ }
+
case OMPD_teams_distribute_parallel_for:
case OMPD_teams_distribute_parallel_for_simd: {
QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1).withConst();
@@ -4346,6 +4567,7 @@ int Sema::getOpenMPCaptureLevels(OpenMPDirectiveKind DKind) {
static OMPCapturedExprDecl *buildCaptureDecl(Sema &S, IdentifierInfo *Id,
Expr *CaptureExpr, bool WithInit,
+ DeclContext *CurContext,
bool AsExpression) {
assert(CaptureExpr);
ASTContext &C = S.getASTContext();
@@ -4364,11 +4586,11 @@ static OMPCapturedExprDecl *buildCaptureDecl(Sema &S, IdentifierInfo *Id,
}
WithInit = true;
}
- auto *CED = OMPCapturedExprDecl::Create(C, S.CurContext, Id, Ty,
+ auto *CED = OMPCapturedExprDecl::Create(C, CurContext, Id, Ty,
CaptureExpr->getBeginLoc());
if (!WithInit)
CED->addAttr(OMPCaptureNoInitAttr::CreateImplicit(C));
- S.CurContext->addHiddenDecl(CED);
+ CurContext->addHiddenDecl(CED);
Sema::TentativeAnalysisScope Trap(S);
S.AddInitializerToDecl(CED, Init, /*DirectInit=*/false);
return CED;
@@ -4381,6 +4603,7 @@ static DeclRefExpr *buildCapture(Sema &S, ValueDecl *D, Expr *CaptureExpr,
CD = cast<OMPCapturedExprDecl>(VD);
else
CD = buildCaptureDecl(S, D->getIdentifier(), CaptureExpr, WithInit,
+ S.CurContext,
/*AsExpression=*/false);
return buildDeclRefExpr(S, CD, CD->getType().getNonReferenceType(),
CaptureExpr->getExprLoc());
@@ -4391,7 +4614,7 @@ static ExprResult buildCapture(Sema &S, Expr *CaptureExpr, DeclRefExpr *&Ref) {
if (!Ref) {
OMPCapturedExprDecl *CD = buildCaptureDecl(
S, &S.getASTContext().Idents.get(".capture_expr."), CaptureExpr,
- /*WithInit=*/true, /*AsExpression=*/true);
+ /*WithInit=*/true, S.CurContext, /*AsExpression=*/true);
Ref = buildDeclRefExpr(S, CD, CD->getType().getNonReferenceType(),
CaptureExpr->getExprLoc());
}
@@ -4533,7 +4756,8 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S,
// This is required for proper codegen.
for (OMPClause *Clause : Clauses) {
if (!LangOpts.OpenMPSimd &&
- isOpenMPTaskingDirective(DSAStack->getCurrentDirective()) &&
+ (isOpenMPTaskingDirective(DSAStack->getCurrentDirective()) ||
+ DSAStack->getCurrentDirective() == OMPD_target) &&
Clause->getClauseKind() == OMPC_in_reduction) {
// Capture taskgroup task_reduction descriptors inside the tasking regions
// with the corresponding in_reduction items.
@@ -4794,6 +5018,8 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack,
(SemaRef.getLangOpts().OpenMP >= 50 &&
(ParentRegion == OMPD_taskloop ||
ParentRegion == OMPD_master_taskloop ||
+ ParentRegion == OMPD_masked_taskloop ||
+ ParentRegion == OMPD_parallel_masked_taskloop ||
ParentRegion == OMPD_parallel_master_taskloop)))) ||
(CancelRegion == OMPD_sections &&
(ParentRegion == OMPD_section || ParentRegion == OMPD_sections ||
@@ -4842,6 +5068,7 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack,
isOpenMPTaskingDirective(ParentRegion) ||
ParentRegion == OMPD_master || ParentRegion == OMPD_masked ||
ParentRegion == OMPD_parallel_master ||
+ ParentRegion == OMPD_parallel_masked ||
ParentRegion == OMPD_critical || ParentRegion == OMPD_ordered;
} else if (isOpenMPWorksharingDirective(CurrentRegion) &&
!isOpenMPParallelDirective(CurrentRegion) &&
@@ -4856,6 +5083,7 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack,
isOpenMPTaskingDirective(ParentRegion) ||
ParentRegion == OMPD_master || ParentRegion == OMPD_masked ||
ParentRegion == OMPD_parallel_master ||
+ ParentRegion == OMPD_parallel_masked ||
ParentRegion == OMPD_critical || ParentRegion == OMPD_ordered;
Recommend = ShouldBeInParallelRegion;
} else if (CurrentRegion == OMPD_ordered) {
@@ -4905,9 +5133,13 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack,
// omp_get_num_teams() regions, and omp_get_team_num() regions are the
// only OpenMP regions that may be strictly nested inside the teams
// region.
+ //
+ // As an extension, we permit atomic within teams as well.
NestingProhibited = !isOpenMPParallelDirective(CurrentRegion) &&
!isOpenMPDistributeDirective(CurrentRegion) &&
- CurrentRegion != OMPD_loop;
+ CurrentRegion != OMPD_loop &&
+ !(SemaRef.getLangOpts().OpenMPExtensions &&
+ CurrentRegion == OMPD_atomic);
Recommend = ShouldBeInParallelRegion;
}
if (!NestingProhibited && CurrentRegion == OMPD_loop) {
@@ -5112,8 +5344,7 @@ class AllocatorChecker final : public ConstStmtVisitor<AllocatorChecker, bool> {
public:
bool VisitDeclRefExpr(const DeclRefExpr *E) {
return S->isUsesAllocatorsDecl(E->getDecl())
- .getValueOr(
- DSAStackTy::UsesAllocatorsDeclKind::AllocatorTrait) ==
+ .value_or(DSAStackTy::UsesAllocatorsDeclKind::AllocatorTrait) ==
DSAStackTy::UsesAllocatorsDeclKind::AllocatorTrait;
}
bool VisitStmt(const Stmt *S) {
@@ -5391,7 +5622,7 @@ static CapturedStmt *buildDistanceFunc(Sema &Actions, QualType LogicalTy,
// the step size, rounding-up the effective upper bound ensures that the
// last iteration is included.
// Note that the rounding-up may cause an overflow in a temporry that
- // could be avoided, but would have occured in a C-style for-loop as well.
+ // could be avoided, but would have occurred in a C-style for-loop as well.
Expr *Divisor = BuildVarRef(NewStep);
if (Rel == BO_GE || Rel == BO_GT)
Divisor =
@@ -5848,6 +6079,9 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
SmallVector<Expr *, 4> ImplicitFirstprivates(
DSAChecker.getImplicitFirstprivate().begin(),
DSAChecker.getImplicitFirstprivate().end());
+ SmallVector<Expr *, 4> ImplicitPrivates(
+ DSAChecker.getImplicitPrivate().begin(),
+ DSAChecker.getImplicitPrivate().end());
const unsigned DefaultmapKindNum = OMPC_DEFAULTMAP_pointer + 1;
SmallVector<Expr *, 4> ImplicitMaps[DefaultmapKindNum][OMPC_MAP_delete];
SmallVector<OpenMPMapModifierKind, NumberOfOMPMapClauseModifiers>
@@ -5900,6 +6134,17 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
ErrorFound = true;
}
}
+ if (!ImplicitPrivates.empty()) {
+ if (OMPClause *Implicit =
+ ActOnOpenMPPrivateClause(ImplicitPrivates, SourceLocation(),
+ SourceLocation(), SourceLocation())) {
+ ClausesWithImplicit.push_back(Implicit);
+ ErrorFound = cast<OMPPrivateClause>(Implicit)->varlist_size() !=
+ ImplicitPrivates.size();
+ } else {
+ ErrorFound = true;
+ }
+ }
// OpenMP 5.0 [2.19.7]
// If a list item appears in a reduction, lastprivate or linear
// clause on a combined target construct then it is treated as
@@ -6028,6 +6273,11 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
StartLoc, EndLoc);
AllowedNameModifiers.push_back(OMPD_parallel);
break;
+ case OMPD_parallel_masked:
+ Res = ActOnOpenMPParallelMaskedDirective(ClausesWithImplicit, AStmt,
+ StartLoc, EndLoc);
+ AllowedNameModifiers.push_back(OMPD_parallel);
+ break;
case OMPD_parallel_sections:
Res = ActOnOpenMPParallelSectionsDirective(ClausesWithImplicit, AStmt,
StartLoc, EndLoc);
@@ -6151,6 +6401,11 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
AllowedNameModifiers.push_back(OMPD_taskloop);
break;
+ case OMPD_masked_taskloop:
+ Res = ActOnOpenMPMaskedTaskLoopDirective(
+ ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
+ AllowedNameModifiers.push_back(OMPD_taskloop);
+ break;
case OMPD_master_taskloop_simd:
Res = ActOnOpenMPMasterTaskLoopSimdDirective(
ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
@@ -6158,12 +6413,28 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
if (LangOpts.OpenMP >= 50)
AllowedNameModifiers.push_back(OMPD_simd);
break;
+ case OMPD_masked_taskloop_simd:
+ Res = ActOnOpenMPMaskedTaskLoopSimdDirective(
+ ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
+ if (LangOpts.OpenMP >= 51) {
+ AllowedNameModifiers.push_back(OMPD_taskloop);
+ AllowedNameModifiers.push_back(OMPD_simd);
+ }
+ break;
case OMPD_parallel_master_taskloop:
Res = ActOnOpenMPParallelMasterTaskLoopDirective(
ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
AllowedNameModifiers.push_back(OMPD_taskloop);
AllowedNameModifiers.push_back(OMPD_parallel);
break;
+ case OMPD_parallel_masked_taskloop:
+ Res = ActOnOpenMPParallelMaskedTaskLoopDirective(
+ ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
+ if (LangOpts.OpenMP >= 51) {
+ AllowedNameModifiers.push_back(OMPD_taskloop);
+ AllowedNameModifiers.push_back(OMPD_parallel);
+ }
+ break;
case OMPD_parallel_master_taskloop_simd:
Res = ActOnOpenMPParallelMasterTaskLoopSimdDirective(
ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
@@ -6172,6 +6443,15 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
if (LangOpts.OpenMP >= 50)
AllowedNameModifiers.push_back(OMPD_simd);
break;
+ case OMPD_parallel_masked_taskloop_simd:
+ Res = ActOnOpenMPParallelMaskedTaskLoopSimdDirective(
+ ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
+ if (LangOpts.OpenMP >= 51) {
+ AllowedNameModifiers.push_back(OMPD_taskloop);
+ AllowedNameModifiers.push_back(OMPD_parallel);
+ AllowedNameModifiers.push_back(OMPD_simd);
+ }
+ break;
case OMPD_distribute:
Res = ActOnOpenMPDistributeDirective(ClausesWithImplicit, AStmt, StartLoc,
EndLoc, VarsWithInheritedDSA);
@@ -6280,6 +6560,22 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
Res = ActOnOpenMPGenericLoopDirective(ClausesWithImplicit, AStmt, StartLoc,
EndLoc, VarsWithInheritedDSA);
break;
+ case OMPD_teams_loop:
+ Res = ActOnOpenMPTeamsGenericLoopDirective(
+ ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
+ break;
+ case OMPD_target_teams_loop:
+ Res = ActOnOpenMPTargetTeamsGenericLoopDirective(
+ ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
+ break;
+ case OMPD_parallel_loop:
+ Res = ActOnOpenMPParallelGenericLoopDirective(
+ ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
+ break;
+ case OMPD_target_parallel_loop:
+ Res = ActOnOpenMPTargetParallelGenericLoopDirective(
+ ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
+ break;
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_threadprivate:
@@ -6302,6 +6598,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
// Check variables in the clauses if default(none) or
// default(firstprivate) was specified.
if (DSAStack->getDefaultDSA() == DSA_none ||
+ DSAStack->getDefaultDSA() == DSA_private ||
DSAStack->getDefaultDSA() == DSA_firstprivate) {
DSAAttrChecker DSAChecker(DSAStack, *this, nullptr);
for (OMPClause *C : Clauses) {
@@ -6381,6 +6678,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
case OMPC_use_device_ptr:
case OMPC_use_device_addr:
case OMPC_is_device_ptr:
+ case OMPC_has_device_addr:
case OMPC_nontemporal:
case OMPC_order:
case OMPC_destroy:
@@ -6389,6 +6687,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
case OMPC_uses_allocators:
case OMPC_affinity:
case OMPC_bind:
+ case OMPC_filter:
continue;
case OMPC_allocator:
case OMPC_flush:
@@ -6420,6 +6719,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
continue;
ErrorFound = true;
if (DSAStack->getDefaultDSA() == DSA_none ||
+ DSAStack->getDefaultDSA() == DSA_private ||
DSAStack->getDefaultDSA() == DSA_firstprivate) {
Diag(P.second->getExprLoc(), diag::err_omp_no_dsa_for_variable)
<< P.first << P.second->getSourceRange();
@@ -6996,11 +7296,11 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
}
auto &&HasMultiVersionAttributes = [](const FunctionDecl *FD) {
- return FD->hasAttrs() &&
- (FD->hasAttr<CPUDispatchAttr>() || FD->hasAttr<CPUSpecificAttr>() ||
- FD->hasAttr<TargetAttr>());
+ // The 'target' attribute needs to be separately checked because it does
+ // not always signify a multiversion function declaration.
+ return FD->isMultiVersion() || FD->hasAttr<TargetAttr>();
};
- // OpenMP is not compatible with CPU-specific attributes.
+ // OpenMP is not compatible with multiversion function attributes.
if (HasMultiVersionAttributes(FD)) {
Diag(FD->getLocation(), diag::err_omp_declare_variant_incompat_attributes)
<< SR;
@@ -7171,6 +7471,13 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
return None;
}
+ if (FD->getCanonicalDecl() == NewFD->getCanonicalDecl()) {
+ Diag(VariantRef->getExprLoc(),
+ diag::err_omp_declare_variant_same_base_function)
+ << VariantRef->getSourceRange();
+ return None;
+ }
+
// Check if function types are compatible in C.
if (!LangOpts.CPlusPlus) {
QualType NewType =
@@ -7529,7 +7836,7 @@ public:
bool doesCondDependOnLC() const { return CondDependOnLC.hasValue(); }
/// Returns index of the loop we depend on (starting from 1), or 0 otherwise.
unsigned getLoopDependentIdx() const {
- return InitDependOnLC.getValueOr(CondDependOnLC.getValueOr(0));
+ return InitDependOnLC.value_or(CondDependOnLC.value_or(0));
}
private:
@@ -7632,7 +7939,7 @@ bool OpenMPIterationSpaceChecker::setStep(Expr *NewStep, bool Subtract) {
bool IsConstZero = Result && !Result->getBoolValue();
// != with increment is treated as <; != with decrement is treated as >
- if (!TestIsLessOp.hasValue())
+ if (!TestIsLessOp)
TestIsLessOp = IsConstPos || (IsUnsigned && !Subtract);
if (UB &&
(IsConstZero || (TestIsLessOp.getValue()
@@ -7928,7 +8235,7 @@ bool OpenMPIterationSpaceChecker::checkAndSetCond(Expr *S) {
CE->getArg(1), CE->getSourceRange(), CE->getOperatorLoc());
}
}
- if (Res.hasValue())
+ if (Res)
return *Res;
if (dependent() || SemaRef.CurContext->isDependentContext())
return false;
@@ -8306,7 +8613,7 @@ Expr *OpenMPIterationSpaceChecker::buildNumIterations(
tryBuildCapture(SemaRef, MinLessMaxRes.get(), Captures).get();
if (!MinLessMax)
return nullptr;
- if (TestIsLessOp.getValue()) {
+ if (*TestIsLessOp) {
// LB(MinVal) < LB(MaxVal) ? LB(MinVal) : LB(MaxVal) - min(LB(MinVal),
// LB(MaxVal))
ExprResult MinLB = SemaRef.ActOnConditionalOp(DefaultLoc, DefaultLoc,
@@ -8383,7 +8690,7 @@ Expr *OpenMPIterationSpaceChecker::buildNumIterations(
tryBuildCapture(SemaRef, MinGreaterMaxRes.get(), Captures).get();
if (!MinGreaterMax)
return nullptr;
- if (TestIsLessOp.getValue()) {
+ if (*TestIsLessOp) {
// UB(MinVal) > UB(MaxVal) ? UB(MinVal) : UB(MaxVal) - max(UB(MinVal),
// UB(MaxVal))
ExprResult MaxUB = SemaRef.ActOnConditionalOp(
@@ -8478,7 +8785,7 @@ std::pair<Expr *, Expr *> OpenMPIterationSpaceChecker::buildMinMaxValues(
if (!Upper || !Lower)
return std::make_pair(nullptr, nullptr);
- if (TestIsLessOp.getValue())
+ if (*TestIsLessOp)
MinExpr = Lower;
else
MaxExpr = Upper;
@@ -8522,7 +8829,7 @@ std::pair<Expr *, Expr *> OpenMPIterationSpaceChecker::buildMinMaxValues(
if (!Diff.isUsable())
return std::make_pair(nullptr, nullptr);
- if (TestIsLessOp.getValue()) {
+ if (*TestIsLessOp) {
// MinExpr = Lower;
// MaxExpr = Lower + (((Upper - Lower [- 1]) / Step) * Step)
Diff = SemaRef.BuildBinOp(
@@ -8555,7 +8862,7 @@ std::pair<Expr *, Expr *> OpenMPIterationSpaceChecker::buildMinMaxValues(
if (!Diff.isUsable())
return std::make_pair(nullptr, nullptr);
- if (TestIsLessOp.getValue())
+ if (*TestIsLessOp)
MaxExpr = Diff.get();
else
MinExpr = Diff.get();
@@ -8744,8 +9051,9 @@ void Sema::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init) {
(LangOpts.OpenMP <= 45 || (DVar.CKind != OMPC_lastprivate &&
DVar.CKind != OMPC_private))) ||
((isOpenMPWorksharingDirective(DKind) || DKind == OMPD_taskloop ||
- DKind == OMPD_master_taskloop ||
+ DKind == OMPD_master_taskloop || DKind == OMPD_masked_taskloop ||
DKind == OMPD_parallel_master_taskloop ||
+ DKind == OMPD_parallel_masked_taskloop ||
isOpenMPDistributeDirective(DKind)) &&
!isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown &&
DVar.CKind != OMPC_private && DVar.CKind != OMPC_lastprivate)) &&
@@ -10106,32 +10414,42 @@ StmtResult Sema::ActOnOpenMPDispatchDirective(ArrayRef<OMPClause *> Clauses,
TargetCallLoc);
}
-StmtResult Sema::ActOnOpenMPGenericLoopDirective(
- ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
- SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
- if (!AStmt)
- return StmtError();
-
- // OpenMP 5.1 [2.11.7, loop construct]
- // A list item may not appear in a lastprivate clause unless it is the
- // loop iteration variable of a loop that is associated with the construct.
+static bool checkGenericLoopLastprivate(Sema &S, ArrayRef<OMPClause *> Clauses,
+ OpenMPDirectiveKind K,
+ DSAStackTy *Stack) {
+ bool ErrorFound = false;
for (OMPClause *C : Clauses) {
if (auto *LPC = dyn_cast<OMPLastprivateClause>(C)) {
for (Expr *RefExpr : LPC->varlists()) {
SourceLocation ELoc;
SourceRange ERange;
Expr *SimpleRefExpr = RefExpr;
- auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange);
+ auto Res = getPrivateItem(S, SimpleRefExpr, ELoc, ERange);
if (ValueDecl *D = Res.first) {
- auto &&Info = DSAStack->isLoopControlVariable(D);
+ auto &&Info = Stack->isLoopControlVariable(D);
if (!Info.first) {
- Diag(ELoc, diag::err_omp_lastprivate_loop_var_non_loop_iteration);
- return StmtError();
+ S.Diag(ELoc, diag::err_omp_lastprivate_loop_var_non_loop_iteration)
+ << getOpenMPDirectiveName(K);
+ ErrorFound = true;
}
}
}
}
}
+ return ErrorFound;
+}
+
+StmtResult Sema::ActOnOpenMPGenericLoopDirective(
+ ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
+ if (!AStmt)
+ return StmtError();
+
+ // OpenMP 5.1 [2.11.7, loop construct, Restrictions]
+ // A list item may not appear in a lastprivate clause unless it is the
+ // loop iteration variable of a loop that is associated with the construct.
+ if (checkGenericLoopLastprivate(*this, Clauses, OMPD_loop, DSAStack))
+ return StmtError();
auto *CS = cast<CapturedStmt>(AStmt);
// 1.2.2 OpenMP Language Terminology
@@ -10157,6 +10475,201 @@ StmtResult Sema::ActOnOpenMPGenericLoopDirective(
NestedLoopCount, Clauses, AStmt, B);
}
+StmtResult Sema::ActOnOpenMPTeamsGenericLoopDirective(
+ ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
+ if (!AStmt)
+ return StmtError();
+
+ // OpenMP 5.1 [2.11.7, loop construct, Restrictions]
+ // A list item may not appear in a lastprivate clause unless it is the
+ // loop iteration variable of a loop that is associated with the construct.
+ if (checkGenericLoopLastprivate(*this, Clauses, OMPD_teams_loop, DSAStack))
+ return StmtError();
+
+ auto *CS = cast<CapturedStmt>(AStmt);
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+ for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_teams_loop);
+ ThisCaptureLevel > 1; --ThisCaptureLevel) {
+ CS = cast<CapturedStmt>(CS->getCapturedStmt());
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+ }
+
+ OMPLoopDirective::HelperExprs B;
+ // In presence of clause 'collapse', it will define the nested loops number.
+ unsigned NestedLoopCount =
+ checkOpenMPLoop(OMPD_teams_loop, getCollapseNumberExpr(Clauses),
+ /*OrderedLoopCountExpr=*/nullptr, CS, *this, *DSAStack,
+ VarsWithImplicitDSA, B);
+ if (NestedLoopCount == 0)
+ return StmtError();
+
+ assert((CurContext->isDependentContext() || B.builtAll()) &&
+ "omp loop exprs were not built");
+
+ setFunctionHasBranchProtectedScope();
+ DSAStack->setParentTeamsRegionLoc(StartLoc);
+
+ return OMPTeamsGenericLoopDirective::Create(
+ Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
+}
+
+StmtResult Sema::ActOnOpenMPTargetTeamsGenericLoopDirective(
+ ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
+ if (!AStmt)
+ return StmtError();
+
+ // OpenMP 5.1 [2.11.7, loop construct, Restrictions]
+ // A list item may not appear in a lastprivate clause unless it is the
+ // loop iteration variable of a loop that is associated with the construct.
+ if (checkGenericLoopLastprivate(*this, Clauses, OMPD_target_teams_loop,
+ DSAStack))
+ return StmtError();
+
+ auto *CS = cast<CapturedStmt>(AStmt);
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+ for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_target_teams_loop);
+ ThisCaptureLevel > 1; --ThisCaptureLevel) {
+ CS = cast<CapturedStmt>(CS->getCapturedStmt());
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+ }
+
+ OMPLoopDirective::HelperExprs B;
+ // In presence of clause 'collapse', it will define the nested loops number.
+ unsigned NestedLoopCount =
+ checkOpenMPLoop(OMPD_target_teams_loop, getCollapseNumberExpr(Clauses),
+ /*OrderedLoopCountExpr=*/nullptr, CS, *this, *DSAStack,
+ VarsWithImplicitDSA, B);
+ if (NestedLoopCount == 0)
+ return StmtError();
+
+ assert((CurContext->isDependentContext() || B.builtAll()) &&
+ "omp loop exprs were not built");
+
+ setFunctionHasBranchProtectedScope();
+
+ return OMPTargetTeamsGenericLoopDirective::Create(
+ Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
+}
+
+StmtResult Sema::ActOnOpenMPParallelGenericLoopDirective(
+ ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
+ if (!AStmt)
+ return StmtError();
+
+ // OpenMP 5.1 [2.11.7, loop construct, Restrictions]
+ // A list item may not appear in a lastprivate clause unless it is the
+ // loop iteration variable of a loop that is associated with the construct.
+ if (checkGenericLoopLastprivate(*this, Clauses, OMPD_parallel_loop, DSAStack))
+ return StmtError();
+
+ auto *CS = cast<CapturedStmt>(AStmt);
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+ for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_parallel_loop);
+ ThisCaptureLevel > 1; --ThisCaptureLevel) {
+ CS = cast<CapturedStmt>(CS->getCapturedStmt());
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+ }
+
+ OMPLoopDirective::HelperExprs B;
+ // In presence of clause 'collapse', it will define the nested loops number.
+ unsigned NestedLoopCount =
+ checkOpenMPLoop(OMPD_parallel_loop, getCollapseNumberExpr(Clauses),
+ /*OrderedLoopCountExpr=*/nullptr, CS, *this, *DSAStack,
+ VarsWithImplicitDSA, B);
+ if (NestedLoopCount == 0)
+ return StmtError();
+
+ assert((CurContext->isDependentContext() || B.builtAll()) &&
+ "omp loop exprs were not built");
+
+ setFunctionHasBranchProtectedScope();
+
+ return OMPParallelGenericLoopDirective::Create(
+ Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
+}
+
+StmtResult Sema::ActOnOpenMPTargetParallelGenericLoopDirective(
+ ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
+ if (!AStmt)
+ return StmtError();
+
+ // OpenMP 5.1 [2.11.7, loop construct, Restrictions]
+ // A list item may not appear in a lastprivate clause unless it is the
+ // loop iteration variable of a loop that is associated with the construct.
+ if (checkGenericLoopLastprivate(*this, Clauses, OMPD_target_parallel_loop,
+ DSAStack))
+ return StmtError();
+
+ auto *CS = cast<CapturedStmt>(AStmt);
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+ for (int ThisCaptureLevel = getOpenMPCaptureLevels(OMPD_target_parallel_loop);
+ ThisCaptureLevel > 1; --ThisCaptureLevel) {
+ CS = cast<CapturedStmt>(CS->getCapturedStmt());
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+ }
+
+ OMPLoopDirective::HelperExprs B;
+ // In presence of clause 'collapse', it will define the nested loops number.
+ unsigned NestedLoopCount =
+ checkOpenMPLoop(OMPD_target_parallel_loop, getCollapseNumberExpr(Clauses),
+ /*OrderedLoopCountExpr=*/nullptr, CS, *this, *DSAStack,
+ VarsWithImplicitDSA, B);
+ if (NestedLoopCount == 0)
+ return StmtError();
+
+ assert((CurContext->isDependentContext() || B.builtAll()) &&
+ "omp loop exprs were not built");
+
+ setFunctionHasBranchProtectedScope();
+
+ return OMPTargetParallelGenericLoopDirective::Create(
+ Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
+}
+
StmtResult Sema::ActOnOpenMPSingleDirective(ArrayRef<OMPClause *> Clauses,
Stmt *AStmt,
SourceLocation StartLoc,
@@ -10379,6 +10892,29 @@ Sema::ActOnOpenMPParallelMasterDirective(ArrayRef<OMPClause *> Clauses,
}
StmtResult
+Sema::ActOnOpenMPParallelMaskedDirective(ArrayRef<OMPClause *> Clauses,
+ Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ if (!AStmt)
+ return StmtError();
+
+ assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
+ auto *CS = cast<CapturedStmt>(AStmt);
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+
+ setFunctionHasBranchProtectedScope();
+
+ return OMPParallelMaskedDirective::Create(
+ Context, StartLoc, EndLoc, Clauses, AStmt,
+ DSAStack->getTaskgroupReductionRef());
+}
+
+StmtResult
Sema::ActOnOpenMPParallelSectionsDirective(ArrayRef<OMPClause *> Clauses,
Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc) {
@@ -10925,6 +11461,797 @@ bool OpenMPAtomicUpdateChecker::checkStatement(Stmt *S, unsigned DiagId,
}
return ErrorFound != NoError;
}
+
+/// Get the node id of the fixed point of an expression \a S.
+llvm::FoldingSetNodeID getNodeId(ASTContext &Context, const Expr *S) {
+ llvm::FoldingSetNodeID Id;
+ S->IgnoreParenImpCasts()->Profile(Id, Context, true);
+ return Id;
+}
+
+/// Check if two expressions are same.
+bool checkIfTwoExprsAreSame(ASTContext &Context, const Expr *LHS,
+ const Expr *RHS) {
+ return getNodeId(Context, LHS) == getNodeId(Context, RHS);
+}
+
+class OpenMPAtomicCompareChecker {
+public:
+ /// All kinds of errors that can occur in `atomic compare`
+ enum ErrorTy {
+ /// Empty compound statement.
+ NoStmt = 0,
+ /// More than one statement in a compound statement.
+ MoreThanOneStmt,
+ /// Not an assignment binary operator.
+ NotAnAssignment,
+ /// Not a conditional operator.
+ NotCondOp,
+ /// Wrong false expr. According to the spec, 'x' should be at the false
+ /// expression of a conditional expression.
+ WrongFalseExpr,
+ /// The condition of a conditional expression is not a binary operator.
+ NotABinaryOp,
+ /// Invalid binary operator (not <, >, or ==).
+ InvalidBinaryOp,
+ /// Invalid comparison (not x == e, e == x, x ordop expr, or expr ordop x).
+ InvalidComparison,
+ /// X is not a lvalue.
+ XNotLValue,
+ /// Not a scalar.
+ NotScalar,
+ /// Not an integer.
+ NotInteger,
+ /// 'else' statement is not expected.
+ UnexpectedElse,
+ /// Not an equality operator.
+ NotEQ,
+ /// Invalid assignment (not v == x).
+ InvalidAssignment,
+ /// Not if statement
+ NotIfStmt,
+ /// More than two statements in a compund statement.
+ MoreThanTwoStmts,
+ /// Not a compound statement.
+ NotCompoundStmt,
+ /// No else statement.
+ NoElse,
+ /// Not 'if (r)'.
+ InvalidCondition,
+ /// No error.
+ NoError,
+ };
+
+ struct ErrorInfoTy {
+ ErrorTy Error;
+ SourceLocation ErrorLoc;
+ SourceRange ErrorRange;
+ SourceLocation NoteLoc;
+ SourceRange NoteRange;
+ };
+
+ OpenMPAtomicCompareChecker(Sema &S) : ContextRef(S.getASTContext()) {}
+
+ /// Check if statement \a S is valid for <tt>atomic compare</tt>.
+ bool checkStmt(Stmt *S, ErrorInfoTy &ErrorInfo);
+
+ Expr *getX() const { return X; }
+ Expr *getE() const { return E; }
+ Expr *getD() const { return D; }
+ Expr *getCond() const { return C; }
+ bool isXBinopExpr() const { return IsXBinopExpr; }
+
+protected:
+ /// Reference to ASTContext
+ ASTContext &ContextRef;
+ /// 'x' lvalue part of the source atomic expression.
+ Expr *X = nullptr;
+ /// 'expr' or 'e' rvalue part of the source atomic expression.
+ Expr *E = nullptr;
+ /// 'd' rvalue part of the source atomic expression.
+ Expr *D = nullptr;
+ /// 'cond' part of the source atomic expression. It is in one of the following
+ /// forms:
+ /// expr ordop x
+ /// x ordop expr
+ /// x == e
+ /// e == x
+ Expr *C = nullptr;
+ /// True if the cond expr is in the form of 'x ordop expr'.
+ bool IsXBinopExpr = true;
+
+ /// Check if it is a valid conditional update statement (cond-update-stmt).
+ bool checkCondUpdateStmt(IfStmt *S, ErrorInfoTy &ErrorInfo);
+
+ /// Check if it is a valid conditional expression statement (cond-expr-stmt).
+ bool checkCondExprStmt(Stmt *S, ErrorInfoTy &ErrorInfo);
+
+ /// Check if all captured values have right type.
+ bool checkType(ErrorInfoTy &ErrorInfo) const;
+
+ static bool CheckValue(const Expr *E, ErrorInfoTy &ErrorInfo,
+ bool ShouldBeLValue) {
+ if (ShouldBeLValue && !E->isLValue()) {
+ ErrorInfo.Error = ErrorTy::XNotLValue;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = E->getExprLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = E->getSourceRange();
+ return false;
+ }
+
+ if (!E->isInstantiationDependent()) {
+ QualType QTy = E->getType();
+ if (!QTy->isScalarType()) {
+ ErrorInfo.Error = ErrorTy::NotScalar;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = E->getExprLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = E->getSourceRange();
+ return false;
+ }
+
+ if (!QTy->isIntegerType()) {
+ ErrorInfo.Error = ErrorTy::NotInteger;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = E->getExprLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = E->getSourceRange();
+ return false;
+ }
+ }
+
+ return true;
+ }
+};
+
+bool OpenMPAtomicCompareChecker::checkCondUpdateStmt(IfStmt *S,
+ ErrorInfoTy &ErrorInfo) {
+ auto *Then = S->getThen();
+ if (auto *CS = dyn_cast<CompoundStmt>(Then)) {
+ if (CS->body_empty()) {
+ ErrorInfo.Error = ErrorTy::NoStmt;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CS->getBeginLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = CS->getSourceRange();
+ return false;
+ }
+ if (CS->size() > 1) {
+ ErrorInfo.Error = ErrorTy::MoreThanOneStmt;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CS->getBeginLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = S->getSourceRange();
+ return false;
+ }
+ Then = CS->body_front();
+ }
+
+ auto *BO = dyn_cast<BinaryOperator>(Then);
+ if (!BO) {
+ ErrorInfo.Error = ErrorTy::NotAnAssignment;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = Then->getBeginLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = Then->getSourceRange();
+ return false;
+ }
+ if (BO->getOpcode() != BO_Assign) {
+ ErrorInfo.Error = ErrorTy::NotAnAssignment;
+ ErrorInfo.ErrorLoc = BO->getExprLoc();
+ ErrorInfo.NoteLoc = BO->getOperatorLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = BO->getSourceRange();
+ return false;
+ }
+
+ X = BO->getLHS();
+
+ auto *Cond = dyn_cast<BinaryOperator>(S->getCond());
+ if (!Cond) {
+ ErrorInfo.Error = ErrorTy::NotABinaryOp;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = S->getCond()->getExprLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = S->getCond()->getSourceRange();
+ return false;
+ }
+
+ switch (Cond->getOpcode()) {
+ case BO_EQ: {
+ C = Cond;
+ D = BO->getRHS();
+ if (checkIfTwoExprsAreSame(ContextRef, X, Cond->getLHS())) {
+ E = Cond->getRHS();
+ } else if (checkIfTwoExprsAreSame(ContextRef, X, Cond->getRHS())) {
+ E = Cond->getLHS();
+ } else {
+ ErrorInfo.Error = ErrorTy::InvalidComparison;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = Cond->getExprLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = Cond->getSourceRange();
+ return false;
+ }
+ break;
+ }
+ case BO_LT:
+ case BO_GT: {
+ E = BO->getRHS();
+ if (checkIfTwoExprsAreSame(ContextRef, X, Cond->getLHS()) &&
+ checkIfTwoExprsAreSame(ContextRef, E, Cond->getRHS())) {
+ C = Cond;
+ } else if (checkIfTwoExprsAreSame(ContextRef, E, Cond->getLHS()) &&
+ checkIfTwoExprsAreSame(ContextRef, X, Cond->getRHS())) {
+ C = Cond;
+ IsXBinopExpr = false;
+ } else {
+ ErrorInfo.Error = ErrorTy::InvalidComparison;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = Cond->getExprLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = Cond->getSourceRange();
+ return false;
+ }
+ break;
+ }
+ default:
+ ErrorInfo.Error = ErrorTy::InvalidBinaryOp;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = Cond->getExprLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = Cond->getSourceRange();
+ return false;
+ }
+
+ if (S->getElse()) {
+ ErrorInfo.Error = ErrorTy::UnexpectedElse;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = S->getElse()->getBeginLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = S->getElse()->getSourceRange();
+ return false;
+ }
+
+ return true;
+}
+
+bool OpenMPAtomicCompareChecker::checkCondExprStmt(Stmt *S,
+ ErrorInfoTy &ErrorInfo) {
+ auto *BO = dyn_cast<BinaryOperator>(S);
+ if (!BO) {
+ ErrorInfo.Error = ErrorTy::NotAnAssignment;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = S->getBeginLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = S->getSourceRange();
+ return false;
+ }
+ if (BO->getOpcode() != BO_Assign) {
+ ErrorInfo.Error = ErrorTy::NotAnAssignment;
+ ErrorInfo.ErrorLoc = BO->getExprLoc();
+ ErrorInfo.NoteLoc = BO->getOperatorLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = BO->getSourceRange();
+ return false;
+ }
+
+ X = BO->getLHS();
+
+ auto *CO = dyn_cast<ConditionalOperator>(BO->getRHS()->IgnoreParenImpCasts());
+ if (!CO) {
+ ErrorInfo.Error = ErrorTy::NotCondOp;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = BO->getRHS()->getExprLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = BO->getRHS()->getSourceRange();
+ return false;
+ }
+
+ if (!checkIfTwoExprsAreSame(ContextRef, X, CO->getFalseExpr())) {
+ ErrorInfo.Error = ErrorTy::WrongFalseExpr;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CO->getFalseExpr()->getExprLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange =
+ CO->getFalseExpr()->getSourceRange();
+ return false;
+ }
+
+ auto *Cond = dyn_cast<BinaryOperator>(CO->getCond());
+ if (!Cond) {
+ ErrorInfo.Error = ErrorTy::NotABinaryOp;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CO->getCond()->getExprLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange =
+ CO->getCond()->getSourceRange();
+ return false;
+ }
+
+ switch (Cond->getOpcode()) {
+ case BO_EQ: {
+ C = Cond;
+ D = CO->getTrueExpr();
+ if (checkIfTwoExprsAreSame(ContextRef, X, Cond->getLHS())) {
+ E = Cond->getRHS();
+ } else if (checkIfTwoExprsAreSame(ContextRef, X, Cond->getRHS())) {
+ E = Cond->getLHS();
+ } else {
+ ErrorInfo.Error = ErrorTy::InvalidComparison;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = Cond->getExprLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = Cond->getSourceRange();
+ return false;
+ }
+ break;
+ }
+ case BO_LT:
+ case BO_GT: {
+ E = CO->getTrueExpr();
+ if (checkIfTwoExprsAreSame(ContextRef, X, Cond->getLHS()) &&
+ checkIfTwoExprsAreSame(ContextRef, E, Cond->getRHS())) {
+ C = Cond;
+ } else if (checkIfTwoExprsAreSame(ContextRef, E, Cond->getLHS()) &&
+ checkIfTwoExprsAreSame(ContextRef, X, Cond->getRHS())) {
+ C = Cond;
+ IsXBinopExpr = false;
+ } else {
+ ErrorInfo.Error = ErrorTy::InvalidComparison;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = Cond->getExprLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = Cond->getSourceRange();
+ return false;
+ }
+ break;
+ }
+ default:
+ ErrorInfo.Error = ErrorTy::InvalidBinaryOp;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = Cond->getExprLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = Cond->getSourceRange();
+ return false;
+ }
+
+ return true;
+}
+
+bool OpenMPAtomicCompareChecker::checkType(ErrorInfoTy &ErrorInfo) const {
+ // 'x' and 'e' cannot be nullptr
+ assert(X && E && "X and E cannot be nullptr");
+
+ if (!CheckValue(X, ErrorInfo, true))
+ return false;
+
+ if (!CheckValue(E, ErrorInfo, false))
+ return false;
+
+ if (D && !CheckValue(D, ErrorInfo, false))
+ return false;
+
+ return true;
+}
+
+bool OpenMPAtomicCompareChecker::checkStmt(
+ Stmt *S, OpenMPAtomicCompareChecker::ErrorInfoTy &ErrorInfo) {
+ auto *CS = dyn_cast<CompoundStmt>(S);
+ if (CS) {
+ if (CS->body_empty()) {
+ ErrorInfo.Error = ErrorTy::NoStmt;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CS->getBeginLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = CS->getSourceRange();
+ return false;
+ }
+
+ if (CS->size() != 1) {
+ ErrorInfo.Error = ErrorTy::MoreThanOneStmt;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CS->getBeginLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = CS->getSourceRange();
+ return false;
+ }
+ S = CS->body_front();
+ }
+
+ auto Res = false;
+
+ if (auto *IS = dyn_cast<IfStmt>(S)) {
+ // Check if the statement is in one of the following forms
+ // (cond-update-stmt):
+ // if (expr ordop x) { x = expr; }
+ // if (x ordop expr) { x = expr; }
+ // if (x == e) { x = d; }
+ Res = checkCondUpdateStmt(IS, ErrorInfo);
+ } else {
+ // Check if the statement is in one of the following forms (cond-expr-stmt):
+ // x = expr ordop x ? expr : x;
+ // x = x ordop expr ? expr : x;
+ // x = x == e ? d : x;
+ Res = checkCondExprStmt(S, ErrorInfo);
+ }
+
+ if (!Res)
+ return false;
+
+ return checkType(ErrorInfo);
+}
+
+class OpenMPAtomicCompareCaptureChecker final
+ : public OpenMPAtomicCompareChecker {
+public:
+ OpenMPAtomicCompareCaptureChecker(Sema &S) : OpenMPAtomicCompareChecker(S) {}
+
+ Expr *getV() const { return V; }
+ Expr *getR() const { return R; }
+ bool isFailOnly() const { return IsFailOnly; }
+ bool isPostfixUpdate() const { return IsPostfixUpdate; }
+
+ /// Check if statement \a S is valid for <tt>atomic compare capture</tt>.
+ bool checkStmt(Stmt *S, ErrorInfoTy &ErrorInfo);
+
+private:
+ bool checkType(ErrorInfoTy &ErrorInfo);
+
+ // NOTE: Form 3, 4, 5 in the following comments mean the 3rd, 4th, and 5th
+ // form of 'conditional-update-capture-atomic' structured block on the v5.2
+ // spec p.p. 82:
+ // (1) { v = x; cond-update-stmt }
+ // (2) { cond-update-stmt v = x; }
+ // (3) if(x == e) { x = d; } else { v = x; }
+ // (4) { r = x == e; if(r) { x = d; } }
+ // (5) { r = x == e; if(r) { x = d; } else { v = x; } }
+
+ /// Check if it is valid 'if(x == e) { x = d; } else { v = x; }' (form 3)
+ bool checkForm3(IfStmt *S, ErrorInfoTy &ErrorInfo);
+
+ /// Check if it is valid '{ r = x == e; if(r) { x = d; } }',
+ /// or '{ r = x == e; if(r) { x = d; } else { v = x; } }' (form 4 and 5)
+ bool checkForm45(Stmt *S, ErrorInfoTy &ErrorInfo);
+
+ /// 'v' lvalue part of the source atomic expression.
+ Expr *V = nullptr;
+ /// 'r' lvalue part of the source atomic expression.
+ Expr *R = nullptr;
+ /// If 'v' is only updated when the comparison fails.
+ bool IsFailOnly = false;
+ /// If original value of 'x' must be stored in 'v', not an updated one.
+ bool IsPostfixUpdate = false;
+};
+
+bool OpenMPAtomicCompareCaptureChecker::checkType(ErrorInfoTy &ErrorInfo) {
+ if (!OpenMPAtomicCompareChecker::checkType(ErrorInfo))
+ return false;
+
+ if (V && !CheckValue(V, ErrorInfo, true))
+ return false;
+
+ if (R && !CheckValue(R, ErrorInfo, true))
+ return false;
+
+ return true;
+}
+
+bool OpenMPAtomicCompareCaptureChecker::checkForm3(IfStmt *S,
+ ErrorInfoTy &ErrorInfo) {
+ IsFailOnly = true;
+
+ auto *Then = S->getThen();
+ if (auto *CS = dyn_cast<CompoundStmt>(Then)) {
+ if (CS->body_empty()) {
+ ErrorInfo.Error = ErrorTy::NoStmt;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CS->getBeginLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = CS->getSourceRange();
+ return false;
+ }
+ if (CS->size() > 1) {
+ ErrorInfo.Error = ErrorTy::MoreThanOneStmt;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CS->getBeginLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = CS->getSourceRange();
+ return false;
+ }
+ Then = CS->body_front();
+ }
+
+ auto *BO = dyn_cast<BinaryOperator>(Then);
+ if (!BO) {
+ ErrorInfo.Error = ErrorTy::NotAnAssignment;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = Then->getBeginLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = Then->getSourceRange();
+ return false;
+ }
+ if (BO->getOpcode() != BO_Assign) {
+ ErrorInfo.Error = ErrorTy::NotAnAssignment;
+ ErrorInfo.ErrorLoc = BO->getExprLoc();
+ ErrorInfo.NoteLoc = BO->getOperatorLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = BO->getSourceRange();
+ return false;
+ }
+
+ X = BO->getLHS();
+ D = BO->getRHS();
+
+ auto *Cond = dyn_cast<BinaryOperator>(S->getCond());
+ if (!Cond) {
+ ErrorInfo.Error = ErrorTy::NotABinaryOp;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = S->getCond()->getExprLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = S->getCond()->getSourceRange();
+ return false;
+ }
+ if (Cond->getOpcode() != BO_EQ) {
+ ErrorInfo.Error = ErrorTy::NotEQ;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = Cond->getExprLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = Cond->getSourceRange();
+ return false;
+ }
+
+ if (checkIfTwoExprsAreSame(ContextRef, X, Cond->getLHS())) {
+ E = Cond->getRHS();
+ } else if (checkIfTwoExprsAreSame(ContextRef, X, Cond->getRHS())) {
+ E = Cond->getLHS();
+ } else {
+ ErrorInfo.Error = ErrorTy::InvalidComparison;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = Cond->getExprLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = Cond->getSourceRange();
+ return false;
+ }
+
+ C = Cond;
+
+ if (!S->getElse()) {
+ ErrorInfo.Error = ErrorTy::NoElse;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = S->getBeginLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = S->getSourceRange();
+ return false;
+ }
+
+ auto *Else = S->getElse();
+ if (auto *CS = dyn_cast<CompoundStmt>(Else)) {
+ if (CS->body_empty()) {
+ ErrorInfo.Error = ErrorTy::NoStmt;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CS->getBeginLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = CS->getSourceRange();
+ return false;
+ }
+ if (CS->size() > 1) {
+ ErrorInfo.Error = ErrorTy::MoreThanOneStmt;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CS->getBeginLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = S->getSourceRange();
+ return false;
+ }
+ Else = CS->body_front();
+ }
+
+ auto *ElseBO = dyn_cast<BinaryOperator>(Else);
+ if (!ElseBO) {
+ ErrorInfo.Error = ErrorTy::NotAnAssignment;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = Else->getBeginLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = Else->getSourceRange();
+ return false;
+ }
+ if (ElseBO->getOpcode() != BO_Assign) {
+ ErrorInfo.Error = ErrorTy::NotAnAssignment;
+ ErrorInfo.ErrorLoc = ElseBO->getExprLoc();
+ ErrorInfo.NoteLoc = ElseBO->getOperatorLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = ElseBO->getSourceRange();
+ return false;
+ }
+
+ if (!checkIfTwoExprsAreSame(ContextRef, X, ElseBO->getRHS())) {
+ ErrorInfo.Error = ErrorTy::InvalidAssignment;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = ElseBO->getRHS()->getExprLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange =
+ ElseBO->getRHS()->getSourceRange();
+ return false;
+ }
+
+ V = ElseBO->getLHS();
+
+ return checkType(ErrorInfo);
+}
+
+bool OpenMPAtomicCompareCaptureChecker::checkForm45(Stmt *S,
+ ErrorInfoTy &ErrorInfo) {
+ // We don't check here as they should be already done before call this
+ // function.
+ auto *CS = cast<CompoundStmt>(S);
+ assert(CS->size() == 2 && "CompoundStmt size is not expected");
+ auto *S1 = cast<BinaryOperator>(CS->body_front());
+ auto *S2 = cast<IfStmt>(CS->body_back());
+ assert(S1->getOpcode() == BO_Assign && "unexpected binary operator");
+
+ if (!checkIfTwoExprsAreSame(ContextRef, S1->getLHS(), S2->getCond())) {
+ ErrorInfo.Error = ErrorTy::InvalidCondition;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = S2->getCond()->getExprLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = S1->getLHS()->getSourceRange();
+ return false;
+ }
+
+ R = S1->getLHS();
+
+ auto *Then = S2->getThen();
+ if (auto *ThenCS = dyn_cast<CompoundStmt>(Then)) {
+ if (ThenCS->body_empty()) {
+ ErrorInfo.Error = ErrorTy::NoStmt;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = ThenCS->getBeginLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = ThenCS->getSourceRange();
+ return false;
+ }
+ if (ThenCS->size() > 1) {
+ ErrorInfo.Error = ErrorTy::MoreThanOneStmt;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = ThenCS->getBeginLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = ThenCS->getSourceRange();
+ return false;
+ }
+ Then = ThenCS->body_front();
+ }
+
+ auto *ThenBO = dyn_cast<BinaryOperator>(Then);
+ if (!ThenBO) {
+ ErrorInfo.Error = ErrorTy::NotAnAssignment;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = S2->getBeginLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = S2->getSourceRange();
+ return false;
+ }
+ if (ThenBO->getOpcode() != BO_Assign) {
+ ErrorInfo.Error = ErrorTy::NotAnAssignment;
+ ErrorInfo.ErrorLoc = ThenBO->getExprLoc();
+ ErrorInfo.NoteLoc = ThenBO->getOperatorLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = ThenBO->getSourceRange();
+ return false;
+ }
+
+ X = ThenBO->getLHS();
+ D = ThenBO->getRHS();
+
+ auto *BO = cast<BinaryOperator>(S1->getRHS()->IgnoreImpCasts());
+ if (BO->getOpcode() != BO_EQ) {
+ ErrorInfo.Error = ErrorTy::NotEQ;
+ ErrorInfo.ErrorLoc = BO->getExprLoc();
+ ErrorInfo.NoteLoc = BO->getOperatorLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = BO->getSourceRange();
+ return false;
+ }
+
+ C = BO;
+
+ if (checkIfTwoExprsAreSame(ContextRef, X, BO->getLHS())) {
+ E = BO->getRHS();
+ } else if (checkIfTwoExprsAreSame(ContextRef, X, BO->getRHS())) {
+ E = BO->getLHS();
+ } else {
+ ErrorInfo.Error = ErrorTy::InvalidComparison;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = BO->getExprLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = BO->getSourceRange();
+ return false;
+ }
+
+ if (S2->getElse()) {
+ IsFailOnly = true;
+
+ auto *Else = S2->getElse();
+ if (auto *ElseCS = dyn_cast<CompoundStmt>(Else)) {
+ if (ElseCS->body_empty()) {
+ ErrorInfo.Error = ErrorTy::NoStmt;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = ElseCS->getBeginLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = ElseCS->getSourceRange();
+ return false;
+ }
+ if (ElseCS->size() > 1) {
+ ErrorInfo.Error = ErrorTy::MoreThanOneStmt;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = ElseCS->getBeginLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = ElseCS->getSourceRange();
+ return false;
+ }
+ Else = ElseCS->body_front();
+ }
+
+ auto *ElseBO = dyn_cast<BinaryOperator>(Else);
+ if (!ElseBO) {
+ ErrorInfo.Error = ErrorTy::NotAnAssignment;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = Else->getBeginLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = Else->getSourceRange();
+ return false;
+ }
+ if (ElseBO->getOpcode() != BO_Assign) {
+ ErrorInfo.Error = ErrorTy::NotAnAssignment;
+ ErrorInfo.ErrorLoc = ElseBO->getExprLoc();
+ ErrorInfo.NoteLoc = ElseBO->getOperatorLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = ElseBO->getSourceRange();
+ return false;
+ }
+ if (!checkIfTwoExprsAreSame(ContextRef, X, ElseBO->getRHS())) {
+ ErrorInfo.Error = ErrorTy::InvalidAssignment;
+ ErrorInfo.ErrorLoc = ElseBO->getRHS()->getExprLoc();
+ ErrorInfo.NoteLoc = X->getExprLoc();
+ ErrorInfo.ErrorRange = ElseBO->getRHS()->getSourceRange();
+ ErrorInfo.NoteRange = X->getSourceRange();
+ return false;
+ }
+
+ V = ElseBO->getLHS();
+ }
+
+ return checkType(ErrorInfo);
+}
+
+bool OpenMPAtomicCompareCaptureChecker::checkStmt(Stmt *S,
+ ErrorInfoTy &ErrorInfo) {
+ // if(x == e) { x = d; } else { v = x; }
+ if (auto *IS = dyn_cast<IfStmt>(S))
+ return checkForm3(IS, ErrorInfo);
+
+ auto *CS = dyn_cast<CompoundStmt>(S);
+ if (!CS) {
+ ErrorInfo.Error = ErrorTy::NotCompoundStmt;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = S->getBeginLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = S->getSourceRange();
+ return false;
+ }
+ if (CS->body_empty()) {
+ ErrorInfo.Error = ErrorTy::NoStmt;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CS->getBeginLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = CS->getSourceRange();
+ return false;
+ }
+
+ // { if(x == e) { x = d; } else { v = x; } }
+ if (CS->size() == 1) {
+ auto *IS = dyn_cast<IfStmt>(CS->body_front());
+ if (!IS) {
+ ErrorInfo.Error = ErrorTy::NotIfStmt;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CS->body_front()->getBeginLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange =
+ CS->body_front()->getSourceRange();
+ return false;
+ }
+
+ return checkForm3(IS, ErrorInfo);
+ } else if (CS->size() == 2) {
+ auto *S1 = CS->body_front();
+ auto *S2 = CS->body_back();
+
+ Stmt *UpdateStmt = nullptr;
+ Stmt *CondUpdateStmt = nullptr;
+
+ if (auto *BO = dyn_cast<BinaryOperator>(S1)) {
+ // { v = x; cond-update-stmt } or form 45.
+ UpdateStmt = S1;
+ CondUpdateStmt = S2;
+ // Check if form 45.
+ if (isa<BinaryOperator>(BO->getRHS()->IgnoreImpCasts()) &&
+ isa<IfStmt>(S2))
+ return checkForm45(CS, ErrorInfo);
+ // It cannot be set before we the check for form45.
+ IsPostfixUpdate = true;
+ } else {
+ // { cond-update-stmt v = x; }
+ UpdateStmt = S2;
+ CondUpdateStmt = S1;
+ }
+
+ auto CheckCondUpdateStmt = [this, &ErrorInfo](Stmt *CUS) {
+ auto *IS = dyn_cast<IfStmt>(CUS);
+ if (!IS) {
+ ErrorInfo.Error = ErrorTy::NotIfStmt;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CUS->getBeginLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = CUS->getSourceRange();
+ return false;
+ }
+
+ if (!checkCondUpdateStmt(IS, ErrorInfo))
+ return false;
+
+ return true;
+ };
+
+ // CheckUpdateStmt has to be called *after* CheckCondUpdateStmt.
+ auto CheckUpdateStmt = [this, &ErrorInfo](Stmt *US) {
+ auto *BO = dyn_cast<BinaryOperator>(US);
+ if (!BO) {
+ ErrorInfo.Error = ErrorTy::NotAnAssignment;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = US->getBeginLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = US->getSourceRange();
+ return false;
+ }
+ if (BO->getOpcode() != BO_Assign) {
+ ErrorInfo.Error = ErrorTy::NotAnAssignment;
+ ErrorInfo.ErrorLoc = BO->getExprLoc();
+ ErrorInfo.NoteLoc = BO->getOperatorLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = BO->getSourceRange();
+ return false;
+ }
+ if (!checkIfTwoExprsAreSame(ContextRef, this->X, BO->getRHS())) {
+ ErrorInfo.Error = ErrorTy::InvalidAssignment;
+ ErrorInfo.ErrorLoc = BO->getRHS()->getExprLoc();
+ ErrorInfo.NoteLoc = this->X->getExprLoc();
+ ErrorInfo.ErrorRange = BO->getRHS()->getSourceRange();
+ ErrorInfo.NoteRange = this->X->getSourceRange();
+ return false;
+ }
+
+ this->V = BO->getLHS();
+
+ return true;
+ };
+
+ if (!CheckCondUpdateStmt(CondUpdateStmt))
+ return false;
+ if (!CheckUpdateStmt(UpdateStmt))
+ return false;
+ } else {
+ ErrorInfo.Error = ErrorTy::MoreThanTwoStmts;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = CS->getBeginLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = CS->getSourceRange();
+ return false;
+ }
+
+ return checkType(ErrorInfo);
+}
} // namespace
StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses,
@@ -10945,14 +12272,18 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses,
SourceLocation AtomicKindLoc;
OpenMPClauseKind MemOrderKind = OMPC_unknown;
SourceLocation MemOrderLoc;
+ bool MutexClauseEncountered = false;
+ llvm::SmallSet<OpenMPClauseKind, 2> EncounteredAtomicKinds;
for (const OMPClause *C : Clauses) {
switch (C->getClauseKind()) {
case OMPC_read:
case OMPC_write:
case OMPC_update:
+ MutexClauseEncountered = true;
+ LLVM_FALLTHROUGH;
case OMPC_capture:
case OMPC_compare: {
- if (AtomicKind != OMPC_unknown) {
+ if (AtomicKind != OMPC_unknown && MutexClauseEncountered) {
Diag(C->getBeginLoc(), diag::err_omp_atomic_several_clauses)
<< SourceRange(C->getBeginLoc(), C->getEndLoc());
Diag(AtomicKindLoc, diag::note_omp_previous_mem_order_clause)
@@ -10960,6 +12291,12 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses,
} else {
AtomicKind = C->getClauseKind();
AtomicKindLoc = C->getBeginLoc();
+ if (!EncounteredAtomicKinds.insert(C->getClauseKind()).second) {
+ Diag(C->getBeginLoc(), diag::err_omp_atomic_several_clauses)
+ << SourceRange(C->getBeginLoc(), C->getEndLoc());
+ Diag(AtomicKindLoc, diag::note_omp_previous_mem_order_clause)
+ << getOpenMPClauseName(AtomicKind);
+ }
}
break;
}
@@ -10987,6 +12324,12 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses,
llvm_unreachable("unknown clause is encountered");
}
}
+ bool IsCompareCapture = false;
+ if (EncounteredAtomicKinds.contains(OMPC_compare) &&
+ EncounteredAtomicKinds.contains(OMPC_capture)) {
+ IsCompareCapture = true;
+ AtomicKind = OMPC_compare;
+ }
// OpenMP 5.0, 2.17.7 atomic Construct, Restrictions
// If atomic-clause is read then memory-order-clause must not be acq_rel or
// release.
@@ -11018,8 +12361,12 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses,
Expr *V = nullptr;
Expr *E = nullptr;
Expr *UE = nullptr;
+ Expr *D = nullptr;
+ Expr *CE = nullptr;
+ Expr *R = nullptr;
bool IsXLHSInRHSPart = false;
bool IsPostfixUpdate = false;
+ bool IsFailOnly = false;
// OpenMP [2.12.6, atomic Construct]
// In the next expressions:
// * x and v (as applicable) are both l-value expressions with scalar type.
@@ -11405,18 +12752,50 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses,
if (CurContext->isDependentContext())
UE = V = E = X = nullptr;
} else if (AtomicKind == OMPC_compare) {
- // TODO: For now we emit an error here and in emitOMPAtomicExpr we ignore
- // code gen.
- unsigned DiagID = Diags.getCustomDiagID(
- DiagnosticsEngine::Error, "atomic compare is not supported for now");
- Diag(AtomicKindLoc, DiagID);
+ if (IsCompareCapture) {
+ OpenMPAtomicCompareCaptureChecker::ErrorInfoTy ErrorInfo;
+ OpenMPAtomicCompareCaptureChecker Checker(*this);
+ if (!Checker.checkStmt(Body, ErrorInfo)) {
+ Diag(ErrorInfo.ErrorLoc, diag::err_omp_atomic_compare_capture)
+ << ErrorInfo.ErrorRange;
+ Diag(ErrorInfo.NoteLoc, diag::note_omp_atomic_compare)
+ << ErrorInfo.Error << ErrorInfo.NoteRange;
+ return StmtError();
+ }
+ X = Checker.getX();
+ E = Checker.getE();
+ D = Checker.getD();
+ CE = Checker.getCond();
+ V = Checker.getV();
+ R = Checker.getR();
+ // We reuse IsXLHSInRHSPart to tell if it is in the form 'x ordop expr'.
+ IsXLHSInRHSPart = Checker.isXBinopExpr();
+ IsFailOnly = Checker.isFailOnly();
+ IsPostfixUpdate = Checker.isPostfixUpdate();
+ } else {
+ OpenMPAtomicCompareChecker::ErrorInfoTy ErrorInfo;
+ OpenMPAtomicCompareChecker Checker(*this);
+ if (!Checker.checkStmt(Body, ErrorInfo)) {
+ Diag(ErrorInfo.ErrorLoc, diag::err_omp_atomic_compare)
+ << ErrorInfo.ErrorRange;
+ Diag(ErrorInfo.NoteLoc, diag::note_omp_atomic_compare)
+ << ErrorInfo.Error << ErrorInfo.NoteRange;
+ return StmtError();
+ }
+ X = Checker.getX();
+ E = Checker.getE();
+ D = Checker.getD();
+ CE = Checker.getCond();
+ // We reuse IsXLHSInRHSPart to tell if it is in the form 'x ordop expr'.
+ IsXLHSInRHSPart = Checker.isXBinopExpr();
+ }
}
setFunctionHasBranchProtectedScope();
- return OMPAtomicDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt,
- X, V, E, UE, IsXLHSInRHSPart,
- IsPostfixUpdate);
+ return OMPAtomicDirective::Create(
+ Context, StartLoc, EndLoc, Clauses, AStmt,
+ {X, V, R, E, UE, D, CE, IsXLHSInRHSPart, IsPostfixUpdate, IsFailOnly});
}
StmtResult Sema::ActOnOpenMPTargetDirective(ArrayRef<OMPClause *> Clauses,
@@ -11583,6 +12962,26 @@ static bool hasClauses(ArrayRef<OMPClause *> Clauses, const OpenMPClauseKind K,
return hasClauses(Clauses, K) || hasClauses(Clauses, ClauseTypes...);
}
+/// Check if the variables in the mapping clause are externally visible.
+static bool isClauseMappable(ArrayRef<OMPClause *> Clauses) {
+ for (const OMPClause *C : Clauses) {
+ if (auto *TC = dyn_cast<OMPToClause>(C))
+ return llvm::all_of(TC->all_decls(), [](ValueDecl *VD) {
+ return !VD || !VD->hasAttr<OMPDeclareTargetDeclAttr>() ||
+ (VD->isExternallyVisible() &&
+ VD->getVisibility() != HiddenVisibility);
+ });
+ else if (auto *FC = dyn_cast<OMPFromClause>(C))
+ return llvm::all_of(FC->all_decls(), [](ValueDecl *VD) {
+ return !VD || !VD->hasAttr<OMPDeclareTargetDeclAttr>() ||
+ (VD->isExternallyVisible() &&
+ VD->getVisibility() != HiddenVisibility);
+ });
+ }
+
+ return true;
+}
+
StmtResult Sema::ActOnOpenMPTargetDataDirective(ArrayRef<OMPClause *> Clauses,
Stmt *AStmt,
SourceLocation StartLoc,
@@ -11716,6 +13115,12 @@ StmtResult Sema::ActOnOpenMPTargetUpdateDirective(ArrayRef<OMPClause *> Clauses,
Diag(StartLoc, diag::err_omp_at_least_one_motion_clause_required);
return StmtError();
}
+
+ if (!isClauseMappable(Clauses)) {
+ Diag(StartLoc, diag::err_omp_cannot_update_with_internal_linkage);
+ return StmtError();
+ }
+
return OMPTargetUpdateDirective::Create(Context, StartLoc, EndLoc, Clauses,
AStmt);
}
@@ -11927,6 +13332,44 @@ StmtResult Sema::ActOnOpenMPMasterTaskLoopDirective(
DSAStack->isCancelRegion());
}
+StmtResult Sema::ActOnOpenMPMaskedTaskLoopDirective(
+ ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
+ if (!AStmt)
+ return StmtError();
+
+ assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
+ OMPLoopBasedDirective::HelperExprs B;
+ // In presence of clause 'collapse' or 'ordered' with number of loops, it will
+ // define the nested loops number.
+ unsigned NestedLoopCount =
+ checkOpenMPLoop(OMPD_masked_taskloop, getCollapseNumberExpr(Clauses),
+ /*OrderedLoopCountExpr=*/nullptr, AStmt, *this, *DSAStack,
+ VarsWithImplicitDSA, B);
+ if (NestedLoopCount == 0)
+ return StmtError();
+
+ assert((CurContext->isDependentContext() || B.builtAll()) &&
+ "omp for loop exprs were not built");
+
+ // OpenMP, [2.9.2 taskloop Construct, Restrictions]
+ // The grainsize clause and num_tasks clause are mutually exclusive and may
+ // not appear on the same taskloop directive.
+ if (checkMutuallyExclusiveClauses(*this, Clauses,
+ {OMPC_grainsize, OMPC_num_tasks}))
+ return StmtError();
+ // OpenMP, [2.9.2 taskloop Construct, Restrictions]
+ // If a reduction clause is present on the taskloop directive, the nogroup
+ // clause must not be specified.
+ if (checkReductionClauseWithNogroup(*this, Clauses))
+ return StmtError();
+
+ setFunctionHasBranchProtectedScope();
+ return OMPMaskedTaskLoopDirective::Create(Context, StartLoc, EndLoc,
+ NestedLoopCount, Clauses, AStmt, B,
+ DSAStack->isCancelRegion());
+}
+
StmtResult Sema::ActOnOpenMPMasterTaskLoopSimdDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
@@ -11977,6 +13420,56 @@ StmtResult Sema::ActOnOpenMPMasterTaskLoopSimdDirective(
Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
}
+StmtResult Sema::ActOnOpenMPMaskedTaskLoopSimdDirective(
+ ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
+ if (!AStmt)
+ return StmtError();
+
+ assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
+ OMPLoopBasedDirective::HelperExprs B;
+ // In presence of clause 'collapse' or 'ordered' with number of loops, it will
+ // define the nested loops number.
+ unsigned NestedLoopCount =
+ checkOpenMPLoop(OMPD_masked_taskloop_simd, getCollapseNumberExpr(Clauses),
+ /*OrderedLoopCountExpr=*/nullptr, AStmt, *this, *DSAStack,
+ VarsWithImplicitDSA, B);
+ if (NestedLoopCount == 0)
+ return StmtError();
+
+ assert((CurContext->isDependentContext() || B.builtAll()) &&
+ "omp for loop exprs were not built");
+
+ if (!CurContext->isDependentContext()) {
+ // Finalize the clauses that need pre-built expressions for CodeGen.
+ for (OMPClause *C : Clauses) {
+ if (auto *LC = dyn_cast<OMPLinearClause>(C))
+ if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef),
+ B.NumIterations, *this, CurScope,
+ DSAStack))
+ return StmtError();
+ }
+ }
+
+ // OpenMP, [2.9.2 taskloop Construct, Restrictions]
+ // The grainsize clause and num_tasks clause are mutually exclusive and may
+ // not appear on the same taskloop directive.
+ if (checkMutuallyExclusiveClauses(*this, Clauses,
+ {OMPC_grainsize, OMPC_num_tasks}))
+ return StmtError();
+ // OpenMP, [2.9.2 taskloop Construct, Restrictions]
+ // If a reduction clause is present on the taskloop directive, the nogroup
+ // clause must not be specified.
+ if (checkReductionClauseWithNogroup(*this, Clauses))
+ return StmtError();
+ if (checkSimdlenSafelenSpecified(*this, Clauses))
+ return StmtError();
+
+ setFunctionHasBranchProtectedScope();
+ return OMPMaskedTaskLoopSimdDirective::Create(
+ Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
+}
+
StmtResult Sema::ActOnOpenMPParallelMasterTaskLoopDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
@@ -12034,6 +13527,63 @@ StmtResult Sema::ActOnOpenMPParallelMasterTaskLoopDirective(
DSAStack->isCancelRegion());
}
+StmtResult Sema::ActOnOpenMPParallelMaskedTaskLoopDirective(
+ ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
+ if (!AStmt)
+ return StmtError();
+
+ assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
+ auto *CS = cast<CapturedStmt>(AStmt);
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+ for (int ThisCaptureLevel =
+ getOpenMPCaptureLevels(OMPD_parallel_masked_taskloop);
+ ThisCaptureLevel > 1; --ThisCaptureLevel) {
+ CS = cast<CapturedStmt>(CS->getCapturedStmt());
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+ }
+
+ OMPLoopBasedDirective::HelperExprs B;
+ // In presence of clause 'collapse' or 'ordered' with number of loops, it will
+ // define the nested loops number.
+ unsigned NestedLoopCount = checkOpenMPLoop(
+ OMPD_parallel_masked_taskloop, getCollapseNumberExpr(Clauses),
+ /*OrderedLoopCountExpr=*/nullptr, CS, *this, *DSAStack,
+ VarsWithImplicitDSA, B);
+ if (NestedLoopCount == 0)
+ return StmtError();
+
+ assert((CurContext->isDependentContext() || B.builtAll()) &&
+ "omp for loop exprs were not built");
+
+ // OpenMP, [2.9.2 taskloop Construct, Restrictions]
+ // The grainsize clause and num_tasks clause are mutually exclusive and may
+ // not appear on the same taskloop directive.
+ if (checkMutuallyExclusiveClauses(*this, Clauses,
+ {OMPC_grainsize, OMPC_num_tasks}))
+ return StmtError();
+ // OpenMP, [2.9.2 taskloop Construct, Restrictions]
+ // If a reduction clause is present on the taskloop directive, the nogroup
+ // clause must not be specified.
+ if (checkReductionClauseWithNogroup(*this, Clauses))
+ return StmtError();
+
+ setFunctionHasBranchProtectedScope();
+ return OMPParallelMaskedTaskLoopDirective::Create(
+ Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B,
+ DSAStack->isCancelRegion());
+}
+
StmtResult Sema::ActOnOpenMPParallelMasterTaskLoopSimdDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
@@ -12103,6 +13653,75 @@ StmtResult Sema::ActOnOpenMPParallelMasterTaskLoopSimdDirective(
Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
}
+StmtResult Sema::ActOnOpenMPParallelMaskedTaskLoopSimdDirective(
+ ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
+ if (!AStmt)
+ return StmtError();
+
+ assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
+ auto *CS = cast<CapturedStmt>(AStmt);
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+ for (int ThisCaptureLevel =
+ getOpenMPCaptureLevels(OMPD_parallel_masked_taskloop_simd);
+ ThisCaptureLevel > 1; --ThisCaptureLevel) {
+ CS = cast<CapturedStmt>(CS->getCapturedStmt());
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+ }
+
+ OMPLoopBasedDirective::HelperExprs B;
+ // In presence of clause 'collapse' or 'ordered' with number of loops, it will
+ // define the nested loops number.
+ unsigned NestedLoopCount = checkOpenMPLoop(
+ OMPD_parallel_masked_taskloop_simd, getCollapseNumberExpr(Clauses),
+ /*OrderedLoopCountExpr=*/nullptr, CS, *this, *DSAStack,
+ VarsWithImplicitDSA, B);
+ if (NestedLoopCount == 0)
+ return StmtError();
+
+ assert((CurContext->isDependentContext() || B.builtAll()) &&
+ "omp for loop exprs were not built");
+
+ if (!CurContext->isDependentContext()) {
+ // Finalize the clauses that need pre-built expressions for CodeGen.
+ for (OMPClause *C : Clauses) {
+ if (auto *LC = dyn_cast<OMPLinearClause>(C))
+ if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef),
+ B.NumIterations, *this, CurScope,
+ DSAStack))
+ return StmtError();
+ }
+ }
+
+ // OpenMP, [2.9.2 taskloop Construct, Restrictions]
+ // The grainsize clause and num_tasks clause are mutually exclusive and may
+ // not appear on the same taskloop directive.
+ if (checkMutuallyExclusiveClauses(*this, Clauses,
+ {OMPC_grainsize, OMPC_num_tasks}))
+ return StmtError();
+ // OpenMP, [2.9.2 taskloop Construct, Restrictions]
+ // If a reduction clause is present on the taskloop directive, the nogroup
+ // clause must not be specified.
+ if (checkReductionClauseWithNogroup(*this, Clauses))
+ return StmtError();
+ if (checkSimdlenSafelenSpecified(*this, Clauses))
+ return StmtError();
+
+ setFunctionHasBranchProtectedScope();
+ return OMPParallelMaskedTaskLoopSimdDirective::Create(
+ Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
+}
+
StmtResult Sema::ActOnOpenMPDistributeDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
@@ -12899,8 +14518,8 @@ bool Sema::checkTransformableLoopNest(
llvm_unreachable("Unhandled loop transformation");
if (!DependentPreInits)
return;
- for (Decl *C : cast<DeclStmt>(DependentPreInits)->getDeclGroup())
- OriginalInits.back().push_back(C);
+ llvm::append_range(OriginalInits.back(),
+ cast<DeclStmt>(DependentPreInits)->getDeclGroup());
});
assert(OriginalInits.back().empty() && "No preinit after innermost loop");
OriginalInits.pop_back();
@@ -13062,8 +14681,8 @@ StmtResult Sema::ActOnOpenMPTileDirective(ArrayRef<OMPClause *> Clauses,
SmallVector<Stmt *, 4> BodyParts;
BodyParts.append(LoopHelper.Updates.begin(), LoopHelper.Updates.end());
BodyParts.push_back(Inner);
- Inner = CompoundStmt::Create(Context, BodyParts, Inner->getBeginLoc(),
- Inner->getEndLoc());
+ Inner = CompoundStmt::Create(Context, BodyParts, FPOptionsOverride(),
+ Inner->getBeginLoc(), Inner->getEndLoc());
Inner = new (Context)
ForStmt(Context, InitStmt.get(), CondExpr.get(), nullptr,
IncrStmt.get(), Inner, LoopHelper.Init->getBeginLoc(),
@@ -13245,8 +14864,7 @@ StmtResult Sema::ActOnOpenMPUnrollDirective(ArrayRef<OMPClause *> Clauses,
uint64_t Factor;
SourceLocation FactorLoc;
if (Expr *FactorVal = PartialClause->getFactor()) {
- Factor =
- FactorVal->getIntegerConstantExpr(Context).getValue().getZExtValue();
+ Factor = FactorVal->getIntegerConstantExpr(Context)->getZExtValue();
FactorLoc = FactorVal->getExprLoc();
} else {
// TODO: Use a better profitability model.
@@ -13314,11 +14932,11 @@ StmtResult Sema::ActOnOpenMPUnrollDirective(ArrayRef<OMPClause *> Clauses,
if (!EndOfTile.isUsable())
return StmtError();
ExprResult InnerCond1 = BuildBinOp(CurScope, LoopHelper.Cond->getExprLoc(),
- BO_LE, MakeInnerRef(), EndOfTile.get());
+ BO_LT, MakeInnerRef(), EndOfTile.get());
if (!InnerCond1.isUsable())
return StmtError();
ExprResult InnerCond2 =
- BuildBinOp(CurScope, LoopHelper.Cond->getExprLoc(), BO_LE, MakeInnerRef(),
+ BuildBinOp(CurScope, LoopHelper.Cond->getExprLoc(), BO_LT, MakeInnerRef(),
MakeNumIterations());
if (!InnerCond2.isUsable())
return StmtError();
@@ -13338,8 +14956,9 @@ StmtResult Sema::ActOnOpenMPUnrollDirective(ArrayRef<OMPClause *> Clauses,
SmallVector<Stmt *> InnerBodyStmts;
InnerBodyStmts.append(LoopHelper.Updates.begin(), LoopHelper.Updates.end());
InnerBodyStmts.push_back(Body);
- CompoundStmt *InnerBody = CompoundStmt::Create(
- Context, InnerBodyStmts, Body->getBeginLoc(), Body->getEndLoc());
+ CompoundStmt *InnerBody =
+ CompoundStmt::Create(Context, InnerBodyStmts, FPOptionsOverride(),
+ Body->getBeginLoc(), Body->getEndLoc());
ForStmt *InnerFor = new (Context)
ForStmt(Context, InnerInit.get(), InnerCond.get(), nullptr,
InnerIncr.get(), InnerBody, LoopHelper.Init->getBeginLoc(),
@@ -13553,6 +15172,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
LLVM_FALLTHROUGH;
case OMPD_target_parallel:
case OMPD_target_parallel_for:
+ case OMPD_target_parallel_loop:
// If this clause applies to the nested 'parallel' region, capture within
// the 'target' region, otherwise do not capture.
if (NameModifier == OMPD_unknown || NameModifier == OMPD_parallel)
@@ -13586,10 +15206,25 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_target_exit_data:
CaptureRegion = OMPD_task;
break;
+ case OMPD_parallel_masked_taskloop:
+ if (NameModifier == OMPD_unknown || NameModifier == OMPD_taskloop)
+ CaptureRegion = OMPD_parallel;
+ break;
case OMPD_parallel_master_taskloop:
if (NameModifier == OMPD_unknown || NameModifier == OMPD_taskloop)
CaptureRegion = OMPD_parallel;
break;
+ case OMPD_parallel_masked_taskloop_simd:
+ if ((OpenMPVersion <= 45 && NameModifier == OMPD_unknown) ||
+ NameModifier == OMPD_taskloop) {
+ CaptureRegion = OMPD_parallel;
+ break;
+ }
+ if (OpenMPVersion <= 45)
+ break;
+ if (NameModifier == OMPD_unknown || NameModifier == OMPD_simd)
+ CaptureRegion = OMPD_taskloop;
+ break;
case OMPD_parallel_master_taskloop_simd:
if ((OpenMPVersion <= 45 && NameModifier == OMPD_unknown) ||
NameModifier == OMPD_taskloop) {
@@ -13609,6 +15244,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
break;
case OMPD_taskloop_simd:
case OMPD_master_taskloop_simd:
+ case OMPD_masked_taskloop_simd:
if (OpenMPVersion <= 45)
break;
if (NameModifier == OMPD_unknown || NameModifier == OMPD_simd)
@@ -13634,15 +15270,19 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_cancel:
case OMPD_parallel:
case OMPD_parallel_master:
+ case OMPD_parallel_masked:
case OMPD_parallel_sections:
case OMPD_parallel_for:
+ case OMPD_parallel_loop:
case OMPD_target:
case OMPD_target_teams:
case OMPD_target_teams_distribute:
+ case OMPD_target_teams_loop:
case OMPD_distribute_parallel_for:
case OMPD_task:
case OMPD_taskloop:
case OMPD_master_taskloop:
+ case OMPD_masked_taskloop:
case OMPD_target_data:
case OMPD_simd:
case OMPD_for_simd:
@@ -13667,6 +15307,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_loop:
+ case OMPD_teams_loop:
case OMPD_teams:
case OMPD_tile:
case OMPD_unroll:
@@ -13695,6 +15336,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_target_parallel:
case OMPD_target_parallel_for:
case OMPD_target_parallel_for_simd:
+ case OMPD_target_parallel_loop:
CaptureRegion = OMPD_target;
break;
case OMPD_teams_distribute_parallel_for:
@@ -13705,13 +15347,17 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
break;
case OMPD_parallel:
case OMPD_parallel_master:
+ case OMPD_parallel_masked:
case OMPD_parallel_sections:
case OMPD_parallel_for:
case OMPD_parallel_for_simd:
+ case OMPD_parallel_loop:
case OMPD_distribute_parallel_for:
case OMPD_distribute_parallel_for_simd:
case OMPD_parallel_master_taskloop:
+ case OMPD_parallel_masked_taskloop:
case OMPD_parallel_master_taskloop_simd:
+ case OMPD_parallel_masked_taskloop_simd:
// Do not capture num_threads-clause expressions.
break;
case OMPD_target_data:
@@ -13728,7 +15374,9 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_taskloop:
case OMPD_taskloop_simd:
case OMPD_master_taskloop:
+ case OMPD_masked_taskloop:
case OMPD_master_taskloop_simd:
+ case OMPD_masked_taskloop_simd:
case OMPD_threadprivate:
case OMPD_allocate:
case OMPD_taskyield:
@@ -13747,6 +15395,8 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_loop:
+ case OMPD_teams_loop:
+ case OMPD_target_teams_loop:
case OMPD_teams:
case OMPD_simd:
case OMPD_tile:
@@ -13781,6 +15431,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_target_teams_distribute_simd:
case OMPD_target_teams_distribute_parallel_for:
case OMPD_target_teams_distribute_parallel_for_simd:
+ case OMPD_target_teams_loop:
CaptureRegion = OMPD_target;
break;
case OMPD_teams_distribute_parallel_for:
@@ -13788,6 +15439,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_teams:
case OMPD_teams_distribute:
case OMPD_teams_distribute_simd:
+ case OMPD_teams_loop:
// Do not capture num_teams-clause expressions.
break;
case OMPD_distribute_parallel_for:
@@ -13796,9 +15448,13 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_taskloop:
case OMPD_taskloop_simd:
case OMPD_master_taskloop:
+ case OMPD_masked_taskloop:
case OMPD_master_taskloop_simd:
+ case OMPD_masked_taskloop_simd:
case OMPD_parallel_master_taskloop:
+ case OMPD_parallel_masked_taskloop:
case OMPD_parallel_master_taskloop_simd:
+ case OMPD_parallel_masked_taskloop_simd:
case OMPD_target_data:
case OMPD_target_enter_data:
case OMPD_target_exit_data:
@@ -13806,14 +15462,17 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_cancel:
case OMPD_parallel:
case OMPD_parallel_master:
+ case OMPD_parallel_masked:
case OMPD_parallel_sections:
case OMPD_parallel_for:
case OMPD_parallel_for_simd:
+ case OMPD_parallel_loop:
case OMPD_target:
case OMPD_target_simd:
case OMPD_target_parallel:
case OMPD_target_parallel_for:
case OMPD_target_parallel_for_simd:
+ case OMPD_target_parallel_loop:
case OMPD_threadprivate:
case OMPD_allocate:
case OMPD_taskyield:
@@ -13863,6 +15522,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_target_teams_distribute_simd:
case OMPD_target_teams_distribute_parallel_for:
case OMPD_target_teams_distribute_parallel_for_simd:
+ case OMPD_target_teams_loop:
CaptureRegion = OMPD_target;
break;
case OMPD_teams_distribute_parallel_for:
@@ -13870,6 +15530,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_teams:
case OMPD_teams_distribute:
case OMPD_teams_distribute_simd:
+ case OMPD_teams_loop:
// Do not capture thread_limit-clause expressions.
break;
case OMPD_distribute_parallel_for:
@@ -13878,9 +15539,13 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_taskloop:
case OMPD_taskloop_simd:
case OMPD_master_taskloop:
+ case OMPD_masked_taskloop:
case OMPD_master_taskloop_simd:
+ case OMPD_masked_taskloop_simd:
case OMPD_parallel_master_taskloop:
+ case OMPD_parallel_masked_taskloop:
case OMPD_parallel_master_taskloop_simd:
+ case OMPD_parallel_masked_taskloop_simd:
case OMPD_target_data:
case OMPD_target_enter_data:
case OMPD_target_exit_data:
@@ -13888,14 +15553,17 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_cancel:
case OMPD_parallel:
case OMPD_parallel_master:
+ case OMPD_parallel_masked:
case OMPD_parallel_sections:
case OMPD_parallel_for:
case OMPD_parallel_for_simd:
+ case OMPD_parallel_loop:
case OMPD_target:
case OMPD_target_simd:
case OMPD_target_parallel:
case OMPD_target_parallel_for:
case OMPD_target_parallel_for_simd:
+ case OMPD_target_parallel_loop:
case OMPD_threadprivate:
case OMPD_allocate:
case OMPD_taskyield:
@@ -13960,9 +15628,13 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_taskloop:
case OMPD_taskloop_simd:
case OMPD_master_taskloop:
+ case OMPD_masked_taskloop:
case OMPD_master_taskloop_simd:
+ case OMPD_masked_taskloop_simd:
case OMPD_parallel_master_taskloop:
+ case OMPD_parallel_masked_taskloop:
case OMPD_parallel_master_taskloop_simd:
+ case OMPD_parallel_masked_taskloop_simd:
case OMPD_target_data:
case OMPD_target_enter_data:
case OMPD_target_exit_data:
@@ -13978,6 +15650,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_cancel:
case OMPD_parallel:
case OMPD_parallel_master:
+ case OMPD_parallel_masked:
case OMPD_parallel_sections:
case OMPD_threadprivate:
case OMPD_allocate:
@@ -13997,6 +15670,10 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_loop:
+ case OMPD_teams_loop:
+ case OMPD_target_teams_loop:
+ case OMPD_parallel_loop:
+ case OMPD_target_parallel_loop:
case OMPD_simd:
case OMPD_tile:
case OMPD_unroll:
@@ -14046,9 +15723,13 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_taskloop:
case OMPD_taskloop_simd:
case OMPD_master_taskloop:
+ case OMPD_masked_taskloop:
case OMPD_master_taskloop_simd:
+ case OMPD_masked_taskloop_simd:
case OMPD_parallel_master_taskloop:
+ case OMPD_parallel_masked_taskloop:
case OMPD_parallel_master_taskloop_simd:
+ case OMPD_parallel_masked_taskloop_simd:
case OMPD_target_data:
case OMPD_target_enter_data:
case OMPD_target_exit_data:
@@ -14060,6 +15741,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_cancel:
case OMPD_parallel:
case OMPD_parallel_master:
+ case OMPD_parallel_masked:
case OMPD_parallel_sections:
case OMPD_threadprivate:
case OMPD_allocate:
@@ -14079,6 +15761,10 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_loop:
+ case OMPD_teams_loop:
+ case OMPD_target_teams_loop:
+ case OMPD_parallel_loop:
+ case OMPD_target_parallel_loop:
case OMPD_simd:
case OMPD_tile:
case OMPD_unroll:
@@ -14115,8 +15801,10 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_target_teams_distribute_simd:
case OMPD_target_parallel_for:
case OMPD_target_parallel_for_simd:
+ case OMPD_target_parallel_loop:
case OMPD_target_teams_distribute_parallel_for:
case OMPD_target_teams_distribute_parallel_for_simd:
+ case OMPD_target_teams_loop:
case OMPD_dispatch:
CaptureRegion = OMPD_task;
break;
@@ -14135,12 +15823,17 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_taskloop:
case OMPD_taskloop_simd:
case OMPD_master_taskloop:
+ case OMPD_masked_taskloop:
case OMPD_master_taskloop_simd:
+ case OMPD_masked_taskloop_simd:
case OMPD_parallel_master_taskloop:
+ case OMPD_parallel_masked_taskloop:
case OMPD_parallel_master_taskloop_simd:
+ case OMPD_parallel_masked_taskloop_simd:
case OMPD_cancel:
case OMPD_parallel:
case OMPD_parallel_master:
+ case OMPD_parallel_masked:
case OMPD_parallel_sections:
case OMPD_parallel_for:
case OMPD_parallel_for_simd:
@@ -14162,6 +15855,8 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_loop:
+ case OMPD_teams_loop:
+ case OMPD_parallel_loop:
case OMPD_simd:
case OMPD_tile:
case OMPD_unroll:
@@ -14195,8 +15890,12 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_taskloop:
case OMPD_taskloop_simd:
case OMPD_master_taskloop:
+ case OMPD_masked_taskloop:
case OMPD_master_taskloop_simd:
+ case OMPD_masked_taskloop_simd:
break;
+ case OMPD_parallel_masked_taskloop:
+ case OMPD_parallel_masked_taskloop_simd:
case OMPD_parallel_master_taskloop:
case OMPD_parallel_master_taskloop_simd:
CaptureRegion = OMPD_parallel;
@@ -14225,6 +15924,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_cancel:
case OMPD_parallel:
case OMPD_parallel_master:
+ case OMPD_parallel_masked:
case OMPD_parallel_sections:
case OMPD_parallel_for:
case OMPD_parallel_for_simd:
@@ -14246,6 +15946,10 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_loop:
+ case OMPD_teams_loop:
+ case OMPD_target_teams_loop:
+ case OMPD_parallel_loop:
+ case OMPD_target_parallel_loop:
case OMPD_simd:
case OMPD_tile:
case OMPD_unroll:
@@ -14811,6 +16515,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
case OMPC_use_device_ptr:
case OMPC_use_device_addr:
case OMPC_is_device_ptr:
+ case OMPC_has_device_addr:
case OMPC_unified_address:
case OMPC_unified_shared_memory:
case OMPC_reverse_offload:
@@ -14877,6 +16582,9 @@ OMPClause *Sema::ActOnOpenMPDefaultClause(DefaultKind Kind,
case OMP_DEFAULT_firstprivate:
DSAStack->setDefaultDSAFirstPrivate(KindKwLoc);
break;
+ case OMP_DEFAULT_private:
+ DSAStack->setDefaultDSAPrivate(KindKwLoc);
+ break;
default:
llvm_unreachable("DSA unexpected in OpenMP default clause");
}
@@ -14953,8 +16661,11 @@ OMPClause *Sema::ActOnOpenMPUpdateClause(OpenMPDependClauseKind Kind,
SourceLocation EndLoc) {
if (Kind == OMPC_DEPEND_unknown || Kind == OMPC_DEPEND_source ||
Kind == OMPC_DEPEND_sink || Kind == OMPC_DEPEND_depobj) {
- unsigned Except[] = {OMPC_DEPEND_source, OMPC_DEPEND_sink,
- OMPC_DEPEND_depobj};
+ SmallVector<unsigned> Except = {
+ OMPC_DEPEND_source, OMPC_DEPEND_sink, OMPC_DEPEND_depobj,
+ OMPC_DEPEND_outallmemory, OMPC_DEPEND_inoutallmemory};
+ if (LangOpts.OpenMP < 51)
+ Except.push_back(OMPC_DEPEND_inoutset);
Diag(KindKwLoc, diag::err_omp_unexpected_clause_value)
<< getListOfPossibleValues(OMPC_depend, /*First=*/0,
/*Last=*/OMPC_DEPEND_unknown, Except)
@@ -15114,6 +16825,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
case OMPC_use_device_ptr:
case OMPC_use_device_addr:
case OMPC_is_device_ptr:
+ case OMPC_has_device_addr:
case OMPC_unified_address:
case OMPC_unified_shared_memory:
case OMPC_reverse_offload:
@@ -15373,6 +17085,7 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind,
case OMPC_use_device_ptr:
case OMPC_use_device_addr:
case OMPC_is_device_ptr:
+ case OMPC_has_device_addr:
case OMPC_atomic_default_mem_order:
case OMPC_device_type:
case OMPC_match:
@@ -15400,6 +17113,7 @@ OMPClause *Sema::ActOnOpenMPNowaitClause(SourceLocation StartLoc,
OMPClause *Sema::ActOnOpenMPUntiedClause(SourceLocation StartLoc,
SourceLocation EndLoc) {
+ DSAStack->setUntiedRegion();
return new (Context) OMPUntiedClause(StartLoc, EndLoc);
}
@@ -15759,20 +17473,17 @@ OMPClause *Sema::ActOnOpenMPFilterClause(Expr *ThreadID,
StartLoc, LParenLoc, EndLoc);
}
-OMPClause *Sema::ActOnOpenMPVarListClause(
- OpenMPClauseKind Kind, ArrayRef<Expr *> VarList, Expr *DepModOrTailExpr,
- const OMPVarListLocTy &Locs, SourceLocation ColonLoc,
- CXXScopeSpec &ReductionOrMapperIdScopeSpec,
- DeclarationNameInfo &ReductionOrMapperId, int ExtraModifier,
- ArrayRef<OpenMPMapModifierKind> MapTypeModifiers,
- ArrayRef<SourceLocation> MapTypeModifiersLoc, bool IsMapTypeImplicit,
- SourceLocation ExtraModifierLoc,
- ArrayRef<OpenMPMotionModifierKind> MotionModifiers,
- ArrayRef<SourceLocation> MotionModifiersLoc) {
+OMPClause *Sema::ActOnOpenMPVarListClause(OpenMPClauseKind Kind,
+ ArrayRef<Expr *> VarList,
+ const OMPVarListLocTy &Locs,
+ OpenMPVarListDataTy &Data) {
SourceLocation StartLoc = Locs.StartLoc;
SourceLocation LParenLoc = Locs.LParenLoc;
SourceLocation EndLoc = Locs.EndLoc;
OMPClause *Res = nullptr;
+ int ExtraModifier = Data.ExtraModifier;
+ SourceLocation ExtraModifierLoc = Data.ExtraModifierLoc;
+ SourceLocation ColonLoc = Data.ColonLoc;
switch (Kind) {
case OMPC_private:
Res = ActOnOpenMPPrivateClause(VarList, StartLoc, LParenLoc, EndLoc);
@@ -15796,28 +17507,28 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
Res = ActOnOpenMPReductionClause(
VarList, static_cast<OpenMPReductionClauseModifier>(ExtraModifier),
StartLoc, LParenLoc, ExtraModifierLoc, ColonLoc, EndLoc,
- ReductionOrMapperIdScopeSpec, ReductionOrMapperId);
+ Data.ReductionOrMapperIdScopeSpec, Data.ReductionOrMapperId);
break;
case OMPC_task_reduction:
- Res = ActOnOpenMPTaskReductionClause(VarList, StartLoc, LParenLoc, ColonLoc,
- EndLoc, ReductionOrMapperIdScopeSpec,
- ReductionOrMapperId);
+ Res = ActOnOpenMPTaskReductionClause(
+ VarList, StartLoc, LParenLoc, ColonLoc, EndLoc,
+ Data.ReductionOrMapperIdScopeSpec, Data.ReductionOrMapperId);
break;
case OMPC_in_reduction:
- Res = ActOnOpenMPInReductionClause(VarList, StartLoc, LParenLoc, ColonLoc,
- EndLoc, ReductionOrMapperIdScopeSpec,
- ReductionOrMapperId);
+ Res = ActOnOpenMPInReductionClause(
+ VarList, StartLoc, LParenLoc, ColonLoc, EndLoc,
+ Data.ReductionOrMapperIdScopeSpec, Data.ReductionOrMapperId);
break;
case OMPC_linear:
assert(0 <= ExtraModifier && ExtraModifier <= OMPC_LINEAR_unknown &&
"Unexpected linear modifier.");
Res = ActOnOpenMPLinearClause(
- VarList, DepModOrTailExpr, StartLoc, LParenLoc,
+ VarList, Data.DepModOrTailExpr, StartLoc, LParenLoc,
static_cast<OpenMPLinearClauseKind>(ExtraModifier), ExtraModifierLoc,
ColonLoc, EndLoc);
break;
case OMPC_aligned:
- Res = ActOnOpenMPAlignedClause(VarList, DepModOrTailExpr, StartLoc,
+ Res = ActOnOpenMPAlignedClause(VarList, Data.DepModOrTailExpr, StartLoc,
LParenLoc, ColonLoc, EndLoc);
break;
case OMPC_copyin:
@@ -15833,26 +17544,30 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
assert(0 <= ExtraModifier && ExtraModifier <= OMPC_DEPEND_unknown &&
"Unexpected depend modifier.");
Res = ActOnOpenMPDependClause(
- DepModOrTailExpr, static_cast<OpenMPDependClauseKind>(ExtraModifier),
- ExtraModifierLoc, ColonLoc, VarList, StartLoc, LParenLoc, EndLoc);
+ {static_cast<OpenMPDependClauseKind>(ExtraModifier), ExtraModifierLoc,
+ ColonLoc, Data.OmpAllMemoryLoc},
+ Data.DepModOrTailExpr, VarList, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_map:
assert(0 <= ExtraModifier && ExtraModifier <= OMPC_MAP_unknown &&
"Unexpected map modifier.");
Res = ActOnOpenMPMapClause(
- MapTypeModifiers, MapTypeModifiersLoc, ReductionOrMapperIdScopeSpec,
- ReductionOrMapperId, static_cast<OpenMPMapClauseKind>(ExtraModifier),
- IsMapTypeImplicit, ExtraModifierLoc, ColonLoc, VarList, Locs);
+ Data.MapTypeModifiers, Data.MapTypeModifiersLoc,
+ Data.ReductionOrMapperIdScopeSpec, Data.ReductionOrMapperId,
+ static_cast<OpenMPMapClauseKind>(ExtraModifier), Data.IsMapTypeImplicit,
+ ExtraModifierLoc, ColonLoc, VarList, Locs);
break;
case OMPC_to:
- Res = ActOnOpenMPToClause(MotionModifiers, MotionModifiersLoc,
- ReductionOrMapperIdScopeSpec, ReductionOrMapperId,
- ColonLoc, VarList, Locs);
+ Res =
+ ActOnOpenMPToClause(Data.MotionModifiers, Data.MotionModifiersLoc,
+ Data.ReductionOrMapperIdScopeSpec,
+ Data.ReductionOrMapperId, ColonLoc, VarList, Locs);
break;
case OMPC_from:
- Res = ActOnOpenMPFromClause(MotionModifiers, MotionModifiersLoc,
- ReductionOrMapperIdScopeSpec,
- ReductionOrMapperId, ColonLoc, VarList, Locs);
+ Res = ActOnOpenMPFromClause(Data.MotionModifiers, Data.MotionModifiersLoc,
+ Data.ReductionOrMapperIdScopeSpec,
+ Data.ReductionOrMapperId, ColonLoc, VarList,
+ Locs);
break;
case OMPC_use_device_ptr:
Res = ActOnOpenMPUseDevicePtrClause(VarList, Locs);
@@ -15863,8 +17578,11 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
case OMPC_is_device_ptr:
Res = ActOnOpenMPIsDevicePtrClause(VarList, Locs);
break;
+ case OMPC_has_device_addr:
+ Res = ActOnOpenMPHasDeviceAddrClause(VarList, Locs);
+ break;
case OMPC_allocate:
- Res = ActOnOpenMPAllocateClause(DepModOrTailExpr, VarList, StartLoc,
+ Res = ActOnOpenMPAllocateClause(Data.DepModOrTailExpr, VarList, StartLoc,
LParenLoc, ColonLoc, EndLoc);
break;
case OMPC_nontemporal:
@@ -15878,7 +17596,7 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
break;
case OMPC_affinity:
Res = ActOnOpenMPAffinityClause(StartLoc, LParenLoc, ColonLoc, EndLoc,
- DepModOrTailExpr, VarList);
+ Data.DepModOrTailExpr, VarList);
break;
case OMPC_if:
case OMPC_depobj:
@@ -15967,6 +17685,8 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,
SourceLocation EndLoc) {
SmallVector<Expr *, 8> Vars;
SmallVector<Expr *, 8> PrivateCopies;
+ bool IsImplicitClause =
+ StartLoc.isInvalid() && LParenLoc.isInvalid() && EndLoc.isInvalid();
for (Expr *RefExpr : VarList) {
assert(RefExpr && "NULL expr in OpenMP private clause.");
SourceLocation ELoc;
@@ -16081,9 +17801,17 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,
*this, VDPrivate, RefExpr->getType().getUnqualifiedType(), ELoc);
DeclRefExpr *Ref = nullptr;
- if (!VD && !CurContext->isDependentContext())
- Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/false);
- DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_private, Ref);
+ if (!VD && !CurContext->isDependentContext()) {
+ auto *FD = dyn_cast<FieldDecl>(D);
+ VarDecl *VD = FD ? DSAStack->getImplicitFDCapExprDecl(FD) : nullptr;
+ if (VD)
+ Ref = buildDeclRefExpr(*this, VD, VD->getType().getNonReferenceType(),
+ RefExpr->getExprLoc());
+ else
+ Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/false);
+ }
+ if (!IsImplicitClause)
+ DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_private, Ref);
Vars.push_back((VD || CurContext->isDependentContext())
? RefExpr->IgnoreParens()
: Ref);
@@ -16356,8 +18084,14 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
if (TopDVar.CKind == OMPC_lastprivate) {
Ref = TopDVar.PrivateCopy;
} else {
- Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/true);
- if (!isOpenMPCapturedDecl(D))
+ auto *FD = dyn_cast<FieldDecl>(D);
+ VarDecl *VD = FD ? DSAStack->getImplicitFDCapExprDecl(FD) : nullptr;
+ if (VD)
+ Ref = buildDeclRefExpr(*this, VD, VD->getType().getNonReferenceType(),
+ RefExpr->getExprLoc());
+ else
+ Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/true);
+ if (VD || !isOpenMPCapturedDecl(D))
ExprCaptures.push_back(Ref->getDecl());
}
}
@@ -16627,7 +18361,7 @@ public:
return true;
DSAStackTy::DSAVarData DVarPrivate = Stack->hasDSA(
VD,
- [](OpenMPClauseKind C, bool AppliedToPointee) {
+ [](OpenMPClauseKind C, bool AppliedToPointee, bool) {
return isOpenMPPrivate(C) && !AppliedToPointee;
},
[](OpenMPDirectiveKind) { return true; },
@@ -18471,10 +20205,12 @@ OMPClause *Sema::ActOnOpenMPDepobjClause(Expr *Depobj, SourceLocation StartLoc,
}
OMPClause *
-Sema::ActOnOpenMPDependClause(Expr *DepModifier, OpenMPDependClauseKind DepKind,
- SourceLocation DepLoc, SourceLocation ColonLoc,
- ArrayRef<Expr *> VarList, SourceLocation StartLoc,
- SourceLocation LParenLoc, SourceLocation EndLoc) {
+Sema::ActOnOpenMPDependClause(const OMPDependClause::DependDataTy &Data,
+ Expr *DepModifier, ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ OpenMPDependClauseKind DepKind = Data.DepKind;
+ SourceLocation DepLoc = Data.DepLoc;
if (DSAStack->getCurrentDirective() == OMPD_ordered &&
DepKind != OMPC_DEPEND_source && DepKind != OMPC_DEPEND_sink) {
Diag(DepLoc, diag::err_omp_unexpected_clause_value)
@@ -18493,11 +20229,13 @@ Sema::ActOnOpenMPDependClause(Expr *DepModifier, OpenMPDependClauseKind DepKind,
((LangOpts.OpenMP < 50 ||
DSAStack->getCurrentDirective() == OMPD_depobj) &&
DepKind == OMPC_DEPEND_depobj))) {
- SmallVector<unsigned, 3> Except;
- Except.push_back(OMPC_DEPEND_source);
- Except.push_back(OMPC_DEPEND_sink);
+ SmallVector<unsigned, 6> Except = {OMPC_DEPEND_source, OMPC_DEPEND_sink,
+ OMPC_DEPEND_outallmemory,
+ OMPC_DEPEND_inoutallmemory};
if (LangOpts.OpenMP < 50 || DSAStack->getCurrentDirective() == OMPD_depobj)
Except.push_back(OMPC_DEPEND_depobj);
+ if (LangOpts.OpenMP < 51)
+ Except.push_back(OMPC_DEPEND_inoutset);
std::string Expected = (LangOpts.OpenMP >= 50 && !DepModifier)
? "depend modifier(iterator) or "
: "";
@@ -18668,9 +20406,9 @@ Sema::ActOnOpenMPDependClause(Expr *DepModifier, OpenMPDependClauseKind DepKind,
}
// OpenMP 5.0, 2.17.11 depend Clause, Restrictions, C/C++
- // List items used in depend clauses with the in, out, inout or
- // mutexinoutset dependence types cannot be expressions of the
- // omp_depend_t type.
+ // List items used in depend clauses with the in, out, inout,
+ // inoutset, or mutexinoutset dependence types cannot be
+ // expressions of the omp_depend_t type.
if (!RefExpr->isValueDependent() && !RefExpr->isTypeDependent() &&
!RefExpr->isInstantiationDependent() &&
!RefExpr->containsUnexpandedParameterPack() &&
@@ -18719,12 +20457,14 @@ Sema::ActOnOpenMPDependClause(Expr *DepModifier, OpenMPDependClauseKind DepKind,
<< 1 << DSAStack->getParentLoopControlVariable(VarList.size() + 1);
}
if (DepKind != OMPC_DEPEND_source && DepKind != OMPC_DEPEND_sink &&
- Vars.empty())
+ DepKind != OMPC_DEPEND_outallmemory &&
+ DepKind != OMPC_DEPEND_inoutallmemory && Vars.empty())
return nullptr;
- auto *C = OMPDependClause::Create(Context, StartLoc, LParenLoc, EndLoc,
- DepModifier, DepKind, DepLoc, ColonLoc,
- Vars, TotalDepCount.getZExtValue());
+ auto *C = OMPDependClause::Create(
+ Context, StartLoc, LParenLoc, EndLoc,
+ {DepKind, DepLoc, Data.ColonLoc, Data.OmpAllMemoryLoc}, DepModifier, Vars,
+ TotalDepCount.getZExtValue());
if ((DepKind == OMPC_DEPEND_sink || DepKind == OMPC_DEPEND_source) &&
DSAStack->isParentOrderedRegion())
DSAStack->addDoacrossDependClause(C, OpsOffs);
@@ -18759,6 +20499,18 @@ OMPClause *Sema::ActOnOpenMPDeviceClause(OpenMPDeviceClauseModifier Modifier,
if (ErrorFound)
return nullptr;
+ // OpenMP 5.0 [2.12.5, Restrictions]
+ // In case of ancestor device-modifier, a requires directive with
+ // the reverse_offload clause must be specified.
+ if (Modifier == OMPC_DEVICE_ancestor) {
+ if (!DSAStack->hasRequiresDeclWithClause<OMPReverseOffloadClause>()) {
+ targetDiag(
+ StartLoc,
+ diag::err_omp_device_ancestor_without_requires_reverse_offload);
+ ErrorFound = true;
+ }
+ }
+
OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
OpenMPDirectiveKind CaptureRegion =
getOpenMPCaptureRegionForClause(DKind, OMPC_device, LangOpts.OpenMP);
@@ -20534,7 +22286,8 @@ OMPClause *Sema::ActOnOpenMPHintClause(Expr *Hint, SourceLocation StartLoc,
// OpenMP [2.13.2, critical construct, Description]
// ... where hint-expression is an integer constant expression that evaluates
// to a valid lock hint.
- ExprResult HintExpr = VerifyPositiveIntegerConstantInClause(Hint, OMPC_hint);
+ ExprResult HintExpr =
+ VerifyPositiveIntegerConstantInClause(Hint, OMPC_hint, false);
if (HintExpr.isInvalid())
return nullptr;
return new (Context)
@@ -20774,6 +22527,14 @@ void Sema::ActOnFinishedOpenMPDeclareTargetContext(
ActOnOpenMPDeclareTargetName(It.first, It.second.Loc, It.second.MT, DTCI);
}
+void Sema::DiagnoseUnterminatedOpenMPDeclareTarget() {
+ if (DeclareTargetNesting.empty())
+ return;
+ DeclareTargetContextInfo &DTCI = DeclareTargetNesting.back();
+ Diag(DTCI.Loc, diag::warn_omp_unterminated_declare_target)
+ << getOpenMPDirectiveName(DTCI.Kind);
+}
+
NamedDecl *Sema::lookupOpenMPDeclareTargetName(Scope *CurScope,
CXXScopeSpec &ScopeSpec,
const DeclarationNameInfo &Id) {
@@ -20827,7 +22588,7 @@ void Sema::ActOnOpenMPDeclareTargetName(NamedDecl *ND, SourceLocation Loc,
auto *VD = cast<ValueDecl>(ND);
llvm::Optional<OMPDeclareTargetDeclAttr *> ActiveAttr =
OMPDeclareTargetDeclAttr::getActiveAttr(VD);
- if (ActiveAttr.hasValue() && ActiveAttr.getValue()->getDevType() != DTCI.DT &&
+ if (ActiveAttr && ActiveAttr.getValue()->getDevType() != DTCI.DT &&
ActiveAttr.getValue()->getLevel() == Level) {
Diag(Loc, diag::err_omp_device_type_mismatch)
<< OMPDeclareTargetDeclAttr::ConvertDevTypeTyToStr(DTCI.DT)
@@ -20835,18 +22596,18 @@ void Sema::ActOnOpenMPDeclareTargetName(NamedDecl *ND, SourceLocation Loc,
ActiveAttr.getValue()->getDevType());
return;
}
- if (ActiveAttr.hasValue() && ActiveAttr.getValue()->getMapType() != MT &&
+ if (ActiveAttr && ActiveAttr.getValue()->getMapType() != MT &&
ActiveAttr.getValue()->getLevel() == Level) {
Diag(Loc, diag::err_omp_declare_target_to_and_link) << ND;
return;
}
- if (ActiveAttr.hasValue() && ActiveAttr.getValue()->getLevel() == Level)
+ if (ActiveAttr && ActiveAttr.getValue()->getLevel() == Level)
return;
Expr *IndirectE = nullptr;
bool IsIndirect = false;
- if (DTCI.Indirect.hasValue()) {
+ if (DTCI.Indirect) {
IndirectE = DTCI.Indirect.getValue();
if (!IndirectE)
IsIndirect = true;
@@ -20884,7 +22645,7 @@ static void checkDeclInTargetContext(SourceLocation SL, SourceRange SR,
return;
}
}
- if (MapTy.hasValue())
+ if (MapTy)
return;
SemaRef.Diag(VD->getLocation(), diag::warn_omp_not_in_target_context);
SemaRef.Diag(SL, diag::note_used_here) << SR;
@@ -20941,12 +22702,12 @@ void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D,
llvm::Optional<OMPDeclareTargetDeclAttr *> ActiveAttr =
OMPDeclareTargetDeclAttr::getActiveAttr(VD);
unsigned Level = DeclareTargetNesting.size();
- if (ActiveAttr.hasValue() && ActiveAttr.getValue()->getLevel() >= Level)
+ if (ActiveAttr && ActiveAttr.getValue()->getLevel() >= Level)
return;
DeclareTargetContextInfo &DTCI = DeclareTargetNesting.back();
Expr *IndirectE = nullptr;
bool IsIndirect = false;
- if (DTCI.Indirect.hasValue()) {
+ if (DTCI.Indirect) {
IndirectE = DTCI.Indirect.getValue();
if (!IndirectE)
IsIndirect = true;
@@ -21260,6 +23021,88 @@ OMPClause *Sema::ActOnOpenMPIsDevicePtrClause(ArrayRef<Expr *> VarList,
MVLI.VarComponents);
}
+OMPClause *Sema::ActOnOpenMPHasDeviceAddrClause(ArrayRef<Expr *> VarList,
+ const OMPVarListLocTy &Locs) {
+ MappableVarListInfo MVLI(VarList);
+ for (Expr *RefExpr : VarList) {
+ assert(RefExpr && "NULL expr in OpenMP has_device_addr clause.");
+ SourceLocation ELoc;
+ SourceRange ERange;
+ Expr *SimpleRefExpr = RefExpr;
+ auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange,
+ /*AllowArraySection=*/true);
+ if (Res.second) {
+ // It will be analyzed later.
+ MVLI.ProcessedVarList.push_back(RefExpr);
+ }
+ ValueDecl *D = Res.first;
+ if (!D)
+ continue;
+
+ // Check if the declaration in the clause does not show up in any data
+ // sharing attribute.
+ DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, /*FromParent=*/false);
+ if (isOpenMPPrivate(DVar.CKind)) {
+ Diag(ELoc, diag::err_omp_variable_in_given_clause_and_dsa)
+ << getOpenMPClauseName(DVar.CKind)
+ << getOpenMPClauseName(OMPC_has_device_addr)
+ << getOpenMPDirectiveName(DSAStack->getCurrentDirective());
+ reportOriginalDsa(*this, DSAStack, D, DVar);
+ continue;
+ }
+
+ const Expr *ConflictExpr;
+ if (DSAStack->checkMappableExprComponentListsForDecl(
+ D, /*CurrentRegionOnly=*/true,
+ [&ConflictExpr](
+ OMPClauseMappableExprCommon::MappableExprComponentListRef R,
+ OpenMPClauseKind) -> bool {
+ ConflictExpr = R.front().getAssociatedExpression();
+ return true;
+ })) {
+ Diag(ELoc, diag::err_omp_map_shared_storage) << RefExpr->getSourceRange();
+ Diag(ConflictExpr->getExprLoc(), diag::note_used_here)
+ << ConflictExpr->getSourceRange();
+ continue;
+ }
+
+ // Store the components in the stack so that they can be used to check
+ // against other clauses later on.
+ OMPClauseMappableExprCommon::MappableComponent MC(
+ SimpleRefExpr, D, /*IsNonContiguous=*/false);
+ DSAStack->addMappableExpressionComponents(
+ D, MC, /*WhereFoundClauseKind=*/OMPC_has_device_addr);
+
+ // Record the expression we've just processed.
+ auto *VD = dyn_cast<VarDecl>(D);
+ if (!VD && !CurContext->isDependentContext()) {
+ DeclRefExpr *Ref =
+ buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/true);
+ assert(Ref && "has_device_addr capture failed");
+ MVLI.ProcessedVarList.push_back(Ref);
+ } else
+ MVLI.ProcessedVarList.push_back(RefExpr->IgnoreParens());
+
+ // Create a mappable component for the list item. List items in this clause
+ // only need a component. We use a null declaration to signal fields in
+ // 'this'.
+ assert((isa<DeclRefExpr>(SimpleRefExpr) ||
+ isa<CXXThisExpr>(cast<MemberExpr>(SimpleRefExpr)->getBase())) &&
+ "Unexpected device pointer expression!");
+ MVLI.VarBaseDeclarations.push_back(
+ isa<DeclRefExpr>(SimpleRefExpr) ? D : nullptr);
+ MVLI.VarComponents.resize(MVLI.VarComponents.size() + 1);
+ MVLI.VarComponents.back().push_back(MC);
+ }
+
+ if (MVLI.ProcessedVarList.empty())
+ return nullptr;
+
+ return OMPHasDeviceAddrClause::Create(Context, Locs, MVLI.ProcessedVarList,
+ MVLI.VarBaseDeclarations,
+ MVLI.VarComponents);
+}
+
OMPClause *Sema::ActOnOpenMPAllocateClause(
Expr *Allocator, ArrayRef<Expr *> VarList, SourceLocation StartLoc,
SourceLocation ColonLoc, SourceLocation LParenLoc, SourceLocation EndLoc) {
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 3fa192cedfa3..c226ed625479 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -49,11 +49,10 @@ static bool functionHasPassObjectSizeParams(const FunctionDecl *FD) {
}
/// A convenience routine for creating a decayed reference to a function.
-static ExprResult
-CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn, NamedDecl *FoundDecl,
- const Expr *Base, bool HadMultipleCandidates,
- SourceLocation Loc = SourceLocation(),
- const DeclarationNameLoc &LocInfo = DeclarationNameLoc()){
+static ExprResult CreateFunctionRefExpr(
+ Sema &S, FunctionDecl *Fn, NamedDecl *FoundDecl, const Expr *Base,
+ bool HadMultipleCandidates, SourceLocation Loc = SourceLocation(),
+ const DeclarationNameLoc &LocInfo = DeclarationNameLoc()) {
if (S.DiagnoseUseOfDecl(FoundDecl, Loc))
return ExprError();
// If FoundDecl is different from Fn (such as if one is a template
@@ -984,8 +983,7 @@ checkPlaceholderForOverload(Sema &S, Expr *&E,
/// checkArgPlaceholdersForOverload - Check a set of call operands for
/// placeholders.
-static bool checkArgPlaceholdersForOverload(Sema &S,
- MultiExprArg Args,
+static bool checkArgPlaceholdersForOverload(Sema &S, MultiExprArg Args,
UnbridgedCastsSet &unbridged) {
for (unsigned i = 0, e = Args.size(); i != e; ++i)
if (checkPlaceholderForOverload(S, Args[i], &unbridged))
@@ -1619,8 +1617,9 @@ bool Sema::IsFunctionConversion(QualType FromType, QualType ToType,
///
/// \param ICK Will be set to the vector conversion kind, if this is a vector
/// conversion.
-static bool IsVectorConversion(Sema &S, QualType FromType,
- QualType ToType, ImplicitConversionKind &ICK) {
+static bool IsVectorConversion(Sema &S, QualType FromType, QualType ToType,
+ ImplicitConversionKind &ICK, Expr *From,
+ bool InOverloadResolution) {
// We need at least one of these types to be a vector type to have a vector
// conversion.
if (!ToType->isVectorType() && !FromType->isVectorType())
@@ -1662,6 +1661,13 @@ static bool IsVectorConversion(Sema &S, QualType FromType,
if (S.Context.areCompatibleVectorTypes(FromType, ToType) ||
(S.isLaxVectorConversion(FromType, ToType) &&
!ToType->hasAttr(attr::ArmMveStrictPolymorphism))) {
+ if (S.isLaxVectorConversion(FromType, ToType) &&
+ S.anyAltivecTypes(FromType, ToType) &&
+ !S.areSameVectorElemTypes(FromType, ToType) &&
+ !InOverloadResolution) {
+ S.Diag(From->getBeginLoc(), diag::warn_deprecated_lax_vec_conv_all)
+ << FromType << ToType;
+ }
ICK = ICK_Vector_Conversion;
return true;
}
@@ -1749,13 +1755,6 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
"Non-address-of operator for overloaded function expression");
FromType = S.Context.getPointerType(FromType);
}
-
- // Check that we've computed the proper type after overload resolution.
- // FIXME: FixOverloadedFunctionReference has side-effects; we shouldn't
- // be calling it from within an NDEBUG block.
- assert(S.Context.hasSameType(
- FromType,
- S.FixOverloadedFunctionReference(From, AccessPair, Fn)->getType()));
} else {
return false;
}
@@ -1917,7 +1916,8 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
InOverloadResolution, FromType)) {
// Pointer to member conversions (4.11).
SCS.Second = ICK_Pointer_Member;
- } else if (IsVectorConversion(S, FromType, ToType, SecondICK)) {
+ } else if (IsVectorConversion(S, FromType, ToType, SecondICK, From,
+ InOverloadResolution)) {
SCS.Second = SecondICK;
FromType = ToType.getUnqualifiedType();
} else if (!S.getLangOpts().CPlusPlus &&
@@ -2954,24 +2954,30 @@ void Sema::HandleFunctionTypeMismatch(PartialDiagnostic &PDiag,
}
/// FunctionParamTypesAreEqual - This routine checks two function proto types
-/// for equality of their argument types. Caller has already checked that
-/// they have same number of arguments. If the parameters are different,
+/// for equality of their parameter types. Caller has already checked that
+/// they have same number of parameters. If the parameters are different,
/// ArgPos will have the parameter index of the first different parameter.
+/// If `Reversed` is true, the parameters of `NewType` will be compared in
+/// reverse order. That's useful if one of the functions is being used as a C++20
+/// synthesized operator overload with a reversed parameter order.
bool Sema::FunctionParamTypesAreEqual(const FunctionProtoType *OldType,
const FunctionProtoType *NewType,
- unsigned *ArgPos) {
- for (FunctionProtoType::param_type_iterator O = OldType->param_type_begin(),
- N = NewType->param_type_begin(),
- E = OldType->param_type_end();
- O && (O != E); ++O, ++N) {
+ unsigned *ArgPos, bool Reversed) {
+ assert(OldType->getNumParams() == NewType->getNumParams() &&
+ "Can't compare parameters of functions with different number of "
+ "parameters!");
+ for (size_t I = 0; I < OldType->getNumParams(); I++) {
+ // Reverse iterate over the parameters of `OldType` if `Reversed` is true.
+ size_t J = Reversed ? (OldType->getNumParams() - I - 1) : I;
+
// Ignore address spaces in pointee type. This is to disallow overloading
// on __ptr32/__ptr64 address spaces.
- QualType Old = Context.removePtrSizeAddrSpace(O->getUnqualifiedType());
- QualType New = Context.removePtrSizeAddrSpace(N->getUnqualifiedType());
+ QualType Old = Context.removePtrSizeAddrSpace(OldType->getParamType(I).getUnqualifiedType());
+ QualType New = Context.removePtrSizeAddrSpace(NewType->getParamType(J).getUnqualifiedType());
if (!Context.hasSameType(Old, New)) {
if (ArgPos)
- *ArgPos = O - OldType->param_type_begin();
+ *ArgPos = I;
return false;
}
}
@@ -3197,9 +3203,8 @@ static bool isQualificationConversionStep(QualType FromType, QualType ToType,
Qualifiers FromQuals = FromType.getQualifiers();
Qualifiers ToQuals = ToType.getQualifiers();
- // Ignore __unaligned qualifier if this type is void.
- if (ToType.getUnqualifiedType()->isVoidType())
- FromQuals.removeUnaligned();
+ // Ignore __unaligned qualifier.
+ FromQuals.removeUnaligned();
// Objective-C ARC:
// Check Objective-C lifetime conversions.
@@ -6476,7 +6481,7 @@ void Sema::AddOverloadCandidate(
// (CUDA B.1): Check for invalid calls between targets.
if (getLangOpts().CUDA)
- if (const FunctionDecl *Caller = dyn_cast<FunctionDecl>(CurContext))
+ if (const FunctionDecl *Caller = getCurFunctionDecl(/*AllowLambda=*/true))
// Skip the check for callers that are implicit members, because in this
// case we may not yet know what the member's target is; the target is
// inferred for the member automatically, based on the bases and fields of
@@ -6986,7 +6991,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
// (CUDA B.1): Check for invalid calls between targets.
if (getLangOpts().CUDA)
- if (const FunctionDecl *Caller = dyn_cast<FunctionDecl>(CurContext))
+ if (const FunctionDecl *Caller = getCurFunctionDecl(/*AllowLambda=*/true))
if (!IsAllowedCUDACall(Caller, Method)) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_target;
@@ -8195,6 +8200,49 @@ static Qualifiers CollectVRQualifiers(ASTContext &Context, Expr* ArgExpr) {
return VRQuals;
}
+// Note: We're currently only handling qualifiers that are meaningful for the
+// LHS of compound assignment overloading.
+static void forAllQualifierCombinationsImpl(
+ QualifiersAndAtomic Available, QualifiersAndAtomic Applied,
+ llvm::function_ref<void(QualifiersAndAtomic)> Callback) {
+ // _Atomic
+ if (Available.hasAtomic()) {
+ Available.removeAtomic();
+ forAllQualifierCombinationsImpl(Available, Applied.withAtomic(), Callback);
+ forAllQualifierCombinationsImpl(Available, Applied, Callback);
+ return;
+ }
+
+ // volatile
+ if (Available.hasVolatile()) {
+ Available.removeVolatile();
+ assert(!Applied.hasVolatile());
+ forAllQualifierCombinationsImpl(Available, Applied.withVolatile(),
+ Callback);
+ forAllQualifierCombinationsImpl(Available, Applied, Callback);
+ return;
+ }
+
+ Callback(Applied);
+}
+
+static void forAllQualifierCombinations(
+ QualifiersAndAtomic Quals,
+ llvm::function_ref<void(QualifiersAndAtomic)> Callback) {
+ return forAllQualifierCombinationsImpl(Quals, QualifiersAndAtomic(),
+ Callback);
+}
+
+static QualType makeQualifiedLValueReferenceType(QualType Base,
+ QualifiersAndAtomic Quals,
+ Sema &S) {
+ if (Quals.hasAtomic())
+ Base = S.Context.getAtomicType(Base);
+ if (Quals.hasVolatile())
+ Base = S.Context.getVolatileType(Base);
+ return S.Context.getLValueReferenceType(Base);
+}
+
namespace {
/// Helper class to manage the addition of builtin operator overload
@@ -8205,7 +8253,7 @@ class BuiltinOperatorOverloadBuilder {
// Common instance state available to all overload candidate addition methods.
Sema &S;
ArrayRef<Expr *> Args;
- Qualifiers VisibleTypeConversionsQuals;
+ QualifiersAndAtomic VisibleTypeConversionsQuals;
bool HasArithmeticOrEnumeralCandidateType;
SmallVectorImpl<BuiltinCandidateTypeSet> &CandidateTypes;
OverloadCandidateSet &CandidateSet;
@@ -8329,7 +8377,7 @@ class BuiltinOperatorOverloadBuilder {
public:
BuiltinOperatorOverloadBuilder(
Sema &S, ArrayRef<Expr *> Args,
- Qualifiers VisibleTypeConversionsQuals,
+ QualifiersAndAtomic VisibleTypeConversionsQuals,
bool HasArithmeticOrEnumeralCandidateType,
SmallVectorImpl<BuiltinCandidateTypeSet> &CandidateTypes,
OverloadCandidateSet &CandidateSet)
@@ -8950,18 +8998,14 @@ public:
ParamTypes[1] = ArithmeticTypes[Right];
auto LeftBaseTy = AdjustAddressSpaceForBuiltinOperandType(
S, ArithmeticTypes[Left], Args[0]);
- // Add this built-in operator as a candidate (VQ is empty).
- ParamTypes[0] = S.Context.getLValueReferenceType(LeftBaseTy);
- S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
- /*IsAssignmentOperator=*/isEqualOp);
- // Add this built-in operator as a candidate (VQ is 'volatile').
- if (VisibleTypeConversionsQuals.hasVolatile()) {
- ParamTypes[0] = S.Context.getVolatileType(LeftBaseTy);
- ParamTypes[0] = S.Context.getLValueReferenceType(ParamTypes[0]);
- S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
- /*IsAssignmentOperator=*/isEqualOp);
- }
+ forAllQualifierCombinations(
+ VisibleTypeConversionsQuals, [&](QualifiersAndAtomic Quals) {
+ ParamTypes[0] =
+ makeQualifiedLValueReferenceType(LeftBaseTy, Quals, S);
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet,
+ /*IsAssignmentOperator=*/isEqualOp);
+ });
}
}
@@ -9008,16 +9052,13 @@ public:
ParamTypes[1] = ArithmeticTypes[Right];
auto LeftBaseTy = AdjustAddressSpaceForBuiltinOperandType(
S, ArithmeticTypes[Left], Args[0]);
- // Add this built-in operator as a candidate (VQ is empty).
- ParamTypes[0] = S.Context.getLValueReferenceType(LeftBaseTy);
- S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
- if (VisibleTypeConversionsQuals.hasVolatile()) {
- // Add this built-in operator as a candidate (VQ is 'volatile').
- ParamTypes[0] = LeftBaseTy;
- ParamTypes[0] = S.Context.getVolatileType(ParamTypes[0]);
- ParamTypes[0] = S.Context.getLValueReferenceType(ParamTypes[0]);
- S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
- }
+
+ forAllQualifierCombinations(
+ VisibleTypeConversionsQuals, [&](QualifiersAndAtomic Quals) {
+ ParamTypes[0] =
+ makeQualifiedLValueReferenceType(LeftBaseTy, Quals, S);
+ S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet);
+ });
}
}
}
@@ -9181,10 +9222,13 @@ void Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
// if the operator we're looking at has built-in operator candidates
// that make use of these types. Also record whether we encounter non-record
// candidate types or either arithmetic or enumeral candidate types.
- Qualifiers VisibleTypeConversionsQuals;
+ QualifiersAndAtomic VisibleTypeConversionsQuals;
VisibleTypeConversionsQuals.addConst();
- for (unsigned ArgIdx = 0, N = Args.size(); ArgIdx != N; ++ArgIdx)
+ for (unsigned ArgIdx = 0, N = Args.size(); ArgIdx != N; ++ArgIdx) {
VisibleTypeConversionsQuals += CollectVRQualifiers(Context, Args[ArgIdx]);
+ if (Args[ArgIdx]->getType()->isAtomicType())
+ VisibleTypeConversionsQuals.addAtomic();
+ }
bool HasNonRecordCandidateType = false;
bool HasArithmeticOrEnumeralCandidateType = false;
@@ -9352,7 +9396,8 @@ void Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
break;
case OO_Subscript:
- OpBuilder.addSubscriptOverloads();
+ if (Args.size() == 2)
+ OpBuilder.addSubscriptOverloads();
break;
case OO_ArrowStar:
@@ -9593,6 +9638,32 @@ static bool haveSameParameterTypes(ASTContext &Context, const FunctionDecl *F1,
return true;
}
+/// We're allowed to use constraints partial ordering only if the candidates
+/// have the same parameter types:
+/// [temp.func.order]p6.2.2 [...] or if the function parameters that
+/// positionally correspond between the two templates are not of the same type,
+/// neither template is more specialized than the other.
+/// [over.match.best]p2.6
+/// F1 and F2 are non-template functions with the same parameter-type-lists,
+/// and F1 is more constrained than F2 [...]
+static bool canCompareFunctionConstraints(Sema &S,
+ const OverloadCandidate &Cand1,
+ const OverloadCandidate &Cand2) {
+ // FIXME: Per P2113R0 we also need to compare the template parameter lists
+ // when comparing template functions.
+ if (Cand1.Function && Cand2.Function && Cand1.Function->hasPrototype() &&
+ Cand2.Function->hasPrototype()) {
+ auto *PT1 = cast<FunctionProtoType>(Cand1.Function->getFunctionType());
+ auto *PT2 = cast<FunctionProtoType>(Cand2.Function->getFunctionType());
+ if (PT1->getNumParams() == PT2->getNumParams() &&
+ PT1->isVariadic() == PT2->isVariadic() &&
+ S.FunctionParamTypesAreEqual(PT1, PT2, nullptr,
+ Cand1.isReversed() ^ Cand2.isReversed()))
+ return true;
+ }
+ return false;
+}
+
/// isBetterOverloadCandidate - Determines whether the first overload
/// candidate is a better candidate than the second (C++ 13.3.3p1).
bool clang::isBetterOverloadCandidate(
@@ -9641,7 +9712,7 @@ bool clang::isBetterOverloadCandidate(
// overloading resolution diagnostics.
if (S.getLangOpts().CUDA && Cand1.Function && Cand2.Function &&
S.getLangOpts().GPUExcludeWrongSideOverloads) {
- if (FunctionDecl *Caller = dyn_cast<FunctionDecl>(S.CurContext)) {
+ if (FunctionDecl *Caller = S.getCurFunctionDecl(/*AllowLambda=*/true)) {
bool IsCallerImplicitHD = Sema::isCUDAImplicitHostDeviceFunction(Caller);
bool IsCand1ImplicitHD =
Sema::isCUDAImplicitHostDeviceFunction(Cand1.Function);
@@ -9824,34 +9895,28 @@ bool clang::isBetterOverloadCandidate(
isa<CXXConversionDecl>(Cand1.Function) ? TPOC_Conversion
: TPOC_Call,
Cand1.ExplicitCallArguments, Cand2.ExplicitCallArguments,
- Cand1.isReversed() ^ Cand2.isReversed()))
+ Cand1.isReversed() ^ Cand2.isReversed(),
+ canCompareFunctionConstraints(S, Cand1, Cand2)))
return BetterTemplate == Cand1.Function->getPrimaryTemplate();
}
// -— F1 and F2 are non-template functions with the same
// parameter-type-lists, and F1 is more constrained than F2 [...],
- if (Cand1.Function && Cand2.Function && !Cand1IsSpecialization &&
- !Cand2IsSpecialization && Cand1.Function->hasPrototype() &&
- Cand2.Function->hasPrototype()) {
- auto *PT1 = cast<FunctionProtoType>(Cand1.Function->getFunctionType());
- auto *PT2 = cast<FunctionProtoType>(Cand2.Function->getFunctionType());
- if (PT1->getNumParams() == PT2->getNumParams() &&
- PT1->isVariadic() == PT2->isVariadic() &&
- S.FunctionParamTypesAreEqual(PT1, PT2)) {
- Expr *RC1 = Cand1.Function->getTrailingRequiresClause();
- Expr *RC2 = Cand2.Function->getTrailingRequiresClause();
- if (RC1 && RC2) {
- bool AtLeastAsConstrained1, AtLeastAsConstrained2;
- if (S.IsAtLeastAsConstrained(Cand1.Function, {RC1}, Cand2.Function,
- {RC2}, AtLeastAsConstrained1) ||
- S.IsAtLeastAsConstrained(Cand2.Function, {RC2}, Cand1.Function,
- {RC1}, AtLeastAsConstrained2))
- return false;
- if (AtLeastAsConstrained1 != AtLeastAsConstrained2)
- return AtLeastAsConstrained1;
- } else if (RC1 || RC2) {
- return RC1 != nullptr;
- }
+ if (!Cand1IsSpecialization && !Cand2IsSpecialization &&
+ canCompareFunctionConstraints(S, Cand1, Cand2)) {
+ Expr *RC1 = Cand1.Function->getTrailingRequiresClause();
+ Expr *RC2 = Cand2.Function->getTrailingRequiresClause();
+ if (RC1 && RC2) {
+ bool AtLeastAsConstrained1, AtLeastAsConstrained2;
+ if (S.IsAtLeastAsConstrained(Cand1.Function, {RC1}, Cand2.Function, {RC2},
+ AtLeastAsConstrained1) ||
+ S.IsAtLeastAsConstrained(Cand2.Function, {RC2}, Cand1.Function, {RC1},
+ AtLeastAsConstrained2))
+ return false;
+ if (AtLeastAsConstrained1 != AtLeastAsConstrained2)
+ return AtLeastAsConstrained1;
+ } else if (RC1 || RC2) {
+ return RC1 != nullptr;
}
}
@@ -9924,7 +9989,7 @@ bool clang::isBetterOverloadCandidate(
// If other rules cannot determine which is better, CUDA preference is used
// to determine which is better.
if (S.getLangOpts().CUDA && Cand1.Function && Cand2.Function) {
- FunctionDecl *Caller = dyn_cast<FunctionDecl>(S.CurContext);
+ FunctionDecl *Caller = S.getCurFunctionDecl(/*AllowLambda=*/true);
return S.IdentifyCUDAPreference(Caller, Cand1.Function) >
S.IdentifyCUDAPreference(Caller, Cand2.Function);
}
@@ -10045,7 +10110,7 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc,
// -fgpu-exclude-wrong-side-overloads is on, all candidates are compared
// uniformly in isBetterOverloadCandidate.
if (S.getLangOpts().CUDA && !S.getLangOpts().GPUExcludeWrongSideOverloads) {
- const FunctionDecl *Caller = dyn_cast<FunctionDecl>(S.CurContext);
+ const FunctionDecl *Caller = S.getCurFunctionDecl(/*AllowLambda=*/true);
bool ContainsSameSideCandidate =
llvm::any_of(Candidates, [&](OverloadCandidate *Cand) {
// Check viable function only.
@@ -10258,10 +10323,19 @@ static bool checkAddressOfFunctionIsAvailable(Sema &S, const FunctionDecl *FD,
return false;
if (!Satisfaction.IsSatisfied) {
if (Complain) {
- if (InOverloadResolution)
+ if (InOverloadResolution) {
+ SmallString<128> TemplateArgString;
+ if (FunctionTemplateDecl *FunTmpl = FD->getPrimaryTemplate()) {
+ TemplateArgString += " ";
+ TemplateArgString += S.getTemplateArgumentBindingsText(
+ FunTmpl->getTemplateParameters(),
+ *FD->getTemplateSpecializationArgs());
+ }
+
S.Diag(FD->getBeginLoc(),
- diag::note_ovl_candidate_unsatisfied_constraints);
- else
+ diag::note_ovl_candidate_unsatisfied_constraints)
+ << TemplateArgString;
+ } else
S.Diag(Loc, diag::err_addrof_function_constraints_not_satisfied)
<< FD;
S.DiagnoseUnsatisfiedConstraint(Satisfaction);
@@ -11070,7 +11144,7 @@ static void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand,
/// CUDA: diagnose an invalid call across targets.
static void DiagnoseBadTarget(Sema &S, OverloadCandidate *Cand) {
- FunctionDecl *Caller = cast<FunctionDecl>(S.CurContext);
+ FunctionDecl *Caller = S.getCurFunctionDecl(/*AllowLambda=*/true);
FunctionDecl *Callee = Cand->Function;
Sema::CUDAFunctionTarget CallerTarget = S.IdentifyCUDATarget(Caller),
@@ -11192,6 +11266,13 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
if (shouldSkipNotingLambdaConversionDecl(Fn))
return;
+ // There is no physical candidate declaration to point to for OpenCL builtins.
+ // Except for failed conversions, the notes are identical for each candidate,
+ // so do not generate such notes.
+ if (S.getLangOpts().OpenCL && Fn->isImplicit() &&
+ Cand->FailureKind != ovl_fail_bad_conversion)
+ return;
+
// Note deleted candidates, but only if they're viable.
if (Cand->Viable) {
if (Fn->isDeleted()) {
@@ -11617,7 +11698,9 @@ CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
// Conversion 0 is 'this', which doesn't have a corresponding parameter.
ConvIdx = 1;
if (CSK == OverloadCandidateSet::CSK_Operator &&
- Cand->Function->getDeclName().getCXXOverloadedOperator() != OO_Call)
+ Cand->Function->getDeclName().getCXXOverloadedOperator() != OO_Call &&
+ Cand->Function->getDeclName().getCXXOverloadedOperator() !=
+ OO_Subscript)
// Argument 0 is 'this', which doesn't have a corresponding parameter.
ArgIdx = 1;
}
@@ -12127,7 +12210,7 @@ private:
if (FunctionDecl *FunDecl = dyn_cast<FunctionDecl>(Fn)) {
if (S.getLangOpts().CUDA)
- if (FunctionDecl *Caller = dyn_cast<FunctionDecl>(S.CurContext))
+ if (FunctionDecl *Caller = S.getCurFunctionDecl(/*AllowLambda=*/true))
if (!Caller->isImplicit() && !S.IsAllowedCUDACall(Caller, FunDecl))
return false;
if (FunDecl->isMultiVersion()) {
@@ -12244,7 +12327,8 @@ private:
}
void EliminateSuboptimalCudaMatches() {
- S.EraseUnwantedCUDAMatches(dyn_cast<FunctionDecl>(S.CurContext), Matches);
+ S.EraseUnwantedCUDAMatches(S.getCurFunctionDecl(/*AllowLambda=*/true),
+ Matches);
}
public:
@@ -12448,7 +12532,7 @@ Sema::resolveAddressOfSingleOverloadCandidate(Expr *E, DeclAccessPair &Pair) {
// We skipped over some ambiguous declarations which might be ambiguous with
// the selected result.
for (FunctionDecl *Skipped : AmbiguousDecls)
- if (!CheckMoreConstrained(Skipped, Result).hasValue())
+ if (!CheckMoreConstrained(Skipped, Result))
return nullptr;
Pair = DAP;
}
@@ -13119,7 +13203,7 @@ static QualType chooseRecoveryType(OverloadCandidateSet &CS,
if (!Result)
return QualType();
- auto Value = Result.getValue();
+ auto Value = *Result;
if (Value.isNull() || Value->isUndeducedType())
return QualType();
return Value;
@@ -14055,17 +14139,65 @@ ExprResult Sema::BuildSynthesizedThreeWayComparison(
return PseudoObjectExpr::Create(Context, SyntacticForm, SemanticForm, 2);
}
-ExprResult
-Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
- SourceLocation RLoc,
- Expr *Base, Expr *Idx) {
- Expr *Args[2] = { Base, Idx };
+static bool PrepareArgumentsForCallToObjectOfClassType(
+ Sema &S, SmallVectorImpl<Expr *> &MethodArgs, CXXMethodDecl *Method,
+ MultiExprArg Args, SourceLocation LParenLoc) {
+
+ const auto *Proto = Method->getType()->castAs<FunctionProtoType>();
+ unsigned NumParams = Proto->getNumParams();
+ unsigned NumArgsSlots =
+ MethodArgs.size() + std::max<unsigned>(Args.size(), NumParams);
+ // Build the full argument list for the method call (the implicit object
+ // parameter is placed at the beginning of the list).
+ MethodArgs.reserve(MethodArgs.size() + NumArgsSlots);
+ bool IsError = false;
+ // Initialize the implicit object parameter.
+ // Check the argument types.
+ for (unsigned i = 0; i != NumParams; i++) {
+ Expr *Arg;
+ if (i < Args.size()) {
+ Arg = Args[i];
+ ExprResult InputInit =
+ S.PerformCopyInitialization(InitializedEntity::InitializeParameter(
+ S.Context, Method->getParamDecl(i)),
+ SourceLocation(), Arg);
+ IsError |= InputInit.isInvalid();
+ Arg = InputInit.getAs<Expr>();
+ } else {
+ ExprResult DefArg =
+ S.BuildCXXDefaultArgExpr(LParenLoc, Method, Method->getParamDecl(i));
+ if (DefArg.isInvalid()) {
+ IsError = true;
+ break;
+ }
+ Arg = DefArg.getAs<Expr>();
+ }
+
+ MethodArgs.push_back(Arg);
+ }
+ return IsError;
+}
+
+ExprResult Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
+ SourceLocation RLoc,
+ Expr *Base,
+ MultiExprArg ArgExpr) {
+ SmallVector<Expr *, 2> Args;
+ Args.push_back(Base);
+ for (auto e : ArgExpr) {
+ Args.push_back(e);
+ }
DeclarationName OpName =
Context.DeclarationNames.getCXXOperatorName(OO_Subscript);
+ SourceRange Range = ArgExpr.empty()
+ ? SourceRange{}
+ : SourceRange(ArgExpr.front()->getBeginLoc(),
+ ArgExpr.back()->getEndLoc());
+
// If either side is type-dependent, create an appropriate dependent
// expression.
- if (Args[0]->isTypeDependent() || Args[1]->isTypeDependent()) {
+ if (Expr::hasAnyTypeDependentArguments(Args)) {
CXXRecordDecl *NamingClass = nullptr; // lookup ignores member operators
// CHECKME: no 'operator' keyword?
@@ -14082,12 +14214,11 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
CurFPFeatureOverrides());
}
- // Handle placeholders on both operands.
- if (checkPlaceholderForOverload(*this, Args[0]))
- return ExprError();
- if (checkPlaceholderForOverload(*this, Args[1]))
+ // Handle placeholders
+ UnbridgedCastsSet UnbridgedCasts;
+ if (checkArgPlaceholdersForOverload(*this, Args, UnbridgedCasts)) {
return ExprError();
-
+ }
// Build an empty overload set.
OverloadCandidateSet CandidateSet(LLoc, OverloadCandidateSet::CSK_Operator);
@@ -14097,7 +14228,8 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
AddMemberOperatorCandidates(OO_Subscript, LLoc, Args, CandidateSet);
// Add builtin operator candidates.
- AddBuiltinOperatorCandidates(OO_Subscript, LLoc, Args, CandidateSet);
+ if (Args.size() == 2)
+ AddBuiltinOperatorCandidates(OO_Subscript, LLoc, Args, CandidateSet);
bool HadMultipleCandidates = (CandidateSet.size() > 1);
@@ -14112,38 +14244,28 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
// We matched an overloaded operator. Build a call to that
// operator.
- CheckMemberOperatorAccess(LLoc, Args[0], Args[1], Best->FoundDecl);
+ CheckMemberOperatorAccess(LLoc, Args[0], ArgExpr, Best->FoundDecl);
// Convert the arguments.
CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl);
- ExprResult Arg0 =
- PerformObjectArgumentInitialization(Args[0], /*Qualifier=*/nullptr,
- Best->FoundDecl, Method);
+ SmallVector<Expr *, 2> MethodArgs;
+ ExprResult Arg0 = PerformObjectArgumentInitialization(
+ Args[0], /*Qualifier=*/nullptr, Best->FoundDecl, Method);
if (Arg0.isInvalid())
return ExprError();
- Args[0] = Arg0.get();
- // Convert the arguments.
- ExprResult InputInit
- = PerformCopyInitialization(InitializedEntity::InitializeParameter(
- Context,
- FnDecl->getParamDecl(0)),
- SourceLocation(),
- Args[1]);
- if (InputInit.isInvalid())
+ MethodArgs.push_back(Arg0.get());
+ bool IsError = PrepareArgumentsForCallToObjectOfClassType(
+ *this, MethodArgs, Method, ArgExpr, LLoc);
+ if (IsError)
return ExprError();
- Args[1] = InputInit.getAs<Expr>();
-
// Build the actual expression node.
DeclarationNameInfo OpLocInfo(OpName, LLoc);
OpLocInfo.setCXXOperatorNameRange(SourceRange(LLoc, RLoc));
- ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl,
- Best->FoundDecl,
- Base,
- HadMultipleCandidates,
- OpLocInfo.getLoc(),
- OpLocInfo.getInfo());
+ ExprResult FnExpr = CreateFunctionRefExpr(
+ *this, FnDecl, Best->FoundDecl, Base, HadMultipleCandidates,
+ OpLocInfo.getLoc(), OpLocInfo.getInfo());
if (FnExpr.isInvalid())
return ExprError();
@@ -14153,7 +14275,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
ResultTy = ResultTy.getNonLValueExprType(Context);
CXXOperatorCallExpr *TheCall = CXXOperatorCallExpr::Create(
- Context, OO_Subscript, FnExpr.get(), Args, ResultTy, VK, RLoc,
+ Context, OO_Subscript, FnExpr.get(), MethodArgs, ResultTy, VK, RLoc,
CurFPFeatureOverrides());
if (CheckCallReturnType(FnDecl->getReturnType(), LLoc, TheCall, FnDecl))
return ExprError();
@@ -14187,33 +14309,41 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
}
case OR_No_Viable_Function: {
- PartialDiagnostic PD = CandidateSet.empty()
- ? (PDiag(diag::err_ovl_no_oper)
- << Args[0]->getType() << /*subscript*/ 0
- << Args[0]->getSourceRange() << Args[1]->getSourceRange())
- : (PDiag(diag::err_ovl_no_viable_subscript)
- << Args[0]->getType() << Args[0]->getSourceRange()
- << Args[1]->getSourceRange());
+ PartialDiagnostic PD =
+ CandidateSet.empty()
+ ? (PDiag(diag::err_ovl_no_oper)
+ << Args[0]->getType() << /*subscript*/ 0
+ << Args[0]->getSourceRange() << Range)
+ : (PDiag(diag::err_ovl_no_viable_subscript)
+ << Args[0]->getType() << Args[0]->getSourceRange() << Range);
CandidateSet.NoteCandidates(PartialDiagnosticAt(LLoc, PD), *this,
- OCD_AllCandidates, Args, "[]", LLoc);
+ OCD_AllCandidates, ArgExpr, "[]", LLoc);
return ExprError();
}
case OR_Ambiguous:
- CandidateSet.NoteCandidates(
- PartialDiagnosticAt(LLoc, PDiag(diag::err_ovl_ambiguous_oper_binary)
- << "[]" << Args[0]->getType()
- << Args[1]->getType()
- << Args[0]->getSourceRange()
- << Args[1]->getSourceRange()),
- *this, OCD_AmbiguousCandidates, Args, "[]", LLoc);
+ if (Args.size() == 2) {
+ CandidateSet.NoteCandidates(
+ PartialDiagnosticAt(
+ LLoc, PDiag(diag::err_ovl_ambiguous_oper_binary)
+ << "[]" << Args[0]->getType() << Args[1]->getType()
+ << Args[0]->getSourceRange() << Range),
+ *this, OCD_AmbiguousCandidates, Args, "[]", LLoc);
+ } else {
+ CandidateSet.NoteCandidates(
+ PartialDiagnosticAt(LLoc,
+ PDiag(diag::err_ovl_ambiguous_subscript_call)
+ << Args[0]->getType()
+ << Args[0]->getSourceRange() << Range),
+ *this, OCD_AmbiguousCandidates, Args, "[]", LLoc);
+ }
return ExprError();
case OR_Deleted:
CandidateSet.NoteCandidates(
PartialDiagnosticAt(LLoc, PDiag(diag::err_ovl_deleted_oper)
<< "[]" << Args[0]->getSourceRange()
- << Args[1]->getSourceRange()),
+ << Range),
*this, OCD_AllCandidates, Args, "[]", LLoc);
return ExprError();
}
@@ -14298,7 +14428,7 @@ ExprResult Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
if (!AllowRecovery)
return ExprError();
std::vector<Expr *> SubExprs = {MemExprE};
- llvm::for_each(Args, [&SubExprs](Expr *E) { SubExprs.push_back(E); });
+ llvm::append_range(SubExprs, Args);
return CreateRecoveryExpr(MemExprE->getBeginLoc(), RParenLoc, SubExprs,
Type);
};
@@ -14717,14 +14847,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
if (NewFn.isInvalid())
return true;
- // The number of argument slots to allocate in the call. If we have default
- // arguments we need to allocate space for them as well. We additionally
- // need one more slot for the object parameter.
- unsigned NumArgsSlots = 1 + std::max<unsigned>(Args.size(), NumParams);
-
- // Build the full argument list for the method call (the implicit object
- // parameter is placed at the beginning of the list).
- SmallVector<Expr *, 8> MethodArgs(NumArgsSlots);
+ SmallVector<Expr *, 8> MethodArgs;
+ MethodArgs.reserve(NumParams + 1);
bool IsError = false;
@@ -14736,37 +14860,10 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
IsError = true;
else
Object = ObjRes;
- MethodArgs[0] = Object.get();
-
- // Check the argument types.
- for (unsigned i = 0; i != NumParams; i++) {
- Expr *Arg;
- if (i < Args.size()) {
- Arg = Args[i];
-
- // Pass the argument.
+ MethodArgs.push_back(Object.get());
- ExprResult InputInit
- = PerformCopyInitialization(InitializedEntity::InitializeParameter(
- Context,
- Method->getParamDecl(i)),
- SourceLocation(), Arg);
-
- IsError |= InputInit.isInvalid();
- Arg = InputInit.getAs<Expr>();
- } else {
- ExprResult DefArg
- = BuildCXXDefaultArgExpr(LParenLoc, Method, Method->getParamDecl(i));
- if (DefArg.isInvalid()) {
- IsError = true;
- break;
- }
-
- Arg = DefArg.getAs<Expr>();
- }
-
- MethodArgs[i + 1] = Arg;
- }
+ IsError |= PrepareArgumentsForCallToObjectOfClassType(
+ *this, MethodArgs, Method, Args, LParenLoc);
// If this is a variadic call, handle args passed through "...".
if (Proto->isVariadic()) {
@@ -14775,7 +14872,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
ExprResult Arg = DefaultVariadicArgumentPromotion(Args[i], VariadicMethod,
nullptr);
IsError |= Arg.isInvalid();
- MethodArgs[i + 1] = Arg.get();
+ MethodArgs.push_back(Arg.get());
}
}
@@ -15165,10 +15262,9 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
if (SubExpr == UnOp->getSubExpr())
return UnOp;
- return UnaryOperator::Create(
- Context, SubExpr, UO_AddrOf, Context.getPointerType(SubExpr->getType()),
- VK_PRValue, OK_Ordinary, UnOp->getOperatorLoc(), false,
- CurFPFeatureOverrides());
+ // FIXME: This can't currently fail, but in principle it could.
+ return CreateBuiltinUnaryOp(UnOp->getOperatorLoc(), UO_AddrOf, SubExpr)
+ .get();
}
if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(E)) {
@@ -15179,10 +15275,20 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
TemplateArgs = &TemplateArgsBuffer;
}
- DeclRefExpr *DRE =
- BuildDeclRefExpr(Fn, Fn->getType(), VK_LValue, ULE->getNameInfo(),
- ULE->getQualifierLoc(), Found.getDecl(),
- ULE->getTemplateKeywordLoc(), TemplateArgs);
+ QualType Type = Fn->getType();
+ ExprValueKind ValueKind = getLangOpts().CPlusPlus ? VK_LValue : VK_PRValue;
+
+ // FIXME: Duplicated from BuildDeclarationNameExpr.
+ if (unsigned BID = Fn->getBuiltinID()) {
+ if (!Context.BuiltinInfo.isDirectlyAddressable(BID)) {
+ Type = Context.BuiltinFnTy;
+ ValueKind = VK_PRValue;
+ }
+ }
+
+ DeclRefExpr *DRE = BuildDeclRefExpr(
+ Fn, Type, ValueKind, ULE->getNameInfo(), ULE->getQualifierLoc(),
+ Found.getDecl(), ULE->getTemplateKeywordLoc(), TemplateArgs);
DRE->setHadMultipleCandidates(ULE->getNumDecls() > 1);
return DRE;
}
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 746eb82a5bdc..f25694ce48c9 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -341,7 +341,7 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S, unsigned DiagID) {
return DiagnoseUnusedExprResult(POE->getSemanticExpr(0), DiagID);
if (isa<ObjCSubscriptRefExpr>(Source))
DiagID = diag::warn_unused_container_subscript_expr;
- else
+ else if (isa<ObjCPropertyRefExpr>(Source))
DiagID = diag::warn_unused_property_expr;
} else if (const CXXFunctionalCastExpr *FC
= dyn_cast<CXXFunctionalCastExpr>(E)) {
@@ -442,7 +442,16 @@ StmtResult Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R,
DiagnoseEmptyLoopBody(Elts[i], Elts[i + 1]);
}
- return CompoundStmt::Create(Context, Elts, L, R);
+ // Calculate difference between FP options in this compound statement and in
+ // the enclosing one. If this is a function body, take the difference against
+ // default options. In this case the difference will indicate options that are
+ // changed upon entry to the statement.
+ FPOptions FPO = (getCurFunction()->CompoundScopes.size() == 1)
+ ? FPOptions(getLangOpts())
+ : getCurCompoundScope().InitialFPFeatures;
+ FPOptionsOverride FPDiff = getCurFPFeatures().getChangesFrom(FPO);
+
+ return CompoundStmt::Create(Context, Elts, FPDiff, L, R);
}
ExprResult
@@ -587,7 +596,7 @@ StmtResult Sema::BuildAttributedStmt(SourceLocation AttrsLoc,
return AttributedStmt::Create(Context, AttrsLoc, Attrs, SubStmt);
}
-StmtResult Sema::ActOnAttributedStmt(const ParsedAttributesWithRange &Attrs,
+StmtResult Sema::ActOnAttributedStmt(const ParsedAttributes &Attrs,
Stmt *SubStmt) {
SmallVector<const Attr *, 1> SemanticAttrs;
ProcessStmtAttributes(SubStmt, Attrs, SemanticAttrs);
@@ -888,8 +897,7 @@ StmtResult Sema::ActOnIfStmt(SourceLocation IfLoc,
CommaVisitor(*this).Visit(CondExpr);
if (!ConstevalOrNegatedConsteval && !elseStmt)
- DiagnoseEmptyStmtBody(CondExpr->getEndLoc(), thenStmt,
- diag::warn_empty_if_body);
+ DiagnoseEmptyStmtBody(RParenLoc, thenStmt, diag::warn_empty_if_body);
if (ConstevalOrNegatedConsteval ||
StatementKind == IfStatementKind::Constexpr) {
@@ -3312,7 +3320,7 @@ Sema::ActOnContinueStmt(SourceLocation ContinueLoc, Scope *CurScope) {
// C99 6.8.6.2p1: A break shall appear only in or as a loop body.
return StmtError(Diag(ContinueLoc, diag::err_continue_not_in_loop));
}
- if (S->getFlags() & Scope::ConditionVarScope) {
+ if (S->isConditionVarScope()) {
// We cannot 'continue;' from within a statement expression in the
// initializer of a condition variable because we would jump past the
// initialization of that variable.
@@ -3762,8 +3770,8 @@ TypeLoc Sema::getReturnTypeLoc(FunctionDecl *FD) const {
bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD,
SourceLocation ReturnLoc,
Expr *&RetExpr,
- AutoType *AT) {
- // If this is the conversion function for a lambda, we choose to deduce it
+ const AutoType *AT) {
+ // If this is the conversion function for a lambda, we choose to deduce its
// type from the corresponding call operator, not from the synthesized return
// statement within it. See Sema::DeduceReturnType.
if (isLambdaConversionOperator(FD))
@@ -3808,19 +3816,26 @@ bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD,
LocalTypedefNameReferencer Referencer(*this);
Referencer.TraverseType(RetExpr->getType());
} else {
- // In the case of a return with no operand, the initializer is considered
- // to be void().
- //
- // Deduction here can only succeed if the return type is exactly 'cv auto'
- // or 'decltype(auto)', so just check for that case directly.
+ // For a function with a deduced result type to return void,
+ // the result type as written must be 'auto' or 'decltype(auto)',
+ // possibly cv-qualified or constrained, but not ref-qualified.
if (!OrigResultType.getType()->getAs<AutoType>()) {
Diag(ReturnLoc, diag::err_auto_fn_return_void_but_not_auto)
<< OrigResultType.getType();
return true;
}
- // We always deduce U = void in this case.
- Deduced = SubstAutoType(OrigResultType.getType(), Context.VoidTy);
- if (Deduced.isNull())
+ // In the case of a return with no operand, the initializer is considered
+ // to be 'void()'.
+ Expr *Dummy = new (Context) CXXScalarValueInitExpr(
+ Context.VoidTy,
+ Context.getTrivialTypeSourceInfo(Context.VoidTy, ReturnLoc), ReturnLoc);
+ DeduceAutoResult DAR = DeduceAutoType(OrigResultType, Dummy, Deduced);
+
+ if (DAR == DAR_Failed && !FD->isInvalidDecl())
+ Diag(ReturnLoc, diag::err_auto_fn_deduction_failure)
+ << OrigResultType.getType() << Dummy->getType();
+
+ if (DAR != DAR_Succeeded)
return true;
}
@@ -4098,7 +4113,9 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp,
} else if (!RetValExp && !HasDependentReturnType) {
FunctionDecl *FD = getCurFunctionDecl();
- if (getLangOpts().CPlusPlus11 && FD && FD->isConstexpr()) {
+ if ((FD && FD->isInvalidDecl()) || FnRetType->containsErrors()) {
+ // The intended return type might have been "void", so don't warn.
+ } else if (getLangOpts().CPlusPlus11 && FD && FD->isConstexpr()) {
// C++11 [stmt.return]p2
Diag(ReturnLoc, diag::err_constexpr_return_missing_expr)
<< FD << FD->isConsteval();
diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp
index 49f7a8d573d5..8dfcf9899e3f 100644
--- a/clang/lib/Sema/SemaStmtAsm.cpp
+++ b/clang/lib/Sema/SemaStmtAsm.cpp
@@ -254,7 +254,7 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos;
// The parser verifies that there is a string literal here.
- assert(AsmString->isAscii());
+ assert(AsmString->isOrdinary());
FunctionDecl *FD = dyn_cast<FunctionDecl>(getCurLexicalContext());
llvm::StringMap<bool> FeatureMap;
@@ -262,7 +262,7 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
for (unsigned i = 0; i != NumOutputs; i++) {
StringLiteral *Literal = Constraints[i];
- assert(Literal->isAscii());
+ assert(Literal->isOrdinary());
StringRef OutputName;
if (Names[i])
@@ -353,7 +353,7 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
for (unsigned i = NumOutputs, e = NumOutputs + NumInputs; i != e; i++) {
StringLiteral *Literal = Constraints[i];
- assert(Literal->isAscii());
+ assert(Literal->isOrdinary());
StringRef InputName;
if (Names[i])
@@ -459,7 +459,7 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
// Check that the clobbers are valid.
for (unsigned i = 0; i != NumClobbers; i++) {
StringLiteral *Literal = Clobbers[i];
- assert(Literal->isAscii());
+ assert(Literal->isOrdinary());
StringRef Clobber = Literal->getString();
@@ -667,8 +667,17 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
// output was a register, just extend the shorter one to the size of the
// larger one.
if (!SmallerValueMentioned && InputDomain != AD_Other &&
- OutputConstraintInfos[TiedTo].allowsRegister())
+ OutputConstraintInfos[TiedTo].allowsRegister()) {
+ // FIXME: GCC supports the OutSize to be 128 at maximum. Currently codegen
+ // crash when the size larger than the register size. So we limit it here.
+ if (OutTy->isStructureType() &&
+ Context.getIntTypeForBitwidth(OutSize, /*Signed*/ false).isNull()) {
+ targetDiag(OutputExpr->getExprLoc(), diag::err_store_value_to_reg);
+ return NS;
+ }
+
continue;
+ }
// Either both of the operands were mentioned or the smaller one was
// mentioned. One more special case that we'll allow: if the tied input is
@@ -707,10 +716,7 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
NamedOperandList.emplace_back(
std::make_pair(Names[i]->getName(), Exprs[i]));
// Sort NamedOperandList.
- std::stable_sort(NamedOperandList.begin(), NamedOperandList.end(),
- [](const NamedOperand &LHS, const NamedOperand &RHS) {
- return LHS.first < RHS.first;
- });
+ llvm::stable_sort(NamedOperandList, llvm::less_first());
// Find adjacent duplicate operand.
SmallVector<NamedOperand, 4>::iterator Found =
std::adjacent_find(begin(NamedOperandList), end(NamedOperandList),
@@ -727,6 +733,9 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
}
if (NS->isAsmGoto())
setFunctionHasBranchIntoScope();
+
+ CleanupVarDeclMarking();
+ DiscardCleanupsInEvaluationContext();
return NS;
}
diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp
index 4f2977f89ce1..b03c055a4f50 100644
--- a/clang/lib/Sema/SemaStmtAttr.cpp
+++ b/clang/lib/Sema/SemaStmtAttr.cpp
@@ -175,17 +175,22 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const ParsedAttr &A,
namespace {
class CallExprFinder : public ConstEvaluatedExprVisitor<CallExprFinder> {
- bool FoundCallExpr = false;
+ bool FoundAsmStmt = false;
+ std::vector<const CallExpr *> CallExprs;
public:
typedef ConstEvaluatedExprVisitor<CallExprFinder> Inherited;
CallExprFinder(Sema &S, const Stmt *St) : Inherited(S.Context) { Visit(St); }
- bool foundCallExpr() { return FoundCallExpr; }
+ bool foundCallExpr() { return !CallExprs.empty(); }
+ const std::vector<const CallExpr *> &getCallExprs() { return CallExprs; }
- void VisitCallExpr(const CallExpr *E) { FoundCallExpr = true; }
- void VisitAsmStmt(const AsmStmt *S) { FoundCallExpr = true; }
+ bool foundAsmStmt() { return FoundAsmStmt; }
+
+ void VisitCallExpr(const CallExpr *E) { CallExprs.push_back(E); }
+
+ void VisitAsmStmt(const AsmStmt *S) { FoundAsmStmt = true; }
void Visit(const Stmt *St) {
if (!St)
@@ -200,15 +205,67 @@ static Attr *handleNoMergeAttr(Sema &S, Stmt *St, const ParsedAttr &A,
NoMergeAttr NMA(S.Context, A);
CallExprFinder CEF(S, St);
- if (!CEF.foundCallExpr()) {
- S.Diag(St->getBeginLoc(), diag::warn_nomerge_attribute_ignored_in_stmt)
- << NMA.getSpelling();
+ if (!CEF.foundCallExpr() && !CEF.foundAsmStmt()) {
+ S.Diag(St->getBeginLoc(), diag::warn_attribute_ignored_no_calls_in_stmt)
+ << A;
return nullptr;
}
return ::new (S.Context) NoMergeAttr(S.Context, A);
}
+static Attr *handleNoInlineAttr(Sema &S, Stmt *St, const ParsedAttr &A,
+ SourceRange Range) {
+ NoInlineAttr NIA(S.Context, A);
+ if (!NIA.isClangNoInline()) {
+ S.Diag(St->getBeginLoc(), diag::warn_function_attribute_ignored_in_stmt)
+ << "[[clang::noinline]]";
+ return nullptr;
+ }
+
+ CallExprFinder CEF(S, St);
+ if (!CEF.foundCallExpr()) {
+ S.Diag(St->getBeginLoc(), diag::warn_attribute_ignored_no_calls_in_stmt)
+ << A;
+ return nullptr;
+ }
+
+ for (const auto *CallExpr : CEF.getCallExprs()) {
+ const Decl *Decl = CallExpr->getCalleeDecl();
+ if (Decl->hasAttr<AlwaysInlineAttr>() || Decl->hasAttr<FlattenAttr>())
+ S.Diag(St->getBeginLoc(), diag::warn_function_stmt_attribute_precedence)
+ << A << (Decl->hasAttr<AlwaysInlineAttr>() ? 0 : 1);
+ }
+
+ return ::new (S.Context) NoInlineAttr(S.Context, A);
+}
+
+static Attr *handleAlwaysInlineAttr(Sema &S, Stmt *St, const ParsedAttr &A,
+ SourceRange Range) {
+ AlwaysInlineAttr AIA(S.Context, A);
+ if (!AIA.isClangAlwaysInline()) {
+ S.Diag(St->getBeginLoc(), diag::warn_function_attribute_ignored_in_stmt)
+ << "[[clang::always_inline]]";
+ return nullptr;
+ }
+
+ CallExprFinder CEF(S, St);
+ if (!CEF.foundCallExpr()) {
+ S.Diag(St->getBeginLoc(), diag::warn_attribute_ignored_no_calls_in_stmt)
+ << A;
+ return nullptr;
+ }
+
+ for (const auto *CallExpr : CEF.getCallExprs()) {
+ const Decl *Decl = CallExpr->getCalleeDecl();
+ if (Decl->hasAttr<NoInlineAttr>() || Decl->hasAttr<FlattenAttr>())
+ S.Diag(St->getBeginLoc(), diag::warn_function_stmt_attribute_precedence)
+ << A << (Decl->hasAttr<NoInlineAttr>() ? 2 : 1);
+ }
+
+ return ::new (S.Context) AlwaysInlineAttr(S.Context, A);
+}
+
static Attr *handleMustTailAttr(Sema &S, Stmt *St, const ParsedAttr &A,
SourceRange Range) {
// Validation is in Sema::ActOnAttributedStmt().
@@ -408,6 +465,8 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A,
return nullptr;
switch (A.getKind()) {
+ case ParsedAttr::AT_AlwaysInline:
+ return handleAlwaysInlineAttr(S, St, A, Range);
case ParsedAttr::AT_FallThrough:
return handleFallThroughAttr(S, St, A, Range);
case ParsedAttr::AT_LoopHint:
@@ -418,6 +477,8 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A,
return handleSuppressAttr(S, St, A, Range);
case ParsedAttr::AT_NoMerge:
return handleNoMergeAttr(S, St, A, Range);
+ case ParsedAttr::AT_NoInline:
+ return handleNoInlineAttr(S, St, A, Range);
case ParsedAttr::AT_MustTail:
return handleMustTailAttr(S, St, A, Range);
case ParsedAttr::AT_Likely:
@@ -434,8 +495,7 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A,
}
}
-void Sema::ProcessStmtAttributes(Stmt *S,
- const ParsedAttributesWithRange &InAttrs,
+void Sema::ProcessStmtAttributes(Stmt *S, const ParsedAttributes &InAttrs,
SmallVectorImpl<const Attr *> &OutAttrs) {
for (const ParsedAttr &AL : InAttrs) {
if (const Attr *A = ProcessStmtAttribute(*this, S, AL, InAttrs.Range))
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 64a0b45feb98..dbfe6164bda2 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -11,11 +11,13 @@
#include "TreeTransform.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/AST/TemplateName.h"
#include "clang/AST/TypeVisitor.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/LangOptions.h"
@@ -223,6 +225,7 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
return TNK_Non_template;
NamedDecl *D = nullptr;
+ UsingShadowDecl *FoundUsingShadow = dyn_cast<UsingShadowDecl>(*R.begin());
if (R.isAmbiguous()) {
// If we got an ambiguity involving a non-function template, treat this
// as a template name, and pick an arbitrary template for error recovery.
@@ -233,6 +236,7 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
AnyFunctionTemplates = true;
else {
D = FoundTemplate;
+ FoundUsingShadow = dyn_cast<UsingShadowDecl>(FoundD);
break;
}
}
@@ -280,13 +284,13 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
}
TemplateDecl *TD = cast<TemplateDecl>(D);
-
+ Template =
+ FoundUsingShadow ? TemplateName(FoundUsingShadow) : TemplateName(TD);
+ assert(!FoundUsingShadow || FoundUsingShadow->getTargetDecl() == TD);
if (SS.isSet() && !SS.isInvalid()) {
NestedNameSpecifier *Qualifier = SS.getScopeRep();
- Template = Context.getQualifiedTemplateName(Qualifier,
- hasTemplateKeyword, TD);
- } else {
- Template = TemplateName(TD);
+ Template = Context.getQualifiedTemplateName(Qualifier, hasTemplateKeyword,
+ Template);
}
if (isa<FunctionTemplateDecl>(TD)) {
@@ -795,8 +799,9 @@ bool Sema::DiagnoseUninstantiableTemplate(SourceLocation PointOfInstantiation,
if (PatternDef && !IsEntityBeingDefined) {
NamedDecl *SuggestedDef = nullptr;
- if (!hasVisibleDefinition(const_cast<NamedDecl*>(PatternDef), &SuggestedDef,
- /*OnlyNeedComplete*/false)) {
+ if (!hasReachableDefinition(const_cast<NamedDecl *>(PatternDef),
+ &SuggestedDef,
+ /*OnlyNeedComplete*/ false)) {
// If we're allowed to diagnose this and recover, do so.
bool Recover = Complain && !isSFINAEContext();
if (Complain)
@@ -863,7 +868,7 @@ bool Sema::DiagnoseUninstantiableTemplate(SourceLocation PointOfInstantiation,
}
}
if (Note) // Diagnostics were emitted.
- Diag(Pattern->getLocation(), Note.getValue());
+ Diag(Pattern->getLocation(), *Note);
// In general, Instantiation isn't marked invalid to get more than one
// error for multiple undefined instantiations. But the code that does
@@ -997,8 +1002,8 @@ ParsedTemplateArgument Sema::ActOnTemplateTypeArgument(TypeResult ParsedType) {
TemplateName Name = DTST.getTypePtr()->getTemplateName();
if (SS.isSet())
Name = Context.getQualifiedTemplateName(SS.getScopeRep(),
- /*HasTemplateKeyword*/ false,
- Name.getAsTemplateDecl());
+ /*HasTemplateKeyword=*/false,
+ Name);
ParsedTemplateArgument Result(SS, TemplateTy::make(Name),
DTST.getTemplateNameLoc());
if (EllipsisLoc.isValid())
@@ -2184,10 +2189,24 @@ struct ConvertConstructorToDeductionGuideTransform {
SubstArgs.push_back(SemaRef.Context.getCanonicalTemplateArgument(
SemaRef.Context.getInjectedTemplateArg(NewParam)));
}
+
+ // Substitute new template parameters into requires-clause if present.
+ Expr *RequiresClause = nullptr;
+ if (Expr *InnerRC = InnerParams->getRequiresClause()) {
+ MultiLevelTemplateArgumentList Args;
+ Args.setKind(TemplateSubstitutionKind::Rewrite);
+ Args.addOuterTemplateArguments(SubstArgs);
+ Args.addOuterRetainedLevel();
+ ExprResult E = SemaRef.SubstExpr(InnerRC, Args);
+ if (E.isInvalid())
+ return nullptr;
+ RequiresClause = E.getAs<Expr>();
+ }
+
TemplateParams = TemplateParameterList::Create(
SemaRef.Context, InnerParams->getTemplateLoc(),
InnerParams->getLAngleLoc(), AllParams, InnerParams->getRAngleLoc(),
- /*FIXME: RequiresClause*/ nullptr);
+ RequiresClause);
}
// If we built a new template-parameter-list, track that we need to
@@ -4280,7 +4299,7 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
bool IsPartialSpecialization) {
// D must be variable template id.
assert(D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId &&
- "Variable template specialization is declared with a template it.");
+ "Variable template specialization is declared with a template id.");
TemplateIdAnnotation *TemplateId = D.getName().TemplateId;
TemplateArgumentListInfo TemplateArgs =
@@ -5237,7 +5256,7 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template,
HasDefaultArg = false;
if (TemplateTypeParmDecl *TypeParm = dyn_cast<TemplateTypeParmDecl>(Param)) {
- if (!hasVisibleDefaultArgument(TypeParm))
+ if (!hasReachableDefaultArgument(TypeParm))
return TemplateArgumentLoc();
HasDefaultArg = true;
@@ -5254,7 +5273,7 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template,
if (NonTypeTemplateParmDecl *NonTypeParm
= dyn_cast<NonTypeTemplateParmDecl>(Param)) {
- if (!hasVisibleDefaultArgument(NonTypeParm))
+ if (!hasReachableDefaultArgument(NonTypeParm))
return TemplateArgumentLoc();
HasDefaultArg = true;
@@ -5272,7 +5291,7 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template,
TemplateTemplateParmDecl *TempTempParm
= cast<TemplateTemplateParmDecl>(Param);
- if (!hasVisibleDefaultArgument(TempTempParm))
+ if (!hasReachableDefaultArgument(TempTempParm))
return TemplateArgumentLoc();
HasDefaultArg = true;
@@ -5610,10 +5629,10 @@ static bool diagnoseMissingArgument(Sema &S, SourceLocation Loc,
->getTemplateParameters()
->getParam(D->getIndex()));
- // If there's a default argument that's not visible, diagnose that we're
+ // If there's a default argument that's not reachable, diagnose that we're
// missing a module import.
llvm::SmallVector<Module*, 8> Modules;
- if (D->hasDefaultArgument() && !S.hasVisibleDefaultArgument(D, &Modules)) {
+ if (D->hasDefaultArgument() && !S.hasReachableDefaultArgument(D, &Modules)) {
S.diagnoseMissingImport(Loc, cast<NamedDecl>(TD),
D->getDefaultArgumentLoc(), Modules,
Sema::MissingImportKind::DefaultArgument,
@@ -5796,7 +5815,7 @@ bool Sema::CheckTemplateArgumentList(
// (when the template parameter was part of a nested template) into
// the default argument.
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
- if (!hasVisibleDefaultArgument(TTP))
+ if (!hasReachableDefaultArgument(TTP))
return diagnoseMissingArgument(*this, TemplateLoc, Template, TTP,
NewArgs);
@@ -5813,7 +5832,7 @@ bool Sema::CheckTemplateArgumentList(
ArgType);
} else if (NonTypeTemplateParmDecl *NTTP
= dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
- if (!hasVisibleDefaultArgument(NTTP))
+ if (!hasReachableDefaultArgument(NTTP))
return diagnoseMissingArgument(*this, TemplateLoc, Template, NTTP,
NewArgs);
@@ -5831,7 +5850,7 @@ bool Sema::CheckTemplateArgumentList(
TemplateTemplateParmDecl *TempParm
= cast<TemplateTemplateParmDecl>(*Param);
- if (!hasVisibleDefaultArgument(TempParm))
+ if (!hasReachableDefaultArgument(TempParm))
return diagnoseMissingArgument(*this, TemplateLoc, Template, TempParm,
NewArgs);
@@ -6995,7 +7014,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// -- a predefined __func__ variable
APValue::LValueBase Base = Value.getLValueBase();
auto *VD = const_cast<ValueDecl *>(Base.dyn_cast<const ValueDecl *>());
- if (Base && (!VD || isa<LifetimeExtendedTemporaryDecl>(VD))) {
+ if (Base &&
+ (!VD ||
+ isa<LifetimeExtendedTemporaryDecl, UnnamedGlobalConstantDecl>(VD))) {
Diag(Arg->getBeginLoc(), diag::err_template_arg_not_decl_ref)
<< Arg->getSourceRange();
return ExprError();
@@ -9740,7 +9761,7 @@ DeclResult Sema::ActOnExplicitInstantiation(
if (!getDLLAttr(Def) && getDLLAttr(Specialization) &&
(Context.getTargetInfo().shouldDLLImportComdatSymbols() &&
- !Context.getTargetInfo().getTriple().isPS4CPU())) {
+ !Context.getTargetInfo().getTriple().isPS())) {
// An explicit instantiation definition can add a dll attribute to a
// template with a previous instantiation declaration. MinGW doesn't
// allow this.
@@ -9758,7 +9779,7 @@ DeclResult Sema::ActOnExplicitInstantiation(
!PreviouslyDLLExported && Specialization->hasAttr<DLLExportAttr>();
if (Old_TSK == TSK_ImplicitInstantiation && NewlyDLLExported &&
(Context.getTargetInfo().shouldDLLImportComdatSymbols() &&
- !Context.getTargetInfo().getTriple().isPS4CPU())) {
+ !Context.getTargetInfo().getTriple().isPS())) {
// An explicit instantiation definition can add a dll attribute to a
// template with a previous implicit instantiation. MinGW doesn't allow
// this. We limit clang to only adding dllexport, to avoid potentially
@@ -10116,7 +10137,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
}
// Check the new variable specialization against the parsed input.
- if (PrevTemplate && Prev && !Context.hasSameType(Prev->getType(), R)) {
+ if (PrevTemplate && !Context.hasSameType(Prev->getType(), R)) {
Diag(T->getTypeLoc().getBeginLoc(),
diag::err_invalid_var_template_spec_type)
<< 0 << PrevTemplate << R << Prev->getType();
@@ -10986,10 +11007,12 @@ class ExplicitSpecializationVisibilityChecker {
Sema &S;
SourceLocation Loc;
llvm::SmallVector<Module *, 8> Modules;
+ Sema::AcceptableKind Kind;
public:
- ExplicitSpecializationVisibilityChecker(Sema &S, SourceLocation Loc)
- : S(S), Loc(Loc) {}
+ ExplicitSpecializationVisibilityChecker(Sema &S, SourceLocation Loc,
+ Sema::AcceptableKind Kind)
+ : S(S), Loc(Loc), Kind(Kind) {}
void check(NamedDecl *ND) {
if (auto *FD = dyn_cast<FunctionDecl>(ND))
@@ -11017,6 +11040,23 @@ private:
S.diagnoseMissingImport(Loc, D, D->getLocation(), Modules, Kind, Recover);
}
+ bool CheckMemberSpecialization(const NamedDecl *D) {
+ return Kind == Sema::AcceptableKind::Visible
+ ? S.hasVisibleMemberSpecialization(D)
+ : S.hasReachableMemberSpecialization(D);
+ }
+
+ bool CheckExplicitSpecialization(const NamedDecl *D) {
+ return Kind == Sema::AcceptableKind::Visible
+ ? S.hasVisibleExplicitSpecialization(D)
+ : S.hasReachableExplicitSpecialization(D);
+ }
+
+ bool CheckDeclaration(const NamedDecl *D) {
+ return Kind == Sema::AcceptableKind::Visible ? S.hasVisibleDeclaration(D)
+ : S.hasReachableDeclaration(D);
+ }
+
// Check a specific declaration. There are three problematic cases:
//
// 1) The declaration is an explicit specialization of a template
@@ -11033,10 +11073,9 @@ private:
void checkImpl(SpecDecl *Spec) {
bool IsHiddenExplicitSpecialization = false;
if (Spec->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) {
- IsHiddenExplicitSpecialization =
- Spec->getMemberSpecializationInfo()
- ? !S.hasVisibleMemberSpecialization(Spec, &Modules)
- : !S.hasVisibleExplicitSpecialization(Spec, &Modules);
+ IsHiddenExplicitSpecialization = Spec->getMemberSpecializationInfo()
+ ? !CheckMemberSpecialization(Spec)
+ : !CheckExplicitSpecialization(Spec);
} else {
checkInstantiated(Spec);
}
@@ -11060,7 +11099,7 @@ private:
checkTemplate(TD);
else if (auto *TD =
From.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) {
- if (!S.hasVisibleDeclaration(TD))
+ if (!CheckDeclaration(TD))
diagnose(TD, true);
checkTemplate(TD);
}
@@ -11076,7 +11115,7 @@ private:
checkTemplate(TD);
else if (auto *TD =
From.dyn_cast<VarTemplatePartialSpecializationDecl *>()) {
- if (!S.hasVisibleDeclaration(TD))
+ if (!CheckDeclaration(TD))
diagnose(TD, true);
checkTemplate(TD);
}
@@ -11087,7 +11126,7 @@ private:
template<typename TemplDecl>
void checkTemplate(TemplDecl *TD) {
if (TD->isMemberSpecialization()) {
- if (!S.hasVisibleMemberSpecialization(TD, &Modules))
+ if (!CheckMemberSpecialization(TD))
diagnose(TD->getMostRecentDecl(), false);
}
}
@@ -11098,5 +11137,17 @@ void Sema::checkSpecializationVisibility(SourceLocation Loc, NamedDecl *Spec) {
if (!getLangOpts().Modules)
return;
- ExplicitSpecializationVisibilityChecker(*this, Loc).check(Spec);
+ ExplicitSpecializationVisibilityChecker(*this, Loc,
+ Sema::AcceptableKind::Visible)
+ .check(Spec);
+}
+
+void Sema::checkSpecializationReachability(SourceLocation Loc,
+ NamedDecl *Spec) {
+ if (!getLangOpts().CPlusPlusModules)
+ return checkSpecializationVisibility(Loc, Spec);
+
+ ExplicitSpecializationVisibilityChecker(*this, Loc,
+ Sema::AcceptableKind::Reachable)
+ .check(Spec);
}
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 22dd395d9943..9ec33e898198 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -533,9 +533,9 @@ DeduceTemplateArguments(Sema &S,
///
/// \param TemplateParams the template parameters that we are deducing
///
-/// \param Param the parameter type
+/// \param P the parameter type
///
-/// \param Arg the argument type
+/// \param A the argument type
///
/// \param Info information about the template argument deduction itself
///
@@ -828,7 +828,7 @@ public:
/// Determine whether this pack expansion scope has a known, fixed arity.
/// This happens if it involves a pack from an outer template that has
/// (notionally) already been expanded.
- bool hasFixedArity() { return FixedNumExpansions.hasValue(); }
+ bool hasFixedArity() { return FixedNumExpansions.has_value(); }
/// Determine whether the next element of the argument is still part of this
/// pack. This is the case unless the pack is already expanded to a fixed
@@ -1199,11 +1199,11 @@ static CXXRecordDecl *getCanonicalRD(QualType T) {
///
/// \param S the semantic analysis object within which we are deducing.
///
-/// \param RecordT the top level record object we are deducing against.
+/// \param RD the top level record object we are deducing against.
///
/// \param TemplateParams the template parameters that we are deducing.
///
-/// \param SpecParam the template specialization parameter type.
+/// \param P the template specialization parameter type.
///
/// \param Info information about the template argument deduction itself.
///
@@ -1315,9 +1315,9 @@ DeduceTemplateBases(Sema &S, const CXXRecordDecl *RD,
///
/// \param TemplateParams the template parameters that we are deducing
///
-/// \param ParamIn the parameter type
+/// \param P the parameter type
///
-/// \param ArgIn the argument type
+/// \param A the argument type
///
/// \param Info information about the template argument deduction itself
///
@@ -3406,7 +3406,7 @@ static unsigned getPackIndexForParam(Sema &S,
for (auto *PD : FunctionTemplate->getTemplatedDecl()->parameters()) {
if (PD->isParameterPack()) {
unsigned NumExpansions =
- S.getNumArgumentsInExpansion(PD->getType(), Args).getValueOr(1);
+ S.getNumArgumentsInExpansion(PD->getType(), Args).value_or(1);
if (Idx + NumExpansions > ParamIdx)
return ParamIdx - Idx;
Idx += NumExpansions;
@@ -4637,7 +4637,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
}
// Find the depth of template parameter to synthesize.
- unsigned Depth = DependentDeductionDepth.getValueOr(0);
+ unsigned Depth = DependentDeductionDepth.value_or(0);
// If this is a 'decltype(auto)' specifier, do the decltype dance.
// Since 'decltype(auto)' can only occur at the top of the type, we
@@ -4769,12 +4769,13 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
return DAR_FailedAlreadyDiagnosed;
}
- if (const auto *AT = Type.getType()->getAs<AutoType>()) {
+ QualType MaybeAuto = Type.getType().getNonReferenceType();
+ while (MaybeAuto->isPointerType())
+ MaybeAuto = MaybeAuto->getPointeeType();
+ if (const auto *AT = MaybeAuto->getAs<AutoType>()) {
if (AT->isConstrained() && !IgnoreConstraints) {
- auto ConstraintsResult =
- CheckDeducedPlaceholderConstraints(*this, *AT,
- Type.getContainedAutoTypeLoc(),
- DeducedType);
+ auto ConstraintsResult = CheckDeducedPlaceholderConstraints(
+ *this, *AT, Type.getContainedAutoTypeLoc(), DeducedType);
if (ConstraintsResult != DAR_Succeeded)
return ConstraintsResult;
}
@@ -5142,18 +5143,20 @@ static bool isVariadicFunctionTemplate(FunctionTemplateDecl *FunTmpl) {
/// candidate with a reversed parameter order. In this case, the corresponding
/// P/A pairs between FT1 and FT2 are reversed.
///
+/// \param AllowOrderingByConstraints If \c is false, don't check whether one
+/// of the templates is more constrained than the other. Default is true.
+///
/// \returns the more specialized function template. If neither
/// template is more specialized, returns NULL.
-FunctionTemplateDecl *
-Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
- FunctionTemplateDecl *FT2,
- SourceLocation Loc,
- TemplatePartialOrderingContext TPOC,
- unsigned NumCallArguments1,
- unsigned NumCallArguments2,
- bool Reversed) {
-
- auto JudgeByConstraints = [&] () -> FunctionTemplateDecl * {
+FunctionTemplateDecl *Sema::getMoreSpecializedTemplate(
+ FunctionTemplateDecl *FT1, FunctionTemplateDecl *FT2, SourceLocation Loc,
+ TemplatePartialOrderingContext TPOC, unsigned NumCallArguments1,
+ unsigned NumCallArguments2, bool Reversed,
+ bool AllowOrderingByConstraints) {
+
+ auto JudgeByConstraints = [&]() -> FunctionTemplateDecl * {
+ if (!AllowOrderingByConstraints)
+ return nullptr;
llvm::SmallVector<const Expr *, 3> AC1, AC2;
FT1->getAssociatedConstraints(AC1);
FT2->getAssociatedConstraints(AC2);
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 6de486be8f16..f09b3473c074 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -10,12 +10,14 @@
//===----------------------------------------------------------------------===/
#include "TreeTransform.h"
+#include "clang/AST/ASTConcept.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTLambda.h"
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/ExprConcepts.h"
#include "clang/AST/PrettyDeclStackTrace.h"
#include "clang/AST/TypeVisitor.h"
#include "clang/Basic/LangOptions.h"
@@ -55,26 +57,23 @@ using namespace sema;
/// instantiating the definition of the given declaration, \p D. This is
/// used to determine the proper set of template instantiation arguments for
/// friend function template specializations.
-MultiLevelTemplateArgumentList
-Sema::getTemplateInstantiationArgs(NamedDecl *D,
- const TemplateArgumentList *Innermost,
- bool RelativeToPrimary,
- const FunctionDecl *Pattern) {
+MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
+ const NamedDecl *D, const TemplateArgumentList *Innermost,
+ bool RelativeToPrimary, const FunctionDecl *Pattern) {
// Accumulate the set of template argument lists in this structure.
MultiLevelTemplateArgumentList Result;
if (Innermost)
Result.addOuterTemplateArguments(Innermost);
- DeclContext *Ctx = dyn_cast<DeclContext>(D);
+ const auto *Ctx = dyn_cast<DeclContext>(D);
if (!Ctx) {
Ctx = D->getDeclContext();
// Add template arguments from a variable template instantiation. For a
// class-scope explicit specialization, there are no template arguments
// at this level, but there may be enclosing template arguments.
- VarTemplateSpecializationDecl *Spec =
- dyn_cast<VarTemplateSpecializationDecl>(D);
+ const auto *Spec = dyn_cast<VarTemplateSpecializationDecl>(D);
if (Spec && !Spec->isClassScopeExplicitSpecialization()) {
// We're done when we hit an explicit specialization.
if (Spec->getSpecializationKind() == TSK_ExplicitSpecialization &&
@@ -107,8 +106,7 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D,
// use empty template parameter lists for all of the outer templates
// to avoid performing any substitutions.
if (Ctx->isTranslationUnit()) {
- if (TemplateTemplateParmDecl *TTP
- = dyn_cast<TemplateTemplateParmDecl>(D)) {
+ if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(D)) {
for (unsigned I = 0, N = TTP->getDepth() + 1; I != N; ++I)
Result.addOuterTemplateArguments(None);
return Result;
@@ -118,8 +116,7 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D,
while (!Ctx->isFileContext()) {
// Add template arguments from a class template instantiation.
- ClassTemplateSpecializationDecl *Spec
- = dyn_cast<ClassTemplateSpecializationDecl>(Ctx);
+ const auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(Ctx);
if (Spec && !Spec->isClassScopeExplicitSpecialization()) {
// We're done when we hit an explicit specialization.
if (Spec->getSpecializationKind() == TSK_ExplicitSpecialization &&
@@ -135,7 +132,7 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D,
break;
}
// Add template arguments from a function template specialization.
- else if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Ctx)) {
+ else if (const auto *Function = dyn_cast<FunctionDecl>(Ctx)) {
if (!RelativeToPrimary &&
Function->getTemplateSpecializationKindForInstantiation() ==
TSK_ExplicitSpecialization)
@@ -177,7 +174,7 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D,
RelativeToPrimary = false;
continue;
}
- } else if (CXXRecordDecl *Rec = dyn_cast<CXXRecordDecl>(Ctx)) {
+ } else if (const auto *Rec = dyn_cast<CXXRecordDecl>(Ctx)) {
if (ClassTemplateDecl *ClassTemplate = Rec->getDescribedClassTemplate()) {
assert(Result.getNumSubstitutedLevels() == 0 &&
"Outer template not instantiated?");
@@ -218,6 +215,7 @@ bool Sema::CodeSynthesisContext::isInstantiationRecord() const {
case RewritingOperatorAsSpaceship:
case InitializingStructuredBinding:
case MarkingClassDllexported:
+ case BuildingBuiltinDumpStructCall:
return false;
// This function should never be called when Kind's value is Memoization.
@@ -487,6 +485,19 @@ void Sema::InstantiatingTemplate::Clear() {
}
}
+static std::string convertCallArgsToString(Sema &S,
+ llvm::ArrayRef<const Expr *> Args) {
+ std::string Result;
+ llvm::raw_string_ostream OS(Result);
+ llvm::ListSeparator Comma;
+ for (const Expr *Arg : Args) {
+ OS << Comma;
+ Arg->IgnoreParens()->printPretty(OS, nullptr,
+ S.Context.getPrintingPolicy());
+ }
+ return Result;
+}
+
bool Sema::InstantiatingTemplate::CheckInstantiationDepth(
SourceLocation PointOfInstantiation,
SourceRange InstantiationRange) {
@@ -775,6 +786,14 @@ void Sema::PrintInstantiationStack() {
<< cast<CXXRecordDecl>(Active->Entity) << !getLangOpts().CPlusPlus11;
break;
+ case CodeSynthesisContext::BuildingBuiltinDumpStructCall:
+ Diags.Report(Active->PointOfInstantiation,
+ diag::note_building_builtin_dump_struct_call)
+ << convertCallArgsToString(
+ *this,
+ llvm::makeArrayRef(Active->CallArgs, Active->NumCallArgs));
+ break;
+
case CodeSynthesisContext::Memoization:
break;
@@ -879,6 +898,7 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
case CodeSynthesisContext::DefiningSynthesizedFunction:
case CodeSynthesisContext::InitializingStructuredBinding:
case CodeSynthesisContext::MarkingClassDllexported:
+ case CodeSynthesisContext::BuildingBuiltinDumpStructCall:
// This happens in a context unrelated to template instantiation, so
// there is no SFINAE.
return None;
@@ -1126,12 +1146,12 @@ namespace {
ExprResult TransformLambdaExpr(LambdaExpr *E) {
LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
- return TreeTransform<TemplateInstantiator>::TransformLambdaExpr(E);
+ return inherited::TransformLambdaExpr(E);
}
ExprResult TransformRequiresExpr(RequiresExpr *E) {
LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
- return TreeTransform<TemplateInstantiator>::TransformRequiresExpr(E);
+ return inherited::TransformRequiresExpr(E);
}
bool TransformRequiresExprRequirements(
@@ -1341,10 +1361,7 @@ TemplateInstantiator::RebuildElaboratedType(SourceLocation KeywordLoc,
}
}
- return TreeTransform<TemplateInstantiator>::RebuildElaboratedType(KeywordLoc,
- Keyword,
- QualifierLoc,
- T);
+ return inherited::RebuildElaboratedType(KeywordLoc, Keyword, QualifierLoc, T);
}
TemplateName TemplateInstantiator::TransformTemplateName(
@@ -1719,7 +1736,7 @@ TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E) {
if (PD->isParameterPack())
return TransformFunctionParmPackRefExpr(E, PD);
- return TreeTransform<TemplateInstantiator>::TransformDeclRefExpr(E);
+ return inherited::TransformDeclRefExpr(E);
}
ExprResult TemplateInstantiator::TransformCXXDefaultArgExpr(
@@ -1981,8 +1998,7 @@ TemplateInstantiator::TransformExprRequirement(concepts::ExprRequirement *Req) {
TransRetReq.emplace(TPL);
}
}
- assert(TransRetReq.hasValue() &&
- "All code paths leading here must set TransRetReq");
+ assert(TransRetReq && "All code paths leading here must set TransRetReq");
if (Expr *E = TransExpr.dyn_cast<Expr *>())
return RebuildExprRequirement(E, Req->isSimple(), Req->getNoexceptLoc(),
std::move(*TransRetReq));
@@ -2008,6 +2024,7 @@ TemplateInstantiator::TransformNestedRequirement(
Req->getConstraintExpr()->getSourceRange());
ExprResult TransConstraint;
+ ConstraintSatisfaction Satisfaction;
TemplateDeductionInfo Info(Req->getConstraintExpr()->getBeginLoc());
{
EnterExpressionEvaluationContext ContextRAII(
@@ -2019,6 +2036,25 @@ TemplateInstantiator::TransformNestedRequirement(
if (ConstrInst.isInvalid())
return nullptr;
TransConstraint = TransformExpr(Req->getConstraintExpr());
+ if (!TransConstraint.isInvalid()) {
+ bool CheckSucceeded =
+ SemaRef.CheckConstraintExpression(TransConstraint.get());
+ (void)CheckSucceeded;
+ assert((CheckSucceeded || Trap.hasErrorOccurred()) &&
+ "CheckConstraintExpression failed, but "
+ "did not produce a SFINAE error");
+ }
+ // Use version of CheckConstraintSatisfaction that does no substitutions.
+ if (!TransConstraint.isInvalid() &&
+ !TransConstraint.get()->isInstantiationDependent() &&
+ !Trap.hasErrorOccurred()) {
+ bool CheckFailed = SemaRef.CheckConstraintSatisfaction(
+ TransConstraint.get(), Satisfaction);
+ (void)CheckFailed;
+ assert((!CheckFailed || Trap.hasErrorOccurred()) &&
+ "CheckConstraintSatisfaction failed, "
+ "but did not produce a SFINAE error");
+ }
if (TransConstraint.isInvalid() || Trap.hasErrorOccurred())
return RebuildNestedRequirement(createSubstDiag(SemaRef, Info,
[&] (llvm::raw_ostream& OS) {
@@ -2026,7 +2062,11 @@ TemplateInstantiator::TransformNestedRequirement(
SemaRef.getPrintingPolicy());
}));
}
- return RebuildNestedRequirement(TransConstraint.get());
+ if (TransConstraint.get()->isInstantiationDependent())
+ return new (SemaRef.Context)
+ concepts::NestedRequirement(TransConstraint.get());
+ return new (SemaRef.Context) concepts::NestedRequirement(
+ SemaRef.Context, TransConstraint.get(), Satisfaction);
}
@@ -3235,6 +3275,17 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
if (FunctionDecl *Pattern =
Function->getInstantiatedFromMemberFunction()) {
+ if (Function->isIneligibleOrNotSelected())
+ continue;
+
+ if (Function->getTrailingRequiresClause()) {
+ ConstraintSatisfaction Satisfaction;
+ if (CheckFunctionConstraints(Function, Satisfaction) ||
+ !Satisfaction.IsSatisfied) {
+ continue;
+ }
+ }
+
if (Function->hasAttr<ExcludeFromExplicitInstantiationAttr>())
continue;
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 1da0dfec3f23..d7558017948a 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -188,15 +188,37 @@ static void instantiateDependentAnnotationAttr(
const AnnotateAttr *Attr, Decl *New) {
EnterExpressionEvaluationContext Unevaluated(
S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+
+ // If the attribute has delayed arguments it will have to instantiate those
+ // and handle them as new arguments for the attribute.
+ bool HasDelayedArgs = Attr->delayedArgs_size();
+
+ ArrayRef<Expr *> ArgsToInstantiate =
+ HasDelayedArgs
+ ? ArrayRef<Expr *>{Attr->delayedArgs_begin(), Attr->delayedArgs_end()}
+ : ArrayRef<Expr *>{Attr->args_begin(), Attr->args_end()};
+
SmallVector<Expr *, 4> Args;
- Args.reserve(Attr->args_size());
- for (auto *E : Attr->args()) {
- ExprResult Result = S.SubstExpr(E, TemplateArgs);
- if (!Result.isUsable())
+ if (S.SubstExprs(ArgsToInstantiate,
+ /*IsCall=*/false, TemplateArgs, Args))
+ return;
+
+ StringRef Str = Attr->getAnnotation();
+ if (HasDelayedArgs) {
+ if (Args.size() < 1) {
+ S.Diag(Attr->getLoc(), diag::err_attribute_too_few_arguments)
+ << Attr << 1;
+ return;
+ }
+
+ if (!S.checkStringLiteralArgumentAttr(*Attr, Args[0], Str))
return;
- Args.push_back(Result.get());
+
+ llvm::SmallVector<Expr *, 4> ActualArgs;
+ ActualArgs.insert(ActualArgs.begin(), Args.begin() + 1, Args.end());
+ std::swap(Args, ActualArgs);
}
- S.AddAnnotationAttr(New, *Attr, Attr->getAnnotation(), Args);
+ S.AddAnnotationAttr(New, *Attr, Str, Args);
}
static Expr *instantiateDependentFunctionAttrCondition(
@@ -498,8 +520,7 @@ static void instantiateOMPDeclareVariantAttr(
continue;
NeedDevicePtrExprs.push_back(ER.get());
}
- for (auto A : Attr.appendArgs())
- AppendArgs.push_back(A);
+ llvm::append_range(AppendArgs, Attr.appendArgs());
S.ActOnOpenMPDeclareVariantDirective(
FD, E, TI, NothingExprs, NeedDevicePtrExprs, AppendArgs, SourceLocation(),
@@ -600,6 +621,31 @@ static bool isRelevantAttr(Sema &S, const Decl *D, const Attr *A) {
return true;
}
+ if (const auto *BA = dyn_cast<BuiltinAttr>(A)) {
+ const FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
+ switch (BA->getID()) {
+ case Builtin::BIforward:
+ // Do not treat 'std::forward' as a builtin if it takes an rvalue reference
+ // type and returns an lvalue reference type. The library implementation
+ // will produce an error in this case; don't get in its way.
+ if (FD && FD->getNumParams() >= 1 &&
+ FD->getParamDecl(0)->getType()->isRValueReferenceType() &&
+ FD->getReturnType()->isLValueReferenceType()) {
+ return false;
+ }
+ LLVM_FALLTHROUGH;
+ case Builtin::BImove:
+ case Builtin::BImove_if_noexcept:
+ // HACK: Super-old versions of libc++ (3.1 and earlier) provide
+ // std::forward and std::move overloads that sometimes return by value
+ // instead of by reference when building in C++98 mode. Don't treat such
+ // cases as builtins.
+ if (FD && !FD->getReturnType()->isReferenceType())
+ return false;
+ break;
+ }
+ }
+
return true;
}
@@ -800,7 +846,7 @@ void Sema::InstantiateDefaultCtorDefaultArgs(CXXConstructorDecl *Ctor) {
for (unsigned I = 0; I != NumParams; ++I) {
(void)CheckCXXDefaultArgExpr(Attr->getLocation(), Ctor,
Ctor->getParamDecl(I));
- DiscardCleanupsInEvaluationContext();
+ CleanupVarDeclMarking();
}
}
@@ -846,6 +892,11 @@ Decl *TemplateDeclInstantiator::VisitMSGuidDecl(MSGuidDecl *D) {
llvm_unreachable("GUID declaration cannot be instantiated");
}
+Decl *TemplateDeclInstantiator::VisitUnnamedGlobalConstantDecl(
+ UnnamedGlobalConstantDecl *D) {
+ llvm_unreachable("UnnamedGlobalConstantDecl cannot be instantiated");
+}
+
Decl *TemplateDeclInstantiator::VisitTemplateParamObjectDecl(
TemplateParamObjectDecl *D) {
llvm_unreachable("template parameter objects cannot be instantiated");
@@ -953,6 +1004,7 @@ Decl *TemplateDeclInstantiator::InstantiateTypedefNameDecl(TypedefNameDecl *D,
SemaRef.inferGslPointerAttribute(Typedef);
Typedef->setAccess(D->getAccess());
+ Typedef->setReferenced(D->isReferenced());
return Typedef;
}
@@ -1831,7 +1883,7 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
if (D->isLambda())
Record = CXXRecordDecl::CreateLambda(
SemaRef.Context, Owner, D->getLambdaTypeInfo(), D->getLocation(),
- D->isDependentLambda(), D->isGenericLambda(),
+ D->getLambdaDependencyKind(), D->isGenericLambda(),
D->getLambdaCaptureDefault());
else
Record = CXXRecordDecl::Create(SemaRef.Context, D->getTagKind(), Owner,
@@ -2217,7 +2269,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
}
SemaRef.CheckFunctionDeclaration(/*Scope*/ nullptr, Function, Previous,
- IsExplicitSpecialization);
+ IsExplicitSpecialization,
+ Function->isThisDeclarationADefinition());
// Check the template parameter list against the previous declaration. The
// goal here is to pick up default arguments added since the friend was
@@ -2425,6 +2478,7 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo,
Destructor->UsesFPIntrin(), Destructor->isInlineSpecified(), false,
Destructor->getConstexprKind(), TrailingRequiresClause);
+ Method->setIneligibleOrNotSelected(true);
Method->setRangeEnd(Destructor->getEndLoc());
Method->setDeclName(SemaRef.Context.DeclarationNames.getCXXDestructorName(
SemaRef.Context.getCanonicalType(
@@ -2542,7 +2596,7 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
IsExplicitSpecialization = true;
} else if (const ASTTemplateArgumentListInfo *Info =
- ClassScopeSpecializationArgs.getValueOr(
+ ClassScopeSpecializationArgs.value_or(
D->getTemplateSpecializationArgsAsWritten())) {
SemaRef.LookupQualifiedName(Previous, DC);
@@ -2578,7 +2632,8 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
}
SemaRef.CheckFunctionDeclaration(nullptr, Method, Previous,
- IsExplicitSpecialization);
+ IsExplicitSpecialization,
+ Method->isThisDeclarationADefinition());
if (D->isPure())
SemaRef.CheckPureMethod(Method, SourceRange());
@@ -3747,13 +3802,15 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
return nullptr;
// Substitute the current template arguments.
- const TemplateArgumentListInfo &TemplateArgsInfo = D->getTemplateArgsInfo();
- VarTemplateArgsInfo.setLAngleLoc(TemplateArgsInfo.getLAngleLoc());
- VarTemplateArgsInfo.setRAngleLoc(TemplateArgsInfo.getRAngleLoc());
+ if (const ASTTemplateArgumentListInfo *TemplateArgsInfo =
+ D->getTemplateArgsInfo()) {
+ VarTemplateArgsInfo.setLAngleLoc(TemplateArgsInfo->getLAngleLoc());
+ VarTemplateArgsInfo.setRAngleLoc(TemplateArgsInfo->getRAngleLoc());
- if (SemaRef.SubstTemplateArguments(TemplateArgsInfo.arguments(), TemplateArgs,
- VarTemplateArgsInfo))
- return nullptr;
+ if (SemaRef.SubstTemplateArguments(TemplateArgsInfo->arguments(),
+ TemplateArgs, VarTemplateArgsInfo))
+ return nullptr;
+ }
// Check that the template argument list is well-formed for this template.
SmallVector<TemplateArgument, 4> Converted;
@@ -4355,10 +4412,10 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
/// Introduce the instantiated function parameters into the local
/// instantiation scope, and set the parameter names to those used
/// in the template.
-static bool addInstantiatedParametersToScope(Sema &S, FunctionDecl *Function,
- const FunctionDecl *PatternDecl,
- LocalInstantiationScope &Scope,
- const MultiLevelTemplateArgumentList &TemplateArgs) {
+bool Sema::addInstantiatedParametersToScope(
+ FunctionDecl *Function, const FunctionDecl *PatternDecl,
+ LocalInstantiationScope &Scope,
+ const MultiLevelTemplateArgumentList &TemplateArgs) {
unsigned FParamIdx = 0;
for (unsigned I = 0, N = PatternDecl->getNumParams(); I != N; ++I) {
const ParmVarDecl *PatternParam = PatternDecl->getParamDecl(I);
@@ -4374,9 +4431,9 @@ static bool addInstantiatedParametersToScope(Sema &S, FunctionDecl *Function,
// it's instantiation-dependent.
// FIXME: Updating the type to work around this is at best fragile.
if (!PatternDecl->getType()->isDependentType()) {
- QualType T = S.SubstType(PatternParam->getType(), TemplateArgs,
- FunctionParam->getLocation(),
- FunctionParam->getDeclName());
+ QualType T = SubstType(PatternParam->getType(), TemplateArgs,
+ FunctionParam->getLocation(),
+ FunctionParam->getDeclName());
if (T.isNull())
return true;
FunctionParam->setType(T);
@@ -4389,8 +4446,8 @@ static bool addInstantiatedParametersToScope(Sema &S, FunctionDecl *Function,
// Expand the parameter pack.
Scope.MakeInstantiatedLocalArgPack(PatternParam);
- Optional<unsigned> NumArgumentsInExpansion
- = S.getNumArgumentsInExpansion(PatternParam->getType(), TemplateArgs);
+ Optional<unsigned> NumArgumentsInExpansion =
+ getNumArgumentsInExpansion(PatternParam->getType(), TemplateArgs);
if (NumArgumentsInExpansion) {
QualType PatternType =
PatternParam->getType()->castAs<PackExpansionType>()->getPattern();
@@ -4398,10 +4455,10 @@ static bool addInstantiatedParametersToScope(Sema &S, FunctionDecl *Function,
ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx);
FunctionParam->setDeclName(PatternParam->getDeclName());
if (!PatternDecl->getType()->isDependentType()) {
- Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(S, Arg);
- QualType T = S.SubstType(PatternType, TemplateArgs,
- FunctionParam->getLocation(),
- FunctionParam->getDeclName());
+ Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(*this, Arg);
+ QualType T =
+ SubstType(PatternType, TemplateArgs, FunctionParam->getLocation(),
+ FunctionParam->getDeclName());
if (T.isNull())
return true;
FunctionParam->setType(T);
@@ -4465,8 +4522,7 @@ bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD,
FunctionDecl *Pattern = FD->getTemplateInstantiationPattern(
/*ForDefinition*/ false);
- if (addInstantiatedParametersToScope(*this, FD, Pattern, Local,
- TemplateArgs))
+ if (addInstantiatedParametersToScope(FD, Pattern, Local, TemplateArgs))
return true;
runWithSufficientStackSpace(CallLoc, [&] {
@@ -4539,8 +4595,7 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
// we don't store enough information to map back to the friend declaration in
// the template.
FunctionDecl *Template = Proto->getExceptionSpecTemplate();
- if (addInstantiatedParametersToScope(*this, Decl, Template, Scope,
- TemplateArgs)) {
+ if (addInstantiatedParametersToScope(Decl, Template, Scope, TemplateArgs)) {
UpdateExceptionSpec(Decl, EST_None);
return;
}
@@ -4549,53 +4604,6 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
TemplateArgs);
}
-bool Sema::CheckInstantiatedFunctionTemplateConstraints(
- SourceLocation PointOfInstantiation, FunctionDecl *Decl,
- ArrayRef<TemplateArgument> TemplateArgs,
- ConstraintSatisfaction &Satisfaction) {
- // In most cases we're not going to have constraints, so check for that first.
- FunctionTemplateDecl *Template = Decl->getPrimaryTemplate();
- // Note - code synthesis context for the constraints check is created
- // inside CheckConstraintsSatisfaction.
- SmallVector<const Expr *, 3> TemplateAC;
- Template->getAssociatedConstraints(TemplateAC);
- if (TemplateAC.empty()) {
- Satisfaction.IsSatisfied = true;
- return false;
- }
-
- // Enter the scope of this instantiation. We don't use
- // PushDeclContext because we don't have a scope.
- Sema::ContextRAII savedContext(*this, Decl);
- LocalInstantiationScope Scope(*this);
-
- // If this is not an explicit specialization - we need to get the instantiated
- // version of the template arguments and add them to scope for the
- // substitution.
- if (Decl->isTemplateInstantiation()) {
- InstantiatingTemplate Inst(*this, Decl->getPointOfInstantiation(),
- InstantiatingTemplate::ConstraintsCheck{}, Decl->getPrimaryTemplate(),
- TemplateArgs, SourceRange());
- if (Inst.isInvalid())
- return true;
- MultiLevelTemplateArgumentList MLTAL(
- *Decl->getTemplateSpecializationArgs());
- if (addInstantiatedParametersToScope(
- *this, Decl, Decl->getPrimaryTemplate()->getTemplatedDecl(),
- Scope, MLTAL))
- return true;
- }
- Qualifiers ThisQuals;
- CXXRecordDecl *Record = nullptr;
- if (auto *Method = dyn_cast<CXXMethodDecl>(Decl)) {
- ThisQuals = Method->getMethodQualifiers();
- Record = Method->getParent();
- }
- CXXThisScopeRAII ThisScope(*this, Record, ThisQuals, Record != nullptr);
- return CheckConstraintSatisfaction(Template, TemplateAC, TemplateArgs,
- PointOfInstantiation, Satisfaction);
-}
-
/// Initializes the common fields of an instantiation function
/// declaration (New) from the corresponding fields of its template (Tmpl).
///
@@ -4791,6 +4799,12 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
if (TSK == TSK_ExplicitSpecialization)
return;
+ // Never implicitly instantiate a builtin; we don't actually need a function
+ // body.
+ if (Function->getBuiltinID() && TSK == TSK_ImplicitInstantiation &&
+ !DefinitionRequired)
+ return;
+
// Don't instantiate a definition if we already have one.
const FunctionDecl *ExistingDefn = nullptr;
if (Function->isDefined(ExistingDefn,
@@ -5028,7 +5042,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
// PushDeclContext because we don't have a scope.
Sema::ContextRAII savedContext(*this, Function);
- if (addInstantiatedParametersToScope(*this, Function, PatternDecl, Scope,
+ if (addInstantiatedParametersToScope(Function, PatternDecl, Scope,
TemplateArgs))
return;
@@ -5543,8 +5557,18 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
// declaration of the definition.
TemplateDeclInstantiator Instantiator(*this, Var->getDeclContext(),
TemplateArgs);
+
+ TemplateArgumentListInfo TemplateArgInfo;
+ if (const ASTTemplateArgumentListInfo *ArgInfo =
+ VarSpec->getTemplateArgsInfo()) {
+ TemplateArgInfo.setLAngleLoc(ArgInfo->getLAngleLoc());
+ TemplateArgInfo.setRAngleLoc(ArgInfo->getRAngleLoc());
+ for (const TemplateArgumentLoc &Arg : ArgInfo->arguments())
+ TemplateArgInfo.addArgument(Arg);
+ }
+
Var = cast_or_null<VarDecl>(Instantiator.VisitVarTemplateSpecializationDecl(
- VarSpec->getSpecializedTemplate(), Def, VarSpec->getTemplateArgsInfo(),
+ VarSpec->getSpecializedTemplate(), Def, TemplateArgInfo,
VarSpec->getTemplateArgs().asArray(), VarSpec));
if (Var) {
llvm::PointerUnion<VarTemplateDecl *,
@@ -6012,7 +6036,9 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
(ParentDependsOnArgs && (ParentDC->isFunctionOrMethod() ||
isa<OMPDeclareReductionDecl>(ParentDC) ||
isa<OMPDeclareMapperDecl>(ParentDC))) ||
- (isa<CXXRecordDecl>(D) && cast<CXXRecordDecl>(D)->isLambda())) {
+ (isa<CXXRecordDecl>(D) && cast<CXXRecordDecl>(D)->isLambda() &&
+ cast<CXXRecordDecl>(D)->getTemplateDepth() >
+ TemplateArgs.getNumRetainedOuterLevels())) {
// D is a local of some kind. Look into the map of local
// declarations to their instantiations.
if (CurrentInstantiationScope) {
diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp
index 51c79e93ab0a..790792f77b24 100644
--- a/clang/lib/Sema/SemaTemplateVariadic.cpp
+++ b/clang/lib/Sema/SemaTemplateVariadic.cpp
@@ -677,21 +677,19 @@ bool Sema::CheckParameterPacksForExpansion(
Optional<unsigned> NumPartialExpansions;
SourceLocation PartiallySubstitutedPackLoc;
- for (ArrayRef<UnexpandedParameterPack>::iterator i = Unexpanded.begin(),
- end = Unexpanded.end();
- i != end; ++i) {
+ for (UnexpandedParameterPack ParmPack : Unexpanded) {
// Compute the depth and index for this parameter pack.
unsigned Depth = 0, Index = 0;
IdentifierInfo *Name;
bool IsVarDeclPack = false;
- if (const TemplateTypeParmType *TTP
- = i->first.dyn_cast<const TemplateTypeParmType *>()) {
+ if (const TemplateTypeParmType *TTP =
+ ParmPack.first.dyn_cast<const TemplateTypeParmType *>()) {
Depth = TTP->getDepth();
Index = TTP->getIndex();
Name = TTP->getIdentifier();
} else {
- NamedDecl *ND = i->first.get<NamedDecl *>();
+ NamedDecl *ND = ParmPack.first.get<NamedDecl *>();
if (isa<VarDecl>(ND))
IsVarDeclPack = true;
else
@@ -706,9 +704,9 @@ bool Sema::CheckParameterPacksForExpansion(
// Figure out whether we're instantiating to an argument pack or not.
typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack;
- llvm::PointerUnion<Decl *, DeclArgumentPack *> *Instantiation
- = CurrentInstantiationScope->findInstantiationOf(
- i->first.get<NamedDecl *>());
+ llvm::PointerUnion<Decl *, DeclArgumentPack *> *Instantiation =
+ CurrentInstantiationScope->findInstantiationOf(
+ ParmPack.first.get<NamedDecl *>());
if (Instantiation->is<DeclArgumentPack *>()) {
// We could expand this function parameter pack.
NewPackSize = Instantiation->get<DeclArgumentPack *>()->size();
@@ -745,7 +743,7 @@ bool Sema::CheckParameterPacksForExpansion(
RetainExpansion = true;
// We don't actually know the new pack size yet.
NumPartialExpansions = NewPackSize;
- PartiallySubstitutedPackLoc = i->second;
+ PartiallySubstitutedPackLoc = ParmPack.second;
continue;
}
}
@@ -756,7 +754,7 @@ bool Sema::CheckParameterPacksForExpansion(
// Record it.
NumExpansions = NewPackSize;
FirstPack.first = Name;
- FirstPack.second = i->second;
+ FirstPack.second = ParmPack.second;
HaveFirstPack = true;
continue;
}
@@ -767,12 +765,12 @@ bool Sema::CheckParameterPacksForExpansion(
// the same number of arguments specified.
if (HaveFirstPack)
Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict)
- << FirstPack.first << Name << *NumExpansions << NewPackSize
- << SourceRange(FirstPack.second) << SourceRange(i->second);
+ << FirstPack.first << Name << *NumExpansions << NewPackSize
+ << SourceRange(FirstPack.second) << SourceRange(ParmPack.second);
else
Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict_multilevel)
- << Name << *NumExpansions << NewPackSize
- << SourceRange(i->second);
+ << Name << *NumExpansions << NewPackSize
+ << SourceRange(ParmPack.second);
return true;
}
}
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index ab47e9f03eaf..3edce941c381 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -121,6 +121,8 @@ static void diagnoseBadTypeAttribute(Sema &S, const ParsedAttr &attr,
case ParsedAttr::AT_SwiftAsyncCall: \
case ParsedAttr::AT_VectorCall: \
case ParsedAttr::AT_AArch64VectorPcs: \
+ case ParsedAttr::AT_AArch64SVEPcs: \
+ case ParsedAttr::AT_AMDGPUKernelCall: \
case ParsedAttr::AT_MSABI: \
case ParsedAttr::AT_SysVABI: \
case ParsedAttr::AT_Pcs: \
@@ -166,12 +168,6 @@ namespace {
/// DeclSpec.
unsigned chunkIndex;
- /// Whether there are non-trivial modifications to the decl spec.
- bool trivial;
-
- /// Whether we saved the attributes in the decl spec.
- bool hasSavedAttrs;
-
/// The original set of attributes on the DeclSpec.
SmallVector<ParsedAttr *, 2> savedAttrs;
@@ -200,8 +196,7 @@ namespace {
public:
TypeProcessingState(Sema &sema, Declarator &declarator)
: sema(sema), declarator(declarator),
- chunkIndex(declarator.getNumTypeObjects()), trivial(true),
- hasSavedAttrs(false), parsedNoDeref(false) {}
+ chunkIndex(declarator.getNumTypeObjects()), parsedNoDeref(false) {}
Sema &getSema() const {
return sema;
@@ -233,13 +228,12 @@ namespace {
/// Save the current set of attributes on the DeclSpec.
void saveDeclSpecAttrs() {
// Don't try to save them multiple times.
- if (hasSavedAttrs) return;
+ if (!savedAttrs.empty())
+ return;
DeclSpec &spec = getMutableDeclSpec();
- for (ParsedAttr &AL : spec.getAttributes())
- savedAttrs.push_back(&AL);
- trivial &= savedAttrs.empty();
- hasSavedAttrs = true;
+ llvm::append_range(savedAttrs,
+ llvm::make_pointer_range(spec.getAttributes()));
}
/// Record that we had nowhere to put the given type attribute.
@@ -266,6 +260,12 @@ namespace {
return T;
}
+ /// Get a BTFTagAttributed type for the btf_type_tag attribute.
+ QualType getBTFTagAttributedType(const BTFTypeTagAttr *BTFAttr,
+ QualType WrappedType) {
+ return sema.Context.getBTFTagAttributedType(BTFAttr, WrappedType);
+ }
+
/// Completely replace the \c auto in \p TypeWithAuto by
/// \p Replacement. Also replace \p TypeWithAuto in \c TypeAttrPair if
/// necessary.
@@ -324,23 +324,18 @@ namespace {
bool didParseNoDeref() const { return parsedNoDeref; }
~TypeProcessingState() {
- if (trivial) return;
+ if (savedAttrs.empty())
+ return;
- restoreDeclSpecAttrs();
+ getMutableDeclSpec().getAttributes().clearListOnly();
+ for (ParsedAttr *AL : savedAttrs)
+ getMutableDeclSpec().getAttributes().addAtEnd(AL);
}
private:
DeclSpec &getMutableDeclSpec() const {
return const_cast<DeclSpec&>(declarator.getDeclSpec());
}
-
- void restoreDeclSpecAttrs() {
- assert(hasSavedAttrs);
-
- getMutableDeclSpec().getAttributes().clearListOnly();
- for (ParsedAttr *AL : savedAttrs)
- getMutableDeclSpec().getAttributes().addAtEnd(AL);
- }
};
} // end anonymous namespace
@@ -362,7 +357,8 @@ enum TypeAttrLocation {
};
static void processTypeAttrs(TypeProcessingState &state, QualType &type,
- TypeAttrLocation TAL, ParsedAttributesView &attrs);
+ TypeAttrLocation TAL,
+ const ParsedAttributesView &attrs);
static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr,
QualType &type);
@@ -633,15 +629,6 @@ static void distributeFunctionTypeAttrFromDeclSpec(TypeProcessingState &state,
QualType &declSpecType) {
state.saveDeclSpecAttrs();
- // C++11 attributes before the decl specifiers actually appertain to
- // the declarators. Move them straight there. We don't support the
- // 'put them wherever you like' semantics we allow for GNU attributes.
- if (attr.isStandardAttributeSyntax()) {
- moveAttrFromListToList(attr, state.getCurrentAttributes(),
- state.getDeclarator().getAttributes());
- return;
- }
-
// Try to distribute to the innermost.
if (distributeFunctionTypeAttrToInnermost(
state, attr, state.getCurrentAttributes(), declSpecType))
@@ -652,8 +639,10 @@ static void distributeFunctionTypeAttrFromDeclSpec(TypeProcessingState &state,
state.addIgnoredTypeAttr(attr);
}
-/// A function type attribute was written on the declarator. Try to
-/// apply it somewhere.
+/// A function type attribute was written on the declarator or declaration.
+/// Try to apply it somewhere.
+/// `Attrs` is the attribute list containing the declaration (either of the
+/// declarator or the declaration).
static void distributeFunctionTypeAttrFromDeclarator(TypeProcessingState &state,
ParsedAttr &attr,
QualType &declSpecType) {
@@ -670,7 +659,7 @@ static void distributeFunctionTypeAttrFromDeclarator(TypeProcessingState &state,
state.addIgnoredTypeAttr(attr);
}
-/// Given that there are attributes written on the declarator
+/// Given that there are attributes written on the declarator or declaration
/// itself, try to distribute any type attributes to the appropriate
/// declarator chunk.
///
@@ -679,11 +668,11 @@ static void distributeFunctionTypeAttrFromDeclarator(TypeProcessingState &state,
/// int (f ATTR)();
/// but not necessarily this:
/// int f() ATTR;
+///
+/// `Attrs` is the attribute list containing the declaration (either of the
+/// declarator or the declaration).
static void distributeTypeAttrsFromDeclarator(TypeProcessingState &state,
QualType &declSpecType) {
- // Collect all the type attributes from the declarator itself.
- assert(!state.getDeclarator().getAttributes().empty() &&
- "declarator has no attrs!");
// The called functions in this loop actually remove things from the current
// list, so iterating over the existing list isn't possible. Instead, make a
// non-owning copy and iterate over that.
@@ -1349,35 +1338,34 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
// allowed to be completely missing a declspec. This is handled in the
// parser already though by it pretending to have seen an 'int' in this
// case.
- if (S.getLangOpts().ImplicitInt) {
- // In C89 mode, we only warn if there is a completely missing declspec
- // when one is not allowed.
- if (DS.isEmpty()) {
- S.Diag(DeclLoc, diag::ext_missing_declspec)
- << DS.getSourceRange()
- << FixItHint::CreateInsertion(DS.getBeginLoc(), "int");
- }
+ if (S.getLangOpts().isImplicitIntRequired()) {
+ S.Diag(DeclLoc, diag::warn_missing_type_specifier)
+ << DS.getSourceRange()
+ << FixItHint::CreateInsertion(DS.getBeginLoc(), "int");
} else if (!DS.hasTypeSpecifier()) {
// C99 and C++ require a type specifier. For example, C99 6.7.2p2 says:
// "At least one type specifier shall be given in the declaration
// specifiers in each declaration, and in the specifier-qualifier list in
// each struct declaration and type name."
- if (S.getLangOpts().CPlusPlus && !DS.isTypeSpecPipe()) {
+ if (!S.getLangOpts().isImplicitIntAllowed() && !DS.isTypeSpecPipe()) {
S.Diag(DeclLoc, diag::err_missing_type_specifier)
- << DS.getSourceRange();
+ << DS.getSourceRange();
- // When this occurs in C++ code, often something is very broken with the
- // value being declared, poison it as invalid so we don't get chains of
+ // When this occurs, often something is very broken with the value
+ // being declared, poison it as invalid so we don't get chains of
// errors.
declarator.setInvalidType(true);
} else if (S.getLangOpts().getOpenCLCompatibleVersion() >= 200 &&
DS.isTypeSpecPipe()) {
S.Diag(DeclLoc, diag::err_missing_actual_pipe_type)
- << DS.getSourceRange();
+ << DS.getSourceRange();
declarator.setInvalidType(true);
} else {
+ assert(S.getLangOpts().isImplicitIntAllowed() &&
+ "implicit int is disabled?");
S.Diag(DeclLoc, diag::ext_missing_type_specifier)
- << DS.getSourceRange();
+ << DS.getSourceRange()
+ << FixItHint::CreateInsertion(DS.getBeginLoc(), "int");
}
}
@@ -1797,8 +1785,42 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
// list of type attributes to be temporarily saved while the type
// attributes are pushed around.
// pipe attributes will be handled later ( at GetFullTypeForDeclarator )
- if (!DS.isTypeSpecPipe())
+ if (!DS.isTypeSpecPipe()) {
+ // We also apply declaration attributes that "slide" to the decl spec.
+ // Ordering can be important for attributes. The decalaration attributes
+ // come syntactically before the decl spec attributes, so we process them
+ // in that order.
+ ParsedAttributesView SlidingAttrs;
+ for (ParsedAttr &AL : declarator.getDeclarationAttributes()) {
+ if (AL.slidesFromDeclToDeclSpecLegacyBehavior()) {
+ SlidingAttrs.addAtEnd(&AL);
+
+ // For standard syntax attributes, which would normally appertain to the
+ // declaration here, suggest moving them to the type instead. But only
+ // do this for our own vendor attributes; moving other vendors'
+ // attributes might hurt portability.
+ // There's one special case that we need to deal with here: The
+ // `MatrixType` attribute may only be used in a typedef declaration. If
+ // it's being used anywhere else, don't output the warning as
+ // ProcessDeclAttributes() will output an error anyway.
+ if (AL.isStandardAttributeSyntax() && AL.isClangScope() &&
+ !(AL.getKind() == ParsedAttr::AT_MatrixType &&
+ DS.getStorageClassSpec() != DeclSpec::SCS_typedef)) {
+ S.Diag(AL.getLoc(), diag::warn_type_attribute_deprecated_on_decl)
+ << AL;
+ }
+ }
+ }
+ // During this call to processTypeAttrs(),
+ // TypeProcessingState::getCurrentAttributes() will erroneously return a
+ // reference to the DeclSpec attributes, rather than the declaration
+ // attributes. However, this doesn't matter, as getCurrentAttributes()
+ // is only called when distributing attributes from one attribute list
+ // to another. Declaration attributes are always C++11 attributes, and these
+ // are never distributed.
+ processTypeAttrs(state, Result, TAL_DeclSpec, SlidingAttrs);
processTypeAttrs(state, Result, TAL_DeclSpec, DS.getAttributes());
+ }
// Apply const/volatile/restrict qualifiers to T.
if (unsigned TypeQuals = DS.getTypeQualifiers()) {
@@ -1874,6 +1896,14 @@ static std::string getPrintableNameForEntity(DeclarationName Entity) {
return "type name";
}
+static bool isDependentOrGNUAutoType(QualType T) {
+ if (T->isDependentType())
+ return true;
+
+ const auto *AT = dyn_cast<AutoType>(T);
+ return AT && AT->isGNUAutoType();
+}
+
QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc,
Qualifiers Qs, const DeclSpec *DS) {
if (T.isNull())
@@ -1907,7 +1937,10 @@ QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc,
DiagID = diag::err_typecheck_invalid_restrict_invalid_pointee;
ProblemTy = EltTy;
}
- } else if (!T->isDependentType()) {
+ } else if (!isDependentOrGNUAutoType(T)) {
+ // For an __auto_type variable, we may not have seen the initializer yet
+ // and so have no idea whether the underlying type is a pointer type or
+ // not.
DiagID = diag::err_typecheck_invalid_restrict_not_pointer;
ProblemTy = T;
}
@@ -2125,6 +2158,11 @@ QualType Sema::BuildPointerType(QualType T,
return QualType();
}
+ if (getLangOpts().HLSL) {
+ Diag(Loc, diag::err_hlsl_pointers_unsupported) << 0;
+ return QualType();
+ }
+
if (checkQualifiedFunction(*this, T, Loc, QFK_Pointer))
return QualType();
@@ -2190,6 +2228,11 @@ QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue,
return QualType();
}
+ if (getLangOpts().HLSL) {
+ Diag(Loc, diag::err_hlsl_pointers_unsupported) << 1;
+ return QualType();
+ }
+
if (checkQualifiedFunction(*this, T, Loc, QFK_Reference))
return QualType();
@@ -2458,6 +2501,9 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
} else if (isSFINAEContext()) {
VLADiag = diag::err_vla_in_sfinae;
VLAIsError = true;
+ } else if (getLangOpts().OpenMP && isInOpenMPTaskUntiedContext()) {
+ VLADiag = diag::err_openmp_vla_in_task_untied;
+ VLAIsError = true;
} else {
VLADiag = diag::ext_vla;
VLAIsError = false;
@@ -2613,7 +2659,7 @@ QualType Sema::BuildVectorType(QualType CurType, Expr *SizeExpr,
return QualType();
}
- if (VectorSizeBits % TypeSize) {
+ if (!TypeSize || VectorSizeBits % TypeSize) {
Diag(AttrLoc, diag::err_attribute_invalid_size)
<< SizeExpr->getSourceRange();
return QualType();
@@ -2641,9 +2687,12 @@ QualType Sema::BuildExtVectorType(QualType T, Expr *ArraySize,
// reserved data type under OpenCL v2.0 s6.1.4), we don't support selects
// on bitvectors, and we have no well-defined ABI for bitvectors, so vectors
// of bool aren't allowed.
+ //
+ // We explictly allow bool elements in ext_vector_type for C/C++.
+ bool IsNoBoolVecLang = getLangOpts().OpenCL || getLangOpts().OpenCLCPlusPlus;
if ((!T->isDependentType() && !T->isIntegerType() &&
!T->isRealFloatingType()) ||
- T->isBooleanType()) {
+ (IsNoBoolVecLang && T->isBooleanType())) {
Diag(AttrLoc, diag::err_attribute_invalid_vector_type) << T;
return QualType();
}
@@ -2943,6 +2992,11 @@ QualType Sema::BuildMemberPointerType(QualType T, QualType Class,
return QualType();
}
+ if (getLangOpts().HLSL) {
+ Diag(Loc, diag::err_hlsl_pointers_unsupported) << 0;
+ return QualType();
+ }
+
// Adjust the default free function calling convention to the default method
// calling convention.
bool IsCtorOrDtor =
@@ -3373,8 +3427,10 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
break;
}
- if (!D.getAttributes().empty())
- distributeTypeAttrsFromDeclarator(state, T);
+ // Note: We don't need to distribute declaration attributes (i.e.
+ // D.getDeclarationAttributes()) because those are always C++11 attributes,
+ // and those don't get distributed.
+ distributeTypeAttrsFromDeclarator(state, T);
// Find the deduced type in this type. Look in the trailing return type if we
// have one, otherwise in the DeclSpec type.
@@ -3506,8 +3562,12 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
case DeclaratorContext::FunctionalCast:
if (isa<DeducedTemplateSpecializationType>(Deduced))
break;
+ if (SemaRef.getLangOpts().CPlusPlus2b && IsCXXAutoType &&
+ !Auto->isDecltypeAuto())
+ break; // auto(x)
LLVM_FALLTHROUGH;
case DeclaratorContext::TypeName:
+ case DeclaratorContext::Association:
Error = 15; // Generic
break;
case DeclaratorContext::File:
@@ -3618,6 +3678,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
case DeclaratorContext::ObjCCatch:
case DeclaratorContext::TemplateArg:
case DeclaratorContext::TemplateTypeArg:
+ case DeclaratorContext::Association:
DiagID = diag::err_type_defined_in_type_specifier;
break;
case DeclaratorContext::Prototype:
@@ -4670,7 +4731,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
AttrList.hasAttribute(ParsedAttr::AT_CFReturnsNotRetained);
};
if (const auto *InnermostChunk = D.getInnermostNonParenChunk()) {
- if (hasCFReturnsAttr(D.getAttributes()) ||
+ if (hasCFReturnsAttr(D.getDeclarationAttributes()) ||
+ hasCFReturnsAttr(D.getAttributes()) ||
hasCFReturnsAttr(InnermostChunk->getAttrs()) ||
hasCFReturnsAttr(D.getDeclSpec().getAttributes())) {
inferNullability = NullabilityKind::Nullable;
@@ -4705,6 +4767,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
case DeclaratorContext::TypeName:
case DeclaratorContext::FunctionalCast:
case DeclaratorContext::RequiresExpr:
+ case DeclaratorContext::Association:
// Don't infer in these contexts.
break;
}
@@ -5228,8 +5291,11 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
FunctionType::ExtInfo EI(
getCCForDeclaratorChunk(S, D, DeclType.getAttrs(), FTI, chunkIndex));
- if (!FTI.NumParams && !FTI.isVariadic && !LangOpts.CPlusPlus
- && !LangOpts.OpenCL) {
+ // OpenCL disallows functions without a prototype, but it doesn't enforce
+ // strict prototypes as in C2x because it allows a function definition to
+ // have an identifier list. See OpenCL 3.0 6.11/g for more details.
+ if (!FTI.NumParams && !FTI.isVariadic &&
+ !LangOpts.requiresStrictPrototypes() && !LangOpts.OpenCL) {
// Simple void foo(), where the incoming T is the result type.
T = Context.getFunctionNoProtoType(T, EI);
} else {
@@ -5237,7 +5303,11 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// function is marked with the "overloadable" attribute. Scan
// for this attribute now.
if (!FTI.NumParams && FTI.isVariadic && !LangOpts.CPlusPlus)
- if (!D.getAttributes().hasAttribute(ParsedAttr::AT_Overloadable))
+ if (!D.getDeclarationAttributes().hasAttribute(
+ ParsedAttr::AT_Overloadable) &&
+ !D.getAttributes().hasAttribute(ParsedAttr::AT_Overloadable) &&
+ !D.getDeclSpec().getAttributes().hasAttribute(
+ ParsedAttr::AT_Overloadable))
S.Diag(FTI.getEllipsisLoc(), diag::err_ellipsis_first_param);
if (FTI.NumParams && FTI.Params[0].Param == nullptr) {
@@ -5246,8 +5316,10 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
S.Diag(FTI.Params[0].IdentLoc,
diag::err_ident_list_in_fn_declaration);
D.setInvalidType(true);
- // Recover by creating a K&R-style function type.
- T = Context.getFunctionNoProtoType(T, EI);
+ // Recover by creating a K&R-style function type, if possible.
+ T = (!LangOpts.requiresStrictPrototypes() && !LangOpts.OpenCL)
+ ? Context.getFunctionNoProtoType(T, EI)
+ : Context.IntTy;
break;
}
@@ -5519,15 +5591,16 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
diag::warn_noderef_on_non_pointer_or_array);
// GNU warning -Wstrict-prototypes
- // Warn if a function declaration is without a prototype.
+ // Warn if a function declaration or definition is without a prototype.
// This warning is issued for all kinds of unprototyped function
// declarations (i.e. function type typedef, function pointer etc.)
// C99 6.7.5.3p14:
// The empty list in a function declarator that is not part of a definition
// of that function specifies that no information about the number or types
// of the parameters is supplied.
- if (!LangOpts.CPlusPlus &&
- D.getFunctionDefinitionKind() == FunctionDefinitionKind::Declaration) {
+ // See ActOnFinishFunctionBody() and MergeFunctionDecl() for handling of
+ // function declarations whose behavior changes in C2x.
+ if (!LangOpts.requiresStrictPrototypes()) {
bool IsBlock = false;
for (const DeclaratorChunk &DeclType : D.type_objects()) {
switch (DeclType.Kind) {
@@ -5538,8 +5611,10 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun;
// We suppress the warning when there's no LParen location, as this
// indicates the declaration was an implicit declaration, which gets
- // warned about separately via -Wimplicit-function-declaration.
- if (FTI.NumParams == 0 && !FTI.isVariadic && FTI.getLParenLoc().isValid())
+ // warned about separately via -Wimplicit-function-declaration. We also
+ // suppress the warning when we know the function has a prototype.
+ if (!FTI.hasPrototype && FTI.NumParams == 0 && !FTI.isVariadic &&
+ FTI.getLParenLoc().isValid())
S.Diag(DeclType.Loc, diag::warn_strict_prototypes)
<< IsBlock
<< FixItHint::CreateInsertion(FTI.getRParenLoc(), "void");
@@ -5646,7 +5721,14 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
}
}
- // Apply any undistributed attributes from the declarator.
+ // Apply any undistributed attributes from the declaration or declarator.
+ ParsedAttributesView NonSlidingAttrs;
+ for (ParsedAttr &AL : D.getDeclarationAttributes()) {
+ if (!AL.slidesFromDeclToDeclSpecLegacyBehavior()) {
+ NonSlidingAttrs.addAtEnd(&AL);
+ }
+ }
+ processTypeAttrs(state, T, TAL_DeclName, NonSlidingAttrs);
processTypeAttrs(state, T, TAL_DeclName, D.getAttributes());
// Diagnose any ignored type attributes.
@@ -5737,6 +5819,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
case DeclaratorContext::TrailingReturnVar:
case DeclaratorContext::TemplateArg:
case DeclaratorContext::TemplateTypeArg:
+ case DeclaratorContext::Association:
// FIXME: We may want to allow parameter packs in block-literal contexts
// in the future.
S.Diag(D.getEllipsisLoc(),
@@ -5907,6 +5990,9 @@ namespace {
Visit(TL.getModifiedLoc());
fillAttributedTypeLoc(TL, State);
}
+ void VisitBTFTagAttributedTypeLoc(BTFTagAttributedTypeLoc TL) {
+ Visit(TL.getWrappedLoc());
+ }
void VisitMacroQualifiedTypeLoc(MacroQualifiedTypeLoc TL) {
Visit(TL.getInnerLoc());
TL.setExpansionLoc(
@@ -6133,6 +6219,9 @@ namespace {
void VisitAttributedTypeLoc(AttributedTypeLoc TL) {
fillAttributedTypeLoc(TL, State);
}
+ void VisitBTFTagAttributedTypeLoc(BTFTagAttributedTypeLoc TL) {
+ // nothing
+ }
void VisitAdjustedTypeLoc(AdjustedTypeLoc TL) {
// nothing
}
@@ -6548,8 +6637,8 @@ static void HandleBTFTypeTagAttribute(QualType &Type, const ParsedAttr &Attr,
ASTContext &Ctx = S.Context;
StringRef BTFTypeTag = StrLiteral->getString();
- Type = State.getAttributedType(
- ::new (Ctx) BTFTypeTagAttr(Ctx, Attr, BTFTypeTag), Type, Type);
+ Type = State.getBTFTagAttributedType(
+ ::new (Ctx) BTFTypeTagAttr(Ctx, Attr, BTFTypeTag), Type);
}
/// HandleAddressSpaceTypeAttribute - Process an address_space attribute on the
@@ -7439,6 +7528,10 @@ static Attr *getCCTypeAttr(ASTContext &Ctx, ParsedAttr &Attr) {
return createSimpleAttr<VectorCallAttr>(Ctx, Attr);
case ParsedAttr::AT_AArch64VectorPcs:
return createSimpleAttr<AArch64VectorPcsAttr>(Ctx, Attr);
+ case ParsedAttr::AT_AArch64SVEPcs:
+ return createSimpleAttr<AArch64SVEPcsAttr>(Ctx, Attr);
+ case ParsedAttr::AT_AMDGPUKernelCall:
+ return createSimpleAttr<AMDGPUKernelCallAttr>(Ctx, Attr);
case ParsedAttr::AT_Pcs: {
// The attribute may have had a fixit applied where we treated an
// identifier as a string literal. The contents of the string are valid,
@@ -8090,6 +8183,34 @@ static void HandleMatrixTypeAttr(QualType &CurType, const ParsedAttr &Attr,
CurType = T;
}
+static void HandleAnnotateTypeAttr(TypeProcessingState &State,
+ QualType &CurType, const ParsedAttr &PA) {
+ Sema &S = State.getSema();
+
+ if (PA.getNumArgs() < 1) {
+ S.Diag(PA.getLoc(), diag::err_attribute_too_few_arguments) << PA << 1;
+ return;
+ }
+
+ // Make sure that there is a string literal as the annotation's first
+ // argument.
+ StringRef Str;
+ if (!S.checkStringLiteralArgumentAttr(PA, 0, Str))
+ return;
+
+ llvm::SmallVector<Expr *, 4> Args;
+ Args.reserve(PA.getNumArgs() - 1);
+ for (unsigned Idx = 1; Idx < PA.getNumArgs(); Idx++) {
+ assert(!PA.isArgIdent(Idx));
+ Args.push_back(PA.getArgAsExpr(Idx));
+ }
+ if (!S.ConstantFoldAttrArgs(PA, Args))
+ return;
+ auto *AnnotateTypeAttr =
+ AnnotateTypeAttr::Create(S.Context, Str, Args.data(), Args.size(), PA);
+ CurType = State.getAttributedType(AnnotateTypeAttr, CurType, CurType);
+}
+
static void HandleLifetimeBoundAttr(TypeProcessingState &State,
QualType &CurType,
ParsedAttr &Attr) {
@@ -8100,22 +8221,14 @@ static void HandleLifetimeBoundAttr(TypeProcessingState &State,
}
}
-static bool isAddressSpaceKind(const ParsedAttr &attr) {
- auto attrKind = attr.getKind();
-
- return attrKind == ParsedAttr::AT_AddressSpace ||
- attrKind == ParsedAttr::AT_OpenCLPrivateAddressSpace ||
- attrKind == ParsedAttr::AT_OpenCLGlobalAddressSpace ||
- attrKind == ParsedAttr::AT_OpenCLGlobalDeviceAddressSpace ||
- attrKind == ParsedAttr::AT_OpenCLGlobalHostAddressSpace ||
- attrKind == ParsedAttr::AT_OpenCLLocalAddressSpace ||
- attrKind == ParsedAttr::AT_OpenCLConstantAddressSpace ||
- attrKind == ParsedAttr::AT_OpenCLGenericAddressSpace;
-}
-
static void processTypeAttrs(TypeProcessingState &state, QualType &type,
TypeAttrLocation TAL,
- ParsedAttributesView &attrs) {
+ const ParsedAttributesView &attrs) {
+
+ state.setParsedNoDeref(false);
+ if (attrs.empty())
+ return;
+
// Scan through and apply attributes to this type where it makes sense. Some
// attributes (such as __address_space__, __vector_size__, etc) apply to the
// type, but others can be present in the type specifiers even though they
@@ -8125,9 +8238,6 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
// sure we visit every element once. Copy the attributes list, and iterate
// over that.
ParsedAttributesView AttrsCopy{attrs};
-
- state.setParsedNoDeref(false);
-
for (ParsedAttr &attr : AttrsCopy) {
// Skip attributes that were marked to be invalid.
@@ -8150,11 +8260,14 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
if (!IsTypeAttr)
continue;
}
- } else if (TAL != TAL_DeclChunk && !isAddressSpaceKind(attr)) {
+ } else if (TAL != TAL_DeclSpec && TAL != TAL_DeclChunk &&
+ !attr.isTypeAttr()) {
// Otherwise, only consider type processing for a C++11 attribute if
- // it's actually been applied to a type.
- // We also allow C++11 address_space and
- // OpenCL language address space attributes to pass through.
+ // - it has actually been applied to a type (decl-specifier-seq or
+ // declarator chunk), or
+ // - it is a type attribute, irrespective of where it was applied (so
+ // that we can support the legacy behavior of some type attributes
+ // that can be applied to the declaration name).
continue;
}
}
@@ -8172,10 +8285,14 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
break;
case ParsedAttr::UnknownAttribute:
- if (attr.isStandardAttributeSyntax() && TAL == TAL_DeclChunk)
+ if (attr.isStandardAttributeSyntax()) {
state.getSema().Diag(attr.getLoc(),
diag::warn_unknown_attribute_ignored)
<< attr << attr.getRange();
+ // Mark the attribute as invalid so we don't emit the same diagnostic
+ // multiple times.
+ attr.setInvalid();
+ }
break;
case ParsedAttr::IgnoredAttribute:
@@ -8244,6 +8361,15 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
break;
case ParsedAttr::AT_NoDeref: {
+ // FIXME: `noderef` currently doesn't work correctly in [[]] syntax.
+ // See https://github.com/llvm/llvm-project/issues/55790 for details.
+ // For the time being, we simply emit a warning that the attribute is
+ // ignored.
+ if (attr.isStandardAttributeSyntax()) {
+ state.getSema().Diag(attr.getLoc(), diag::warn_attribute_ignored)
+ << attr;
+ break;
+ }
ASTContext &Ctx = state.getSema().Context;
type = state.getAttributedType(createSimpleAttr<NoDerefAttr>(Ctx, attr),
type, type);
@@ -8321,6 +8447,16 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
FUNCTION_TYPE_ATTRS_CASELIST:
attr.setUsedAsTypeAttr();
+ // Attributes with standard syntax have strict rules for what they
+ // appertain to and hence should not use the "distribution" logic below.
+ if (attr.isStandardAttributeSyntax()) {
+ if (!handleFunctionTypeAttr(state, attr, type)) {
+ diagnoseBadTypeAttribute(state.getSema(), attr, type);
+ attr.setInvalid();
+ }
+ break;
+ }
+
// Never process function type attributes as part of the
// declaration-specifiers.
if (TAL == TAL_DeclSpec)
@@ -8351,6 +8487,11 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
attr.setUsedAsTypeAttr();
break;
}
+ case ParsedAttr::AT_AnnotateType: {
+ HandleAnnotateTypeAttr(state, type, attr);
+ attr.setUsedAsTypeAttr();
+ break;
+ }
}
// Handle attributes that are defined in a macro. We do not want this to be
@@ -8501,17 +8642,8 @@ bool Sema::hasStructuralCompatLayout(Decl *D, Decl *Suggested) {
return Ctx.IsEquivalent(D, Suggested);
}
-/// Determine whether there is any declaration of \p D that was ever a
-/// definition (perhaps before module merging) and is currently visible.
-/// \param D The definition of the entity.
-/// \param Suggested Filled in with the declaration that should be made visible
-/// in order to provide a definition of this entity.
-/// \param OnlyNeedComplete If \c true, we only need the type to be complete,
-/// not defined. This only matters for enums with a fixed underlying
-/// type, since in all other cases, a type is complete if and only if it
-/// is defined.
-bool Sema::hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested,
- bool OnlyNeedComplete) {
+bool Sema::hasAcceptableDefinition(NamedDecl *D, NamedDecl **Suggested,
+ AcceptableKind Kind, bool OnlyNeedComplete) {
// Easy case: if we don't have modules, all declarations are visible.
if (!getLangOpts().Modules && !getLangOpts().ModulesLocalVisibility)
return true;
@@ -8555,13 +8687,14 @@ bool Sema::hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested,
VD = Pattern;
D = VD->getDefinition();
}
+
assert(D && "missing definition for pattern of instantiated definition");
*Suggested = D;
- auto DefinitionIsVisible = [&] {
+ auto DefinitionIsAcceptable = [&] {
// The (primary) definition might be in a visible module.
- if (isVisible(D))
+ if (isAcceptable(D, Kind))
return true;
// A visible module might have a merged definition instead.
@@ -8579,19 +8712,51 @@ bool Sema::hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested,
return false;
};
- if (DefinitionIsVisible())
+ if (DefinitionIsAcceptable())
return true;
// The external source may have additional definitions of this entity that are
// visible, so complete the redeclaration chain now and ask again.
if (auto *Source = Context.getExternalSource()) {
Source->CompleteRedeclChain(D);
- return DefinitionIsVisible();
+ return DefinitionIsAcceptable();
}
return false;
}
+/// Determine whether there is any declaration of \p D that was ever a
+/// definition (perhaps before module merging) and is currently visible.
+/// \param D The definition of the entity.
+/// \param Suggested Filled in with the declaration that should be made visible
+/// in order to provide a definition of this entity.
+/// \param OnlyNeedComplete If \c true, we only need the type to be complete,
+/// not defined. This only matters for enums with a fixed underlying
+/// type, since in all other cases, a type is complete if and only if it
+/// is defined.
+bool Sema::hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested,
+ bool OnlyNeedComplete) {
+ return hasAcceptableDefinition(D, Suggested, Sema::AcceptableKind::Visible,
+ OnlyNeedComplete);
+}
+
+/// Determine whether there is any declaration of \p D that was ever a
+/// definition (perhaps before module merging) and is currently
+/// reachable.
+/// \param D The definition of the entity.
+/// \param Suggested Filled in with the declaration that should be made
+/// reachable
+/// in order to provide a definition of this entity.
+/// \param OnlyNeedComplete If \c true, we only need the type to be complete,
+/// not defined. This only matters for enums with a fixed underlying
+/// type, since in all other cases, a type is complete if and only if it
+/// is defined.
+bool Sema::hasReachableDefinition(NamedDecl *D, NamedDecl **Suggested,
+ bool OnlyNeedComplete) {
+ return hasAcceptableDefinition(D, Suggested, Sema::AcceptableKind::Reachable,
+ OnlyNeedComplete);
+}
+
/// Locks in the inheritance model for the given class and all of its bases.
static void assignInheritanceModel(Sema &S, CXXRecordDecl *RD) {
RD = RD->getMostRecentNonInjectedDecl();
@@ -8661,20 +8826,19 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
// Check that any necessary explicit specializations are visible. For an
// enum, we just need the declaration, so don't check this.
if (Def && !isa<EnumDecl>(Def))
- checkSpecializationVisibility(Loc, Def);
+ checkSpecializationReachability(Loc, Def);
// If we have a complete type, we're done.
if (!Incomplete) {
- // If we know about the definition but it is not visible, complain.
- NamedDecl *SuggestedDef = nullptr;
+ NamedDecl *Suggested = nullptr;
if (Def &&
- !hasVisibleDefinition(Def, &SuggestedDef, /*OnlyNeedComplete*/true)) {
+ !hasReachableDefinition(Def, &Suggested, /*OnlyNeedComplete=*/true)) {
// If the user is going to see an error here, recover by making the
// definition visible.
bool TreatAsComplete = Diagnoser && !isSFINAEContext();
- if (Diagnoser && SuggestedDef)
- diagnoseMissingImport(Loc, SuggestedDef, MissingImportKind::Definition,
- /*Recover*/TreatAsComplete);
+ if (Diagnoser && Suggested)
+ diagnoseMissingImport(Loc, Suggested, MissingImportKind::Definition,
+ /*Recover*/ TreatAsComplete);
return !TreatAsComplete;
} else if (Def && !TemplateInstCallbacks.empty()) {
CodeSynthesisContext TempInst;
@@ -9078,7 +9242,7 @@ QualType Sema::BuildUnaryTransformType(QualType BaseType,
}
QualType Sema::BuildAtomicType(QualType T, SourceLocation Loc) {
- if (!T->isDependentType()) {
+ if (!isDependentOrGNUAutoType(T)) {
// FIXME: It isn't entirely clear whether incomplete atomic types
// are allowed or not; for simplicity, ban them for the moment.
if (RequireCompleteType(Loc, T, diag::err_atomic_specifier_bad_type, 0))
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 5c37fcaaea13..a8589191fc91 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -1470,9 +1470,28 @@ public:
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
- ExprResult RebuildCoawaitExpr(SourceLocation CoawaitLoc, Expr *Result,
+ ExprResult RebuildCoawaitExpr(SourceLocation CoawaitLoc, Expr *Operand,
+ UnresolvedLookupExpr *OpCoawaitLookup,
bool IsImplicit) {
- return getSema().BuildResolvedCoawaitExpr(CoawaitLoc, Result, IsImplicit);
+ // This function rebuilds a coawait-expr given its operator.
+ // For an explicit coawait-expr, the rebuild involves the full set
+ // of transformations performed by BuildUnresolvedCoawaitExpr(),
+ // including calling await_transform().
+ // For an implicit coawait-expr, we need to rebuild the "operator
+ // coawait" but not await_transform(), so use BuildResolvedCoawaitExpr().
+ // This mirrors how the implicit CoawaitExpr is originally created
+ // in Sema::ActOnCoroutineBodyStart().
+ if (IsImplicit) {
+ ExprResult Suspend = getSema().BuildOperatorCoawaitCall(
+ CoawaitLoc, Operand, OpCoawaitLookup);
+ if (Suspend.isInvalid())
+ return ExprError();
+ return getSema().BuildResolvedCoawaitExpr(CoawaitLoc, Operand,
+ Suspend.get(), true);
+ }
+
+ return getSema().BuildUnresolvedCoawaitExpr(CoawaitLoc, Operand,
+ OpCoawaitLookup);
}
/// Build a new co_await expression.
@@ -1900,14 +1919,13 @@ public:
///
/// By default, performs semantic analysis to build the new OpenMP clause.
/// Subclasses may override this routine to provide different behavior.
- OMPClause *
- RebuildOMPDependClause(Expr *DepModifier, OpenMPDependClauseKind DepKind,
- SourceLocation DepLoc, SourceLocation ColonLoc,
- ArrayRef<Expr *> VarList, SourceLocation StartLoc,
- SourceLocation LParenLoc, SourceLocation EndLoc) {
- return getSema().ActOnOpenMPDependClause(DepModifier, DepKind, DepLoc,
- ColonLoc, VarList, StartLoc,
- LParenLoc, EndLoc);
+ OMPClause *RebuildOMPDependClause(OMPDependClause::DependDataTy Data,
+ Expr *DepModifier, ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPDependClause(Data, DepModifier, VarList,
+ StartLoc, LParenLoc, EndLoc);
}
/// Build a new OpenMP 'device' clause.
@@ -2101,6 +2119,15 @@ public:
return getSema().ActOnOpenMPIsDevicePtrClause(VarList, Locs);
}
+ /// Build a new OpenMP 'has_device_addr' clause.
+ ///
+ /// By default, performs semantic analysis to build the new OpenMP clause.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPHasDeviceAddrClause(ArrayRef<Expr *> VarList,
+ const OMPVarListLocTy &Locs) {
+ return getSema().ActOnOpenMPHasDeviceAddrClause(VarList, Locs);
+ }
+
/// Build a new OpenMP 'defaultmap' clause.
///
/// By default, performs semantic analysis to build the new OpenMP clause.
@@ -2629,6 +2656,13 @@ public:
/*Scope=*/nullptr, Callee, LParenLoc, Args, RParenLoc, ExecConfig);
}
+ ExprResult RebuildCxxSubscriptExpr(Expr *Callee, SourceLocation LParenLoc,
+ MultiExprArg Args,
+ SourceLocation RParenLoc) {
+ return getSema().ActOnArraySubscriptExpr(
+ /*Scope=*/nullptr, Callee, LParenLoc, Args, RParenLoc);
+ }
+
/// Build a new member access expression.
///
/// By default, performs semantic analysis to build the new expression.
@@ -3379,10 +3413,11 @@ public:
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
ExprResult RebuildSourceLocExpr(SourceLocExpr::IdentKind Kind,
- SourceLocation BuiltinLoc,
+ QualType ResultTy, SourceLocation BuiltinLoc,
SourceLocation RPLoc,
DeclContext *ParentContext) {
- return getSema().BuildSourceLocExpr(Kind, BuiltinLoc, RPLoc, ParentContext);
+ return getSema().BuildSourceLocExpr(Kind, ResultTy, BuiltinLoc, RPLoc,
+ ParentContext);
}
/// Build a new Objective-C boxed expression.
@@ -4263,7 +4298,7 @@ TreeTransform<Derived>::TransformTemplateName(CXXScopeSpec &SS,
NamedDecl *FirstQualifierInScope,
bool AllowInjectedClassName) {
if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName()) {
- TemplateDecl *Template = QTN->getTemplateDecl();
+ TemplateDecl *Template = QTN->getUnderlyingTemplate().getAsTemplateDecl();
assert(Template && "qualified template name must refer to a template");
TemplateDecl *TransTemplate
@@ -6858,6 +6893,13 @@ QualType TreeTransform<Derived>::TransformAttributedType(
return result;
}
+template <typename Derived>
+QualType TreeTransform<Derived>::TransformBTFTagAttributedType(
+ TypeLocBuilder &TLB, BTFTagAttributedTypeLoc TL) {
+ // The BTFTagAttributedType is available for C only.
+ llvm_unreachable("Unexpected TreeTransform for BTFTagAttributedType");
+}
+
template<typename Derived>
QualType
TreeTransform<Derived>::TransformParenType(TypeLocBuilder &TLB,
@@ -7896,12 +7938,6 @@ TreeTransform<Derived>::TransformCoroutineBodyStmt(CoroutineBodyStmt *S) {
return StmtError();
Builder.Deallocate = DeallocRes.get();
- assert(S->getResultDecl() && "ResultDecl must already be built");
- StmtResult ResultDecl = getDerived().TransformStmt(S->getResultDecl());
- if (ResultDecl.isInvalid())
- return StmtError();
- Builder.ResultDecl = ResultDecl.get();
-
if (auto *ReturnStmt = S->getReturnStmt()) {
StmtResult Res = getDerived().TransformStmt(ReturnStmt);
if (Res.isInvalid())
@@ -7927,18 +7963,27 @@ TreeTransform<Derived>::TransformCoreturnStmt(CoreturnStmt *S) {
S->isImplicit());
}
-template<typename Derived>
-ExprResult
-TreeTransform<Derived>::TransformCoawaitExpr(CoawaitExpr *E) {
- ExprResult Result = getDerived().TransformInitializer(E->getOperand(),
- /*NotCopyInit*/false);
- if (Result.isInvalid())
+template <typename Derived>
+ExprResult TreeTransform<Derived>::TransformCoawaitExpr(CoawaitExpr *E) {
+ ExprResult Operand = getDerived().TransformInitializer(E->getOperand(),
+ /*NotCopyInit*/ false);
+ if (Operand.isInvalid())
return ExprError();
+ // Rebuild the common-expr from the operand rather than transforming it
+ // separately.
+
+ // FIXME: getCurScope() should not be used during template instantiation.
+ // We should pick up the set of unqualified lookup results for operator
+ // co_await during the initial parse.
+ ExprResult Lookup = getSema().BuildOperatorCoawaitLookupExpr(
+ getSema().getCurScope(), E->getKeywordLoc());
+
// Always rebuild; we don't know if this needs to be injected into a new
// context or if the promise type has changed.
- return getDerived().RebuildCoawaitExpr(E->getKeywordLoc(), Result.get(),
- E->isImplicit());
+ return getDerived().RebuildCoawaitExpr(
+ E->getKeywordLoc(), Operand.get(),
+ cast<UnresolvedLookupExpr>(Lookup.get()), E->isImplicit());
}
template <typename Derived>
@@ -8728,6 +8773,17 @@ StmtResult TreeTransform<Derived>::TransformOMPParallelMasterDirective(
}
template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformOMPParallelMaskedDirective(
+ OMPParallelMaskedDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_parallel_masked, DirName,
+ nullptr, D->getBeginLoc());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
StmtResult TreeTransform<Derived>::TransformOMPParallelSectionsDirective(
OMPParallelSectionsDirective *D) {
DeclarationNameInfo DirName;
@@ -8992,6 +9048,17 @@ StmtResult TreeTransform<Derived>::TransformOMPMasterTaskLoopDirective(
}
template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformOMPMaskedTaskLoopDirective(
+ OMPMaskedTaskLoopDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_masked_taskloop, DirName,
+ nullptr, D->getBeginLoc());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
StmtResult TreeTransform<Derived>::TransformOMPMasterTaskLoopSimdDirective(
OMPMasterTaskLoopSimdDirective *D) {
DeclarationNameInfo DirName;
@@ -9003,6 +9070,17 @@ StmtResult TreeTransform<Derived>::TransformOMPMasterTaskLoopSimdDirective(
}
template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformOMPMaskedTaskLoopSimdDirective(
+ OMPMaskedTaskLoopSimdDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_masked_taskloop_simd, DirName,
+ nullptr, D->getBeginLoc());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
StmtResult TreeTransform<Derived>::TransformOMPParallelMasterTaskLoopDirective(
OMPParallelMasterTaskLoopDirective *D) {
DeclarationNameInfo DirName;
@@ -9014,6 +9092,17 @@ StmtResult TreeTransform<Derived>::TransformOMPParallelMasterTaskLoopDirective(
}
template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformOMPParallelMaskedTaskLoopDirective(
+ OMPParallelMaskedTaskLoopDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(
+ OMPD_parallel_masked_taskloop, DirName, nullptr, D->getBeginLoc());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
StmtResult
TreeTransform<Derived>::TransformOMPParallelMasterTaskLoopSimdDirective(
OMPParallelMasterTaskLoopSimdDirective *D) {
@@ -9026,6 +9115,18 @@ TreeTransform<Derived>::TransformOMPParallelMasterTaskLoopSimdDirective(
}
template <typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformOMPParallelMaskedTaskLoopSimdDirective(
+ OMPParallelMaskedTaskLoopSimdDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(
+ OMPD_parallel_masked_taskloop_simd, DirName, nullptr, D->getBeginLoc());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
StmtResult TreeTransform<Derived>::TransformOMPDistributeDirective(
OMPDistributeDirective *D) {
DeclarationNameInfo DirName;
@@ -9241,6 +9342,51 @@ StmtResult TreeTransform<Derived>::TransformOMPGenericLoopDirective(
return Res;
}
+template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformOMPTeamsGenericLoopDirective(
+ OMPTeamsGenericLoopDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_teams_loop, DirName, nullptr,
+ D->getBeginLoc());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformOMPTargetTeamsGenericLoopDirective(
+ OMPTargetTeamsGenericLoopDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_target_teams_loop, DirName,
+ nullptr, D->getBeginLoc());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformOMPParallelGenericLoopDirective(
+ OMPParallelGenericLoopDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_parallel_loop, DirName,
+ nullptr, D->getBeginLoc());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformOMPTargetParallelGenericLoopDirective(
+ OMPTargetParallelGenericLoopDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_target_parallel_loop, DirName,
+ nullptr, D->getBeginLoc());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
//===----------------------------------------------------------------------===//
// OpenMP clause transformation
//===----------------------------------------------------------------------===//
@@ -9949,9 +10095,9 @@ TreeTransform<Derived>::TransformOMPDependClause(OMPDependClause *C) {
Vars.push_back(EVar.get());
}
return getDerived().RebuildOMPDependClause(
- DepModifier, C->getDependencyKind(), C->getDependencyLoc(),
- C->getColonLoc(), Vars, C->getBeginLoc(), C->getLParenLoc(),
- C->getEndLoc());
+ {C->getDependencyKind(), C->getDependencyLoc(), C->getColonLoc(),
+ C->getOmpAllMemoryLoc()},
+ DepModifier, Vars, C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc());
}
template <typename Derived>
@@ -10217,6 +10363,21 @@ TreeTransform<Derived>::TransformOMPIsDevicePtrClause(OMPIsDevicePtrClause *C) {
}
template <typename Derived>
+OMPClause *TreeTransform<Derived>::TransformOMPHasDeviceAddrClause(
+ OMPHasDeviceAddrClause *C) {
+ llvm::SmallVector<Expr *, 16> Vars;
+ Vars.reserve(C->varlist_size());
+ for (auto *VE : C->varlists()) {
+ ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE));
+ if (EVar.isInvalid())
+ return nullptr;
+ Vars.push_back(EVar.get());
+ }
+ OMPVarListLocTy Locs(C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc());
+ return getDerived().RebuildOMPHasDeviceAddrClause(Vars, Locs);
+}
+
+template <typename Derived>
OMPClause *
TreeTransform<Derived>::TransformOMPNontemporalClause(OMPNontemporalClause *C) {
llvm::SmallVector<Expr *, 16> Vars;
@@ -10460,9 +10621,7 @@ TreeTransform<Derived>::TransformCharacterLiteral(CharacterLiteral *E) {
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformUserDefinedLiteral(UserDefinedLiteral *E) {
- if (FunctionDecl *FD = E->getDirectCallee())
- SemaRef.MarkFunctionReferenced(E->getBeginLoc(), FD);
- return SemaRef.MaybeBindToTemporary(E);
+ return getDerived().TransformCallExpr(E);
}
template<typename Derived>
@@ -10961,11 +11120,15 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) {
FoundDecl == E->getFoundDecl() &&
!E->hasExplicitTemplateArgs()) {
- // Mark it referenced in the new context regardless.
- // FIXME: this is a bit instantiation-specific.
- SemaRef.MarkMemberReferenced(E);
-
- return E;
+ // Skip for member expression of (this->f), rebuilt thisi->f is needed
+ // for Openmp where the field need to be privatizized in the case.
+ if (!(isa<CXXThisExpr>(E->getBase()) &&
+ getSema().isOpenMPRebuildMemberExpr(cast<ValueDecl>(Member)))) {
+ // Mark it referenced in the new context regardless.
+ // FIXME: this is a bit instantiation-specific.
+ SemaRef.MarkMemberReferenced(E);
+ return E;
+ }
}
TemplateArgumentListInfo TransArgs;
@@ -11507,6 +11670,7 @@ TreeTransform<Derived>::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
case OO_Array_Delete:
llvm_unreachable("new and delete operators cannot use CXXOperatorCallExpr");
+ case OO_Subscript:
case OO_Call: {
// This is a call to an object's operator().
assert(E->getNumArgs() >= 1 && "Object call is missing arguments");
@@ -11526,17 +11690,20 @@ TreeTransform<Derived>::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
Args))
return ExprError();
+ if (E->getOperator() == OO_Subscript)
+ return getDerived().RebuildCxxSubscriptExpr(Object.get(), FakeLParenLoc,
+ Args, E->getEndLoc());
+
return getDerived().RebuildCallExpr(Object.get(), FakeLParenLoc, Args,
E->getEndLoc());
}
-#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
- case OO_##Name:
+#define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemberOnly) \
+ case OO_##Name: \
+ break;
+
#define OVERLOADED_OPERATOR_MULTI(Name,Spelling,Unary,Binary,MemberOnly)
#include "clang/Basic/OperatorKinds.def"
- case OO_Subscript:
- // Handled below.
- break;
case OO_Conditional:
llvm_unreachable("conditional operator is not actually overloadable");
@@ -11598,8 +11765,8 @@ ExprResult TreeTransform<Derived>::TransformSourceLocExpr(SourceLocExpr *E) {
if (!getDerived().AlwaysRebuild() && !NeedRebuildFunc)
return E;
- return getDerived().RebuildSourceLocExpr(E->getIdentKind(), E->getBeginLoc(),
- E->getEndLoc(),
+ return getDerived().RebuildSourceLocExpr(E->getIdentKind(), E->getType(),
+ E->getBeginLoc(), E->getEndLoc(),
getSema().CurContext);
}
@@ -11907,9 +12074,9 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
// Transform the size of the array we're allocating (if any).
Optional<Expr *> ArraySize;
- if (Optional<Expr *> OldArraySize = E->getArraySize()) {
+ if (E->isArray()) {
ExprResult NewArraySize;
- if (*OldArraySize) {
+ if (Optional<Expr *> OldArraySize = E->getArraySize()) {
NewArraySize = getDerived().TransformExpr(*OldArraySize);
if (NewArraySize.isInvalid())
return ExprError();
@@ -12516,8 +12683,7 @@ TreeTransform<Derived>::TransformExprRequirement(concepts::ExprRequirement *Req)
return nullptr;
TransRetReq.emplace(TPL);
}
- assert(TransRetReq.hasValue() &&
- "All code paths leading here must set TransRetReq");
+ assert(TransRetReq && "All code paths leading here must set TransRetReq");
if (Expr *E = TransExpr.dyn_cast<Expr *>())
return getDerived().RebuildExprRequirement(E, Req->isSimple(),
Req->getNoexceptLoc(),
@@ -12743,6 +12909,9 @@ ExprResult TreeTransform<Derived>::TransformCXXInheritedCtorInitExpr(
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
+ if (auto *Dtor = E->getTemporary()->getDestructor())
+ SemaRef.MarkFunctionReferenced(E->getBeginLoc(),
+ const_cast<CXXDestructorDecl *>(Dtor));
return getDerived().TransformExpr(E->getSubExpr());
}
@@ -12922,14 +13091,24 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
NewTrailingRequiresClause = getDerived().TransformExpr(TRC);
// Create the local class that will describe the lambda.
- // FIXME: KnownDependent below is wrong when substituting inside a templated
- // context that isn't a DeclContext (such as a variable template).
+
+ // FIXME: DependencyKind below is wrong when substituting inside a templated
+ // context that isn't a DeclContext (such as a variable template), or when
+ // substituting an unevaluated lambda inside of a function's parameter's type
+ // - as parameter types are not instantiated from within a function's DC. We
+ // use isUnevaluatedContext() to distinguish the function parameter case.
+ CXXRecordDecl::LambdaDependencyKind DependencyKind =
+ CXXRecordDecl::LDK_Unknown;
+ if (getSema().isUnevaluatedContext() &&
+ (getSema().CurContext->isFileContext() ||
+ !getSema().CurContext->getParent()->isDependentContext()))
+ DependencyKind = CXXRecordDecl::LDK_NeverDependent;
+
CXXRecordDecl *OldClass = E->getLambdaClass();
- CXXRecordDecl *Class
- = getSema().createLambdaClosureType(E->getIntroducerRange(),
- NewCallOpTSI,
- /*KnownDependent=*/false,
- E->getCaptureDefault());
+ CXXRecordDecl *Class =
+ getSema().createLambdaClosureType(E->getIntroducerRange(), NewCallOpTSI,
+ DependencyKind, E->getCaptureDefault());
+
getDerived().transformedLocalDecl(OldClass, {Class});
Optional<std::tuple<bool, unsigned, unsigned, Decl *>> Mangling;
@@ -14621,7 +14800,7 @@ TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS,
bool TemplateKW,
TemplateDecl *Template) {
return SemaRef.Context.getQualifiedTemplateName(SS.getScopeRep(), TemplateKW,
- Template);
+ TemplateName(Template));
}
template<typename Derived>
@@ -14697,6 +14876,10 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
return getSema().CreateBuiltinArraySubscriptExpr(
First, Callee->getBeginLoc(), Second, OpLoc);
} else if (Op == OO_Arrow) {
+ // It is possible that the type refers to a RecoveryExpr created earlier
+ // in the tree transformation.
+ if (First->getType()->isDependentType())
+ return ExprError();
// -> is never a builtin operation.
return SemaRef.BuildOverloadedArrowExpr(nullptr, First, OpLoc);
} else if (Second == nullptr || isPostIncDec) {