diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2022-07-03 14:10:23 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2022-07-03 14:10:23 +0000 |
commit | 145449b1e420787bb99721a429341fa6be3adfb6 (patch) | |
tree | 1d56ae694a6de602e348dd80165cf881a36600ed /clang/lib/Sema | |
parent | ecbca9f5fb7d7613d2b94982c4825eb0d33d6842 (diff) | |
download | src-145449b1e420787bb99721a429341fa6be3adfb6.tar.gz src-145449b1e420787bb99721a429341fa6be3adfb6.zip |
Diffstat (limited to 'clang/lib/Sema')
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) { |