summaryrefslogtreecommitdiff
path: root/clang/lib/Sema
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2020-01-17 20:45:01 +0000
committerDimitry Andric <dim@FreeBSD.org>2020-01-17 20:45:01 +0000
commit706b4fc47bbc608932d3b491ae19a3b9cde9497b (patch)
tree4adf86a776049cbf7f69a1929c4babcbbef925eb /clang/lib/Sema
parent7cc9cf2bf09f069cb2dd947ead05d0b54301fb71 (diff)
Notes
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r--clang/lib/Sema/AnalysisBasedWarnings.cpp2
-rw-r--r--clang/lib/Sema/JumpDiagnostics.cpp4
-rw-r--r--clang/lib/Sema/MultiplexExternalSemaSource.cpp2
-rw-r--r--clang/lib/Sema/OpenCLBuiltins.td809
-rw-r--r--clang/lib/Sema/Sema.cpp22
-rw-r--r--clang/lib/Sema/SemaAccess.cpp23
-rw-r--r--clang/lib/Sema/SemaAttr.cpp8
-rw-r--r--clang/lib/Sema/SemaCUDA.cpp2
-rw-r--r--clang/lib/Sema/SemaCast.cpp27
-rw-r--r--clang/lib/Sema/SemaChecking.cpp777
-rw-r--r--clang/lib/Sema/SemaCodeComplete.cpp110
-rw-r--r--clang/lib/Sema/SemaConcept.cpp821
-rw-r--r--clang/lib/Sema/SemaCoroutine.cpp9
-rw-r--r--clang/lib/Sema/SemaDecl.cpp403
-rw-r--r--clang/lib/Sema/SemaDeclAttr.cpp347
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp1750
-rw-r--r--clang/lib/Sema/SemaDeclObjC.cpp182
-rw-r--r--clang/lib/Sema/SemaExceptionSpec.cpp357
-rw-r--r--clang/lib/Sema/SemaExpr.cpp515
-rw-r--r--clang/lib/Sema/SemaExprCXX.cpp565
-rw-r--r--clang/lib/Sema/SemaExprMember.cpp12
-rw-r--r--clang/lib/Sema/SemaExprObjC.cpp129
-rw-r--r--clang/lib/Sema/SemaInit.cpp212
-rw-r--r--clang/lib/Sema/SemaLambda.cpp16
-rw-r--r--clang/lib/Sema/SemaLookup.cpp41
-rw-r--r--clang/lib/Sema/SemaModule.cpp2
-rw-r--r--clang/lib/Sema/SemaObjCProperty.cpp143
-rw-r--r--clang/lib/Sema/SemaOpenMP.cpp1030
-rw-r--r--clang/lib/Sema/SemaOverload.cpp1363
-rw-r--r--clang/lib/Sema/SemaPseudoObject.cpp22
-rw-r--r--clang/lib/Sema/SemaStmt.cpp56
-rw-r--r--clang/lib/Sema/SemaStmtAsm.cpp20
-rw-r--r--clang/lib/Sema/SemaTemplate.cpp589
-rw-r--r--clang/lib/Sema/SemaTemplateDeduction.cpp278
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiate.cpp126
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiateDecl.cpp432
-rw-r--r--clang/lib/Sema/SemaTemplateVariadic.cpp4
-rw-r--r--clang/lib/Sema/SemaType.cpp314
-rw-r--r--clang/lib/Sema/TreeTransform.h158
39 files changed, 9087 insertions, 2595 deletions
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index 2c70c0599ecf..04611dadde66 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -1174,7 +1174,7 @@ namespace {
// We analyze lambda bodies separately. Skip them here.
bool TraverseLambdaExpr(LambdaExpr *LE) {
// Traverse the captures, but not the body.
- for (const auto &C : zip(LE->captures(), LE->capture_inits()))
+ for (const auto C : zip(LE->captures(), LE->capture_inits()))
TraverseLambdaCapture(LE, &std::get<0>(C), std::get<1>(C));
return true;
}
diff --git a/clang/lib/Sema/JumpDiagnostics.cpp b/clang/lib/Sema/JumpDiagnostics.cpp
index c8743df90e34..960e62d4a2db 100644
--- a/clang/lib/Sema/JumpDiagnostics.cpp
+++ b/clang/lib/Sema/JumpDiagnostics.cpp
@@ -546,8 +546,8 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S,
SmallVector<const Expr *, 4> CommaLHS;
SmallVector<SubobjectAdjustment, 4> Adjustments;
const Expr *ExtendedObject =
- MTE->GetTemporaryExpr()->skipRValueSubobjectAdjustments(
- CommaLHS, Adjustments);
+ MTE->getSubExpr()->skipRValueSubobjectAdjustments(CommaLHS,
+ Adjustments);
if (ExtendedObject->getType().isDestructedType()) {
Scopes.push_back(GotoScope(ParentScope, 0,
diag::note_exits_temporary_dtor,
diff --git a/clang/lib/Sema/MultiplexExternalSemaSource.cpp b/clang/lib/Sema/MultiplexExternalSemaSource.cpp
index b0aa67454a7b..2b0cd6b8c4fc 100644
--- a/clang/lib/Sema/MultiplexExternalSemaSource.cpp
+++ b/clang/lib/Sema/MultiplexExternalSemaSource.cpp
@@ -15,6 +15,8 @@
using namespace clang;
+char MultiplexExternalSemaSource::ID;
+
///Constructs a new multiplexing external sema source and appends the
/// given element to it.
///
diff --git a/clang/lib/Sema/OpenCLBuiltins.td b/clang/lib/Sema/OpenCLBuiltins.td
index 298614059467..9d6bb411eff8 100644
--- a/clang/lib/Sema/OpenCLBuiltins.td
+++ b/clang/lib/Sema/OpenCLBuiltins.td
@@ -40,6 +40,30 @@ def ConstantAS : AddressSpace<"clang::LangAS::opencl_constant">;
def LocalAS : AddressSpace<"clang::LangAS::opencl_local">;
def GenericAS : AddressSpace<"clang::LangAS::opencl_generic">;
+// OpenCL language extension.
+class AbstractExtension<string _Ext> {
+ // One or more OpenCL extensions, space separated. Each extension must be
+ // a valid extension name for the opencl extension pragma.
+ string ExtName = _Ext;
+}
+
+// Extension associated to a builtin function.
+class FunctionExtension<string _Ext> : AbstractExtension<_Ext>;
+
+// FunctionExtension definitions.
+def FuncExtNone : FunctionExtension<"">;
+def FuncExtKhrSubgroups : FunctionExtension<"cl_khr_subgroups">;
+def FuncExtKhrGlobalInt32BaseAtomics : FunctionExtension<"cl_khr_global_int32_base_atomics">;
+def FuncExtKhrGlobalInt32ExtendedAtomics : FunctionExtension<"cl_khr_global_int32_extended_atomics">;
+def FuncExtKhrLocalInt32BaseAtomics : FunctionExtension<"cl_khr_local_int32_base_atomics">;
+def FuncExtKhrLocalInt32ExtendedAtomics : FunctionExtension<"cl_khr_local_int32_extended_atomics">;
+def FuncExtKhrInt64BaseAtomics : FunctionExtension<"cl_khr_int64_base_atomics">;
+def FuncExtKhrInt64ExtendedAtomics : FunctionExtension<"cl_khr_int64_extended_atomics">;
+def FuncExtKhrMipmapImage : FunctionExtension<"cl_khr_mipmap_image">;
+def FuncExtKhrGlMsaaSharing : FunctionExtension<"cl_khr_gl_msaa_sharing">;
+
+// Multiple extensions
+def FuncExtKhrMipmapAndWrite3d : FunctionExtension<"cl_khr_mipmap_image cl_khr_3d_image_writes">;
// Qualified Type. These map to ASTContext::QualType.
class QualType<string _Name, bit _IsAbstract=0> {
@@ -180,18 +204,32 @@ class GenericType<string _Ty, TypeList _TypeList, IntList _VectorList> :
let VecWidth = 0;
}
+// Builtin function attributes.
+def Attr {
+ list<bit> None = [0, 0, 0];
+ list<bit> Pure = [1, 0, 0];
+ list<bit> Const = [0, 1, 0];
+ list<bit> Convergent = [0, 0, 1];
+}
+
//===----------------------------------------------------------------------===//
// OpenCL C class for builtin functions
//===----------------------------------------------------------------------===//
-class Builtin<string _Name, list<Type> _Signature> {
+class Builtin<string _Name, list<Type> _Signature, list<bit> _Attributes = Attr.None> {
// Name of the builtin function
string Name = _Name;
// List of types used by the function. The first one is the return type and
// the following are the arguments. The list must have at least one element
// (the return type).
list<Type> Signature = _Signature;
- // OpenCL Extension to which the function belongs (cl_khr_subgroups, ...)
- string Extension = "";
+ // Function attribute __attribute__((pure))
+ bit IsPure = _Attributes[0];
+ // Function attribute __attribute__((const))
+ bit IsConst = _Attributes[1];
+ // Function attribute __attribute__((convergent))
+ bit IsConv = _Attributes[2];
+ // OpenCL extensions to which the function belongs.
+ FunctionExtension Extension = FuncExtNone;
// Version of OpenCL from which the function is available (e.g.: CL10).
// MinVersion is inclusive.
Version MinVersion = CL10;
@@ -260,10 +298,25 @@ def Event : Type<"Event", QualType<"OCLEventTy">>;
def VecAndScalar: IntList<"VecAndScalar", [1, 2, 3, 4, 8, 16]>;
def VecNoScalar : IntList<"VecNoScalar", [2, 3, 4, 8, 16]>;
def Vec1 : IntList<"Vec1", [1]>;
+def Vec2 : IntList<"Vec2", [2]>;
+def Vec4 : IntList<"Vec4", [4]>;
+def Vec8 : IntList<"Vec8", [8]>;
+def Vec16 : IntList<"Vec16", [16]>;
+def Vec1234 : IntList<"Vec1234", [1, 2, 3, 4]>;
// Type lists.
-def TLAll : TypeList<"TLAll", [Char, UChar, Short, UShort, Int, UInt, Long, ULong, Float, Double, Half]>;
+def TLAll : TypeList<"TLAll", [Char, UChar, Short, UShort, Int, UInt, Long, ULong, Float, Double, Half]>;
+def TLAllUnsigned : TypeList<"TLAllUnsigned", [UChar, UChar, UShort, UShort, UInt, UInt, ULong, ULong, UInt, ULong, UShort]>;
def TLFloat : TypeList<"TLFloat", [Float, Double, Half]>;
+def TLSignedInts : TypeList<"TLSignedInts", [Char, Short, Int, Long]>;
+def TLUnsignedInts : TypeList<"TLUnsignedInts", [UChar, UShort, UInt, ULong]>;
+
+def TLIntLongFloats : TypeList<"TLIntLongFloats", [Int, UInt, Long, ULong, Float, Double, Half]>;
+
+// All unsigned integer types twice, to facilitate unsigned return types for e.g.
+// uchar abs(char) and
+// uchar abs(uchar).
+def TLAllUIntsTwice : TypeList<"TLAllUIntsTwice", [UChar, UChar, UShort, UShort, UInt, UInt, ULong, ULong]>;
def TLAllInts : TypeList<"TLAllInts", [Char, UChar, Short, UShort, Int, UInt, Long, ULong]>;
@@ -276,8 +329,16 @@ def AGenTypeNNoScalar : GenericType<"AGenTypeNNoScalar", TLAll, VecNoScalar
def AIGenType1 : GenericType<"AIGenType1", TLAllInts, Vec1>;
def AIGenTypeN : GenericType<"AIGenTypeN", TLAllInts, VecAndScalar>;
def AIGenTypeNNoScalar : GenericType<"AIGenTypeNNoScalar", TLAllInts, VecNoScalar>;
+// All integer to unsigned
+def AI2UGenTypeN : GenericType<"AI2UGenTypeN", TLAllUIntsTwice, VecAndScalar>;
+// Signed integer
+def SGenTypeN : GenericType<"SGenTypeN", TLSignedInts, VecAndScalar>;
+// Unsigned integer
+def UGenTypeN : GenericType<"UGenTypeN", TLUnsignedInts, VecAndScalar>;
// Float
def FGenTypeN : GenericType<"FGenTypeN", TLFloat, VecAndScalar>;
+// (u)int, (u)long, and all floats
+def IntLongFloatGenType1 : GenericType<"IntLongFloatGenType1", TLIntLongFloats, Vec1>;
// GenType definitions for every single base type (e.g. fp32 only).
// Names are like: GenTypeFloatVecAndScalar.
@@ -292,6 +353,14 @@ foreach Type = [Char, UChar, Short, UShort,
}
}
+// GenType definitions for vec1234.
+foreach Type = [Float, Double, Half] in {
+ def "GenType" # Type # Vec1234 :
+ GenericType<"GenType" # Type # Vec1234,
+ TypeList<"GL" # Type.Name, [Type]>,
+ Vec1234>;
+}
+
//===----------------------------------------------------------------------===//
// Definitions of OpenCL builtin functions
@@ -307,11 +376,12 @@ foreach RType = [Float, Double, Half, Char, UChar, Short,
UShort, Int, UInt, Long, ULong] in {
foreach sat = ["", "_sat"] in {
foreach rnd = ["", "_rte", "_rtn", "_rtp", "_rtz"] in {
- def : Builtin<"convert_" # RType.Name # sat # rnd, [RType, IType]>;
+ def : Builtin<"convert_" # RType.Name # sat # rnd, [RType, IType],
+ Attr.Const>;
foreach v = [2, 3, 4, 8, 16] in {
def : Builtin<"convert_" # RType.Name # v # sat # rnd,
- [VectorType<RType, v>,
- VectorType<IType, v>]>;
+ [VectorType<RType, v>, VectorType<IType, v>],
+ Attr.Const>;
}
}
}
@@ -321,11 +391,11 @@ foreach RType = [Float, Double, Half, Char, UChar, Short,
//--------------------------------------------------------------------
// OpenCL v1.1 s6.11.1, v1.2 s6.12.1, v2.0 s6.13.1 - Work-item Functions
// --- Table 7 ---
-def : Builtin<"get_work_dim", [UInt]>;
+def : Builtin<"get_work_dim", [UInt], Attr.Const>;
foreach name = ["get_global_size", "get_global_id", "get_local_size",
"get_local_id", "get_num_groups", "get_group_id",
"get_global_offset"] in {
- def : Builtin<name, [Size, UInt]>;
+ def : Builtin<name, [Size, UInt], Attr.Const>;
}
let MinVersion = CL20 in {
@@ -335,9 +405,303 @@ let MinVersion = CL20 in {
}
}
+
+//--------------------------------------------------------------------
+// OpenCL v1.1 s6.11.2, v1.2 s6.12.2, v2.0 s6.13.2 - Math functions
+// OpenCL Extension v2.0 s5.1.2 and s6.1.2 - Math Functions
+// --- Table 8 ---
+// --- 1 argument ---
+foreach name = ["acos", "acosh", "acospi",
+ "asin", "asinh", "asinpi",
+ "atan", "atanh", "atanpi",
+ "cbrt", "ceil",
+ "cos", "cosh", "cospi",
+ "erfc", "erf",
+ "exp", "exp2", "exp10", "expm1",
+ "fabs", "floor",
+ "log", "log2", "log10", "log1p", "logb",
+ "rint", "round", "rsqrt",
+ "sin", "sinh", "sinpi",
+ "sqrt",
+ "tan", "tanh", "tanpi",
+ "tgamma", "trunc",
+ "lgamma"] in {
+ def : Builtin<name, [FGenTypeN, FGenTypeN], Attr.Const>;
+}
+foreach name = ["nan"] in {
+ def : Builtin<name, [GenTypeFloatVecAndScalar, GenTypeUIntVecAndScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeDoubleVecAndScalar, GenTypeULongVecAndScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeHalfVecAndScalar, GenTypeUShortVecAndScalar], Attr.Const>;
+}
+
+// --- 2 arguments ---
+foreach name = ["atan2", "atan2pi", "copysign", "fdim", "fmod", "hypot",
+ "maxmag", "minmag", "nextafter", "pow", "powr",
+ "remainder"] in {
+ def : Builtin<name, [FGenTypeN, FGenTypeN, FGenTypeN], Attr.Const>;
+}
+foreach name = ["fmax", "fmin"] in {
+ def : Builtin<name, [FGenTypeN, FGenTypeN, FGenTypeN], Attr.Const>;
+ def : Builtin<name, [GenTypeFloatVecNoScalar, GenTypeFloatVecNoScalar, Float], Attr.Const>;
+ def : Builtin<name, [GenTypeDoubleVecNoScalar, GenTypeDoubleVecNoScalar, Double], Attr.Const>;
+ def : Builtin<name, [GenTypeHalfVecNoScalar, GenTypeHalfVecNoScalar, Half], Attr.Const>;
+}
+foreach name = ["ilogb"] in {
+ def : Builtin<name, [GenTypeIntVecAndScalar, GenTypeFloatVecAndScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeIntVecAndScalar, GenTypeDoubleVecAndScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeIntVecAndScalar, GenTypeHalfVecAndScalar], Attr.Const>;
+}
+foreach name = ["ldexp"] in {
+ def : Builtin<name, [GenTypeFloatVecAndScalar, GenTypeFloatVecAndScalar, GenTypeIntVecAndScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeFloatVecNoScalar, GenTypeFloatVecNoScalar, Int], Attr.Const>;
+ def : Builtin<name, [GenTypeDoubleVecAndScalar, GenTypeDoubleVecAndScalar, GenTypeIntVecAndScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeDoubleVecNoScalar, GenTypeDoubleVecNoScalar, Int], Attr.Const>;
+ def : Builtin<name, [GenTypeHalfVecAndScalar, GenTypeHalfVecAndScalar, GenTypeIntVecAndScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeHalfVecNoScalar, GenTypeHalfVecNoScalar, Int], Attr.Const>;
+}
+foreach name = ["pown", "rootn"] in {
+ def : Builtin<name, [GenTypeFloatVecAndScalar, GenTypeFloatVecAndScalar, GenTypeIntVecAndScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeDoubleVecAndScalar, GenTypeDoubleVecAndScalar, GenTypeIntVecAndScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeHalfVecAndScalar, GenTypeHalfVecAndScalar, GenTypeIntVecAndScalar], Attr.Const>;
+}
+
+// --- 3 arguments ---
+foreach name = ["fma", "mad"] in {
+ def : Builtin<name, [FGenTypeN, FGenTypeN, FGenTypeN, FGenTypeN], Attr.Const>;
+}
+
+// --- Version dependent ---
+let MaxVersion = CL20 in {
+ foreach AS = [GlobalAS, LocalAS, PrivateAS] in {
+ foreach name = ["fract", "modf", "sincos"] in {
+ def : Builtin<name, [FGenTypeN, FGenTypeN, PointerType<FGenTypeN, AS>]>;
+ }
+ foreach name = ["frexp", "lgamma_r"] in {
+ foreach Type = [GenTypeFloatVecAndScalar, GenTypeDoubleVecAndScalar, GenTypeHalfVecAndScalar] in {
+ def : Builtin<name, [Type, Type, PointerType<GenTypeIntVecAndScalar, AS>]>;
+ }
+ }
+ foreach name = ["remquo"] in {
+ foreach Type = [GenTypeFloatVecAndScalar, GenTypeDoubleVecAndScalar, GenTypeHalfVecAndScalar] in {
+ def : Builtin<name, [Type, Type, Type, PointerType<GenTypeIntVecAndScalar, AS>]>;
+ }
+ }
+ }
+}
+let MinVersion = CL20 in {
+ foreach name = ["fract", "modf", "sincos"] in {
+ def : Builtin<name, [FGenTypeN, FGenTypeN, PointerType<FGenTypeN, GenericAS>]>;
+ }
+ foreach name = ["frexp", "lgamma_r"] in {
+ foreach Type = [GenTypeFloatVecAndScalar, GenTypeDoubleVecAndScalar, GenTypeHalfVecAndScalar] in {
+ def : Builtin<name, [Type, Type, PointerType<GenTypeIntVecAndScalar, GenericAS>]>;
+ } }
+ foreach name = ["remquo"] in {
+ foreach Type = [GenTypeFloatVecAndScalar, GenTypeDoubleVecAndScalar, GenTypeHalfVecAndScalar] in {
+ def : Builtin<name, [Type, Type, Type, PointerType<GenTypeIntVecAndScalar, GenericAS>]>;
+ }
+ }
+}
+
+// --- Table 9 ---
+foreach name = ["half_cos",
+ "half_exp", "half_exp2", "half_exp10",
+ "half_log", "half_log2", "half_log10",
+ "half_recip", "half_rsqrt",
+ "half_sin", "half_sqrt", "half_tan",
+ "native_cos",
+ "native_exp", "native_exp2", "native_exp10",
+ "native_log", "native_log2", "native_log10",
+ "native_recip", "native_rsqrt",
+ "native_sin", "native_sqrt", "native_tan"] in {
+ def : Builtin<name, [GenTypeFloatVecAndScalar, GenTypeFloatVecAndScalar], Attr.Const>;
+}
+foreach name = ["half_divide", "half_powr",
+ "native_divide", "native_powr"] in {
+ def : Builtin<name, [GenTypeFloatVecAndScalar, GenTypeFloatVecAndScalar, GenTypeFloatVecAndScalar], Attr.Const>;
+}
+
+//--------------------------------------------------------------------
+// OpenCL v1.1 s6.11.3, v1.2 s6.12.3, v2.0 s6.13.3 - Integer Functions
+// --- Table 10 ---
+// --- 1 argument ---
+foreach name = ["abs"] in {
+ def : Builtin<name, [AI2UGenTypeN, AIGenTypeN], Attr.Const>;
+}
+foreach name = ["clz", "popcount"] in {
+ def : Builtin<name, [AIGenTypeN, AIGenTypeN], Attr.Const>;
+}
+let MinVersion = CL20 in {
+ foreach name = ["ctz"] in {
+ def : Builtin<name, [AIGenTypeN, AIGenTypeN]>;
+ }
+}
+
+// --- 2 arguments ---
+foreach name = ["abs_diff"] in {
+ def : Builtin<name, [AI2UGenTypeN, AIGenTypeN, AIGenTypeN], Attr.Const>;
+}
+foreach name = ["add_sat", "hadd", "rhadd", "mul_hi", "rotate", "sub_sat"] in {
+ def : Builtin<name, [AIGenTypeN, AIGenTypeN, AIGenTypeN], Attr.Const>;
+}
+foreach name = ["max", "min"] in {
+ def : Builtin<name, [AIGenTypeN, AIGenTypeN, AIGenTypeN], Attr.Const>;
+ def : Builtin<name, [AIGenTypeNNoScalar, AIGenTypeNNoScalar, AIGenType1], Attr.Const>;
+}
+foreach name = ["upsample"] in {
+ def : Builtin<name, [GenTypeShortVecAndScalar, GenTypeCharVecAndScalar, GenTypeUCharVecAndScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeUShortVecAndScalar, GenTypeUCharVecAndScalar, GenTypeUCharVecAndScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeIntVecAndScalar, GenTypeShortVecAndScalar, GenTypeUShortVecAndScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeUIntVecAndScalar, GenTypeUShortVecAndScalar, GenTypeUShortVecAndScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeLongVecAndScalar, GenTypeIntVecAndScalar, GenTypeUIntVecAndScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeULongVecAndScalar, GenTypeUIntVecAndScalar, GenTypeUIntVecAndScalar], Attr.Const>;
+}
+
+// --- 3 arguments ---
+foreach name = ["clamp"] in {
+ def : Builtin<name, [AIGenTypeN, AIGenTypeN, AIGenTypeN, AIGenTypeN], Attr.Const>;
+ def : Builtin<name, [AIGenTypeNNoScalar, AIGenTypeNNoScalar, AIGenType1, AIGenType1], Attr.Const>;
+}
+foreach name = ["mad_hi", "mad_sat"] in {
+ def : Builtin<name, [AIGenTypeN, AIGenTypeN, AIGenTypeN, AIGenTypeN], Attr.Const>;
+}
+
+// --- Table 11 ---
+foreach name = ["mad24"] in {
+ def : Builtin<name, [GenTypeIntVecAndScalar, GenTypeIntVecAndScalar, GenTypeIntVecAndScalar, GenTypeIntVecAndScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeUIntVecAndScalar, GenTypeUIntVecAndScalar, GenTypeUIntVecAndScalar, GenTypeUIntVecAndScalar], Attr.Const>;
+}
+foreach name = ["mul24"] in {
+ def : Builtin<name, [GenTypeIntVecAndScalar, GenTypeIntVecAndScalar, GenTypeIntVecAndScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeUIntVecAndScalar, GenTypeUIntVecAndScalar, GenTypeUIntVecAndScalar], Attr.Const>;
+}
+
+//--------------------------------------------------------------------
+// OpenCL v1.1 s6.11.4, v1.2 s6.12.4, v2.0 s6.13.4 - Common Functions
+// OpenCL Extension v2.0 s5.1.3 and s6.1.3 - Common Functions
+// --- Table 12 ---
+// --- 1 argument ---
+foreach name = ["degrees", "radians", "sign"] in {
+ def : Builtin<name, [FGenTypeN, FGenTypeN], Attr.Const>;
+}
+
+// --- 2 arguments ---
+foreach name = ["max", "min"] in {
+ def : Builtin<name, [FGenTypeN, FGenTypeN, FGenTypeN], Attr.Const>;
+ def : Builtin<name, [GenTypeFloatVecNoScalar, GenTypeFloatVecNoScalar, Float], Attr.Const>;
+ def : Builtin<name, [GenTypeDoubleVecNoScalar, GenTypeDoubleVecNoScalar, Double], Attr.Const>;
+ def : Builtin<name, [GenTypeHalfVecNoScalar, GenTypeHalfVecNoScalar, Half], Attr.Const>;
+}
+foreach name = ["step"] in {
+ def : Builtin<name, [FGenTypeN, FGenTypeN, FGenTypeN], Attr.Const>;
+ def : Builtin<name, [GenTypeFloatVecNoScalar, Float, GenTypeFloatVecNoScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeDoubleVecNoScalar, Double, GenTypeDoubleVecNoScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeHalfVecNoScalar, Half, GenTypeHalfVecNoScalar], Attr.Const>;
+}
+
+// --- 3 arguments ---
+foreach name = ["clamp", "mix"] in {
+ def : Builtin<name, [FGenTypeN, FGenTypeN, FGenTypeN, FGenTypeN], Attr.Const>;
+ def : Builtin<name, [GenTypeFloatVecNoScalar, GenTypeFloatVecNoScalar, Float, Float], Attr.Const>;
+ def : Builtin<name, [GenTypeDoubleVecNoScalar, GenTypeDoubleVecNoScalar, Double, Double], Attr.Const>;
+ def : Builtin<name, [GenTypeHalfVecNoScalar, GenTypeHalfVecNoScalar, Half, Half], Attr.Const>;
+}
+foreach name = ["smoothstep"] in {
+ def : Builtin<name, [FGenTypeN, FGenTypeN, FGenTypeN, FGenTypeN], Attr.Const>;
+ def : Builtin<name, [GenTypeFloatVecNoScalar, Float, Float, GenTypeFloatVecNoScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeDoubleVecNoScalar, Double, Double, GenTypeDoubleVecNoScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeHalfVecNoScalar, Half, Half, GenTypeHalfVecNoScalar], Attr.Const>;
+}
+
+
+//--------------------------------------------------------------------
+// OpenCL v1.1 s6.11.5, v1.2 s6.12.5, v2.0 s6.13.5 - Geometric Functions
+// OpenCL Extension v2.0 s5.1.4 and s6.1.4 - Geometric Functions
+// --- Table 13 ---
+// --- 1 argument ---
+foreach name = ["length"] in {
+ def : Builtin<name, [Float, GenTypeFloatVec1234], Attr.Const>;
+ def : Builtin<name, [Double, GenTypeDoubleVec1234], Attr.Const>;
+ def : Builtin<name, [Half, GenTypeHalfVec1234], Attr.Const>;
+}
+foreach name = ["normalize"] in {
+ def : Builtin<name, [GenTypeFloatVec1234, GenTypeFloatVec1234], Attr.Const>;
+ def : Builtin<name, [GenTypeDoubleVec1234, GenTypeDoubleVec1234], Attr.Const>;
+ def : Builtin<name, [GenTypeHalfVec1234, GenTypeHalfVec1234], Attr.Const>;
+}
+foreach name = ["fast_length"] in {
+ def : Builtin<name, [Float, GenTypeFloatVec1234], Attr.Const>;
+}
+foreach name = ["fast_normalize"] in {
+ def : Builtin<name, [GenTypeFloatVec1234, GenTypeFloatVec1234], Attr.Const>;
+}
+
+// --- 2 arguments ---
+foreach name = ["cross"] in {
+ foreach VSize = [3, 4] in {
+ def : Builtin<name, [VectorType<Float, VSize>, VectorType<Float, VSize>, VectorType<Float, VSize>], Attr.Const>;
+ def : Builtin<name, [VectorType<Double, VSize>, VectorType<Double, VSize>, VectorType<Double, VSize>], Attr.Const>;
+ def : Builtin<name, [VectorType<Half, VSize>, VectorType<Half, VSize>, VectorType<Half, VSize>], Attr.Const>;
+ }
+}
+foreach name = ["dot", "distance"] in {
+ def : Builtin<name, [Float, GenTypeFloatVec1234, GenTypeFloatVec1234], Attr.Const>;
+ def : Builtin<name, [Double, GenTypeDoubleVec1234, GenTypeDoubleVec1234], Attr.Const>;
+ def : Builtin<name, [Half, GenTypeHalfVec1234, GenTypeHalfVec1234], Attr.Const>;
+}
+foreach name = ["fast_distance"] in {
+ def : Builtin<name, [Float, GenTypeFloatVec1234, GenTypeFloatVec1234], Attr.Const>;
+}
+
+
+//--------------------------------------------------------------------
+// OpenCL v1.1 s6.11.6, v1.2 s6.12.6, v2.0 s6.13.6 - Relational Functions
+// OpenCL Extension v2.0 s5.1.5 and s6.1.5 - Relational Functions
+// --- Table 14 ---
+// --- 1 argument ---
+foreach name = ["isfinite", "isinf", "isnan", "isnormal", "signbit"] in {
+ def : Builtin<name, [GenTypeIntVecAndScalar, GenTypeFloatVecAndScalar], Attr.Const>;
+ def : Builtin<name, [Int, Double], Attr.Const>;
+ def : Builtin<name, [GenTypeLongVecNoScalar, GenTypeDoubleVecNoScalar], Attr.Const>;
+ def : Builtin<name, [Int, Half], Attr.Const>;
+ def : Builtin<name, [GenTypeShortVecNoScalar, GenTypeHalfVecNoScalar], Attr.Const>;
+}
+foreach name = ["any", "all"] in {
+ def : Builtin<name, [Int, AIGenTypeN], Attr.Const>;
+}
+
+// --- 2 arguments ---
+foreach name = ["isequal", "isnotequal", "isgreater", "isgreaterequal",
+ "isless", "islessequal", "islessgreater", "isordered",
+ "isunordered"] in {
+ def : Builtin<name, [GenTypeIntVecAndScalar, GenTypeFloatVecAndScalar, GenTypeFloatVecAndScalar], Attr.Const>;
+ def : Builtin<name, [Int, Double, Double], Attr.Const>;
+ def : Builtin<name, [GenTypeLongVecNoScalar, GenTypeDoubleVecNoScalar, GenTypeDoubleVecNoScalar], Attr.Const>;
+ def : Builtin<name, [Int, Half, Half], Attr.Const>;
+ def : Builtin<name, [GenTypeShortVecNoScalar, GenTypeHalfVecNoScalar, GenTypeHalfVecNoScalar], Attr.Const>;
+}
+
+// --- 3 arguments ---
+foreach name = ["bitselect"] in {
+ def : Builtin<name, [AGenTypeN, AGenTypeN, AGenTypeN, AGenTypeN], Attr.Const>;
+}
+foreach name = ["select"] in {
+ def : Builtin<name, [SGenTypeN, SGenTypeN, SGenTypeN, SGenTypeN], Attr.Const>;
+ def : Builtin<name, [SGenTypeN, SGenTypeN, SGenTypeN, UGenTypeN], Attr.Const>;
+ def : Builtin<name, [UGenTypeN, UGenTypeN, UGenTypeN, UGenTypeN], Attr.Const>;
+ def : Builtin<name, [UGenTypeN, UGenTypeN, UGenTypeN, SGenTypeN], Attr.Const>;
+ def : Builtin<name, [GenTypeFloatVecAndScalar, GenTypeFloatVecAndScalar, GenTypeFloatVecAndScalar, GenTypeIntVecAndScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeFloatVecAndScalar, GenTypeFloatVecAndScalar, GenTypeFloatVecAndScalar, GenTypeUIntVecAndScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeDoubleVecAndScalar, GenTypeDoubleVecAndScalar, GenTypeDoubleVecAndScalar, GenTypeLongVecAndScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeDoubleVecAndScalar, GenTypeDoubleVecAndScalar, GenTypeDoubleVecAndScalar, GenTypeULongVecAndScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeHalfVecAndScalar, GenTypeHalfVecAndScalar, GenTypeHalfVecAndScalar, GenTypeShortVecAndScalar], Attr.Const>;
+ def : Builtin<name, [GenTypeHalfVecAndScalar, GenTypeHalfVecAndScalar, GenTypeHalfVecAndScalar, GenTypeUShortVecAndScalar], Attr.Const>;
+}
+
+
//--------------------------------------------------------------------
// OpenCL v1.1 s6.11.7, v1.2 s6.12.7, v2.0 s6.13.7 - Vector Data Load and Store Functions
-// OpenCL Extension v1.1 s9.3.6 and s9.6.6, v1.2 s9.5.6, v2.0 s9.4.6, v2.0 s5.1.6 and 6.1.6 - Vector Data Load and Store Functions
+// OpenCL Extension v1.1 s9.3.6 and s9.6.6, v1.2 s9.5.6, v2.0 s5.1.6 and s6.1.6 - Vector Data Load and Store Functions
// --- Table 15 ---
// Variants for OpenCL versions below 2.0, using pointers to the global, local
// and private address spaces.
@@ -448,6 +812,55 @@ foreach VSize = [2, 3, 4, 8, 16] in {
}
}
}
+let MaxVersion = CL20 in {
+ foreach AS = [GlobalAS, LocalAS, PrivateAS] in {
+ def : Builtin<"vload_half", [Float, Size, PointerType<ConstType<Half>, AS>]>;
+ foreach VSize = [2, 3, 4, 8, 16] in {
+ foreach name = ["vload_half" # VSize] in {
+ def : Builtin<name, [VectorType<Float, VSize>, Size, PointerType<ConstType<Half>, AS>]>;
+ }
+ }
+ foreach rnd = ["", "_rte", "_rtz", "_rtp", "_rtn"] in {
+ def : Builtin<"vstore_half" # rnd, [Void, Float, Size, PointerType<Half, AS>]>;
+ def : Builtin<"vstore_half" # rnd, [Void, Double, Size, PointerType<Half, AS>]>;
+ foreach VSize = [2, 3, 4, 8, 16] in {
+ foreach name = ["vstore_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>]>;
+ }
+ }
+ }
+ }
+}
+let MinVersion = CL20 in {
+ foreach AS = [GenericAS] in {
+ def : Builtin<"vload_half", [Float, Size, PointerType<ConstType<Half>, AS>]>;
+ foreach VSize = [2, 3, 4, 8, 16] in {
+ foreach name = ["vload_half" # VSize] in {
+ def : Builtin<name, [VectorType<Float, VSize>, Size, PointerType<ConstType<Half>, AS>]>;
+ }
+ }
+ foreach rnd = ["", "_rte", "_rtz", "_rtp", "_rtn"] in {
+ def : Builtin<"vstore_half" # rnd, [Void, Float, Size, PointerType<Half, AS>]>;
+ def : Builtin<"vstore_half" # rnd, [Void, Double, Size, PointerType<Half, AS>]>;
+ foreach VSize = [2, 3, 4, 8, 16] in {
+ foreach name = ["vstore_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>]>;
+ }
+ }
+ }
+ }
+}
+
+foreach AS = [ConstantAS] in {
+ def : Builtin<"vload_half", [Float, Size, PointerType<ConstType<Half>, AS>]>;
+ foreach VSize = [2, 3, 4, 8, 16] in {
+ foreach name = ["vload_half" # VSize] in {
+ def : Builtin<name, [VectorType<Float, VSize>, Size, PointerType<ConstType<Half>, AS>]>;
+ }
+ }
+}
//--------------------------------------------------------------------
// OpenCL v1.1 s6.11.10, v1.2 s6.12.10, v2.0 s6.13.10: Async Copies from Global to Local Memory, Local to Global Memory, and Prefetch
@@ -473,42 +886,116 @@ foreach name = ["prefetch"] in {
// Functions that use memory_order and cl_mem_fence_flags enums are not
// declared here as the TableGen backend does not handle enums.
-// OpenCL v1.0 s9.5, s9.6, s9.7 - Atomic Functions for 32-bit integers.
+// OpenCL v1.0 s9.5, s9.6, s9.7 - Atomic Functions for 32-bit integers
// --- Table 9.1 ---
-foreach Type = [Int, UInt] in {
- foreach name = ["atom_add", "atom_sub", "atom_xchg"] in {
- def : Builtin<name, [Type, PointerType<VolatileType<Type>, GlobalAS>, Type]>;
+let Extension = FuncExtKhrGlobalInt32BaseAtomics in {
+ foreach Type = [Int, UInt] in {
+ foreach name = ["atom_add", "atom_sub", "atom_xchg"] in {
+ def : Builtin<name, [Type, PointerType<VolatileType<Type>, GlobalAS>, Type]>;
+ }
+ foreach name = ["atom_inc", "atom_dec"] in {
+ def : Builtin<name, [Type, PointerType<VolatileType<Type>, GlobalAS>]>;
+ }
+ foreach name = ["atom_cmpxchg"] in {
+ def : Builtin<name, [Type, PointerType<VolatileType<Type>, GlobalAS>, Type, Type]>;
+ }
+ }
+}
+// --- Table 9.3 ---
+let Extension = FuncExtKhrLocalInt32BaseAtomics in {
+ foreach Type = [Int, UInt] in {
+ foreach name = ["atom_add", "atom_sub", "atom_xchg"] in {
+ def : Builtin<name, [Type, PointerType<VolatileType<Type>, LocalAS>, Type]>;
+ }
+ foreach name = ["atom_inc", "atom_dec"] in {
+ def : Builtin<name, [Type, PointerType<VolatileType<Type>, LocalAS>]>;
+ }
+ foreach name = ["atom_cmpxchg"] in {
+ def : Builtin<name, [Type, PointerType<VolatileType<Type>, LocalAS>, Type, Type]>;
+ }
+ }
+}
+// --- Table 9.5 ---
+let Extension = FuncExtKhrInt64BaseAtomics in {
+ foreach AS = [GlobalAS, LocalAS] in {
+ foreach Type = [Long, ULong] in {
+ foreach name = ["atom_add", "atom_sub", "atom_xchg"] in {
+ def : Builtin<name, [Type, PointerType<VolatileType<Type>, AS>, Type]>;
+ }
+ foreach name = ["atom_inc", "atom_dec"] in {
+ def : Builtin<name, [Type, PointerType<VolatileType<Type>, AS>]>;
+ }
+ foreach name = ["atom_cmpxchg"] in {
+ def : Builtin<name, [Type, PointerType<VolatileType<Type>, AS>, Type, Type]>;
+ }
+ }
}
- foreach name = ["atom_inc", "atom_dec"] in {
- def : Builtin<name, [Type, PointerType<VolatileType<Type>, GlobalAS>]>;
+}
+// --- Table 9.2 ---
+let Extension = FuncExtKhrGlobalInt32ExtendedAtomics in {
+ foreach Type = [Int, UInt] in {
+ foreach name = ["atom_min", "atom_max", "atom_and",
+ "atom_or", "atom_xor"] in {
+ def : Builtin<name, [Type, PointerType<VolatileType<Type>, GlobalAS>, Type]>;
+ }
}
- foreach name = ["atom_cmpxchg"] in {
- def : Builtin<name, [Type, PointerType<VolatileType<Type>, GlobalAS>, Type, Type]>;
+}
+// --- Table 9.4 ---
+let Extension = FuncExtKhrLocalInt32ExtendedAtomics in {
+ foreach Type = [Int, UInt] in {
+ foreach name = ["atom_min", "atom_max", "atom_and",
+ "atom_or", "atom_xor"] in {
+ def : Builtin<name, [Type, PointerType<VolatileType<Type>, LocalAS>, Type]>;
+ }
}
}
-
-// OpenCL v1.2 s6.12.2: Math Functions
-foreach name = ["acos", "acosh", "acospi",
- "asin", "asinh", "asinpi",
- "atan", "atanh", "atanpi"] in {
- def : Builtin<name, [FGenTypeN, FGenTypeN]>;
+// --- Table 9.6 ---
+let Extension = FuncExtKhrInt64ExtendedAtomics in {
+ foreach AS = [GlobalAS, LocalAS] in {
+ foreach Type = [Long, ULong] in {
+ foreach name = ["atom_min", "atom_max", "atom_and",
+ "atom_or", "atom_xor"] in {
+ def : Builtin<name, [Type, PointerType<VolatileType<Type>, AS>, Type]>;
+ }
+ }
+ }
}
-
-foreach name = ["atan2", "atan2pi"] in {
- def : Builtin<name, [FGenTypeN, FGenTypeN, FGenTypeN]>;
+// OpenCL v1.1 s6.11.1, v1.2 s6.12.11 - Atomic Functions
+foreach AS = [GlobalAS, LocalAS] in {
+ foreach Type = [Int, UInt] in {
+ foreach name = ["atomic_add", "atomic_sub", "atomic_xchg",
+ "atomic_min", "atomic_max", "atomic_and",
+ "atomic_or", "atomic_xor"] in {
+ def : Builtin<name, [Type, PointerType<VolatileType<Type>, AS>, Type]>;
+ }
+ foreach name = ["atomic_inc", "atomic_dec"] in {
+ def : Builtin<name, [Type, PointerType<VolatileType<Type>, AS>]>;
+ }
+ foreach name = ["atomic_cmpxchg"] in {
+ def : Builtin<name, [Type, PointerType<VolatileType<Type>, AS>, Type, Type]>;
+ }
+ }
}
-foreach name = ["fmax", "fmin"] in {
- def : Builtin<name, [FGenTypeN, FGenTypeN, FGenTypeN]>;
- def : Builtin<name, [GenTypeFloatVecNoScalar, GenTypeFloatVecNoScalar, Float]>;
- def : Builtin<name, [GenTypeDoubleVecNoScalar, GenTypeDoubleVecNoScalar, Double]>;
- def : Builtin<name, [GenTypeHalfVecNoScalar, GenTypeHalfVecNoScalar, Half]>;
+//--------------------------------------------------------------------
+// OpenCL v1.1 s6.11.12, v1.2 s6.12.12, v2.0 s6.13.12 - Miscellaneous Vector Functions
+// --- Table 19 ---
+foreach VSize1 = [Vec2, Vec4, Vec8, Vec16] in {
+ foreach VSize2 = [Vec2, Vec4, Vec8, Vec16] in {
+ def : Builtin<"shuffle", [GenericType<"TLAll" # VSize1.Name, TLAll, VSize1>,
+ GenericType<"TLAll" # VSize2.Name, TLAll, VSize2>,
+ GenericType<"TLAllUnsigned" # VSize1.Name, TLAllUnsigned, VSize1>],
+ Attr.Const>;
+ }
}
-
-// OpenCL v1.1 s6.11.3, v1.2 s6.12.3, v2.0 s6.13.3 - Integer Functions
-foreach name = ["max", "min"] in {
- def : Builtin<name, [AIGenTypeN, AIGenTypeN, AIGenTypeN]>;
- def : Builtin<name, [AIGenTypeNNoScalar, AIGenTypeNNoScalar, AIGenType1]>;
+foreach VSize1 = [Vec2, Vec4, Vec8, Vec16] in {
+ foreach VSize2 = [Vec2, Vec4, Vec8, Vec16] in {
+ def : Builtin<"shuffle2", [GenericType<"TLAll" # VSize1.Name, TLAll, VSize1>,
+ GenericType<"TLAll" # VSize2.Name, TLAll, VSize2>,
+ GenericType<"TLAll" # VSize2.Name, TLAll, VSize2>,
+ GenericType<"TLAllUnsigned" # VSize1.Name, TLAllUnsigned, VSize1>],
+ Attr.Const>;
+ }
}
//--------------------------------------------------------------------
@@ -517,49 +1004,49 @@ foreach name = ["max", "min"] in {
// --- Table 22: Image Read Functions with Samplers ---
foreach imgTy = [Image1d] in {
foreach coordTy = [Int, Float] in {
- def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, "RO">, Sampler, coordTy]>;
- def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, "RO">, Sampler, coordTy]>;
- def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, "RO">, Sampler, coordTy]>;
+ def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, "RO">, Sampler, coordTy], Attr.Pure>;
+ def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, "RO">, Sampler, coordTy], Attr.Pure>;
+ def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, "RO">, Sampler, coordTy], Attr.Pure>;
}
}
foreach imgTy = [Image2d, Image1dArray] in {
foreach coordTy = [Int, Float] in {
- def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 2>]>;
- def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 2>]>;
- def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 2>]>;
+ def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 2>], Attr.Pure>;
+ def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 2>], Attr.Pure>;
+ def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 2>], Attr.Pure>;
}
}
foreach imgTy = [Image3d, Image2dArray] in {
foreach coordTy = [Int, Float] in {
- def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 4>]>;
- def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 4>]>;
- def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 4>]>;
+ def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 4>], Attr.Pure>;
+ def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 4>], Attr.Pure>;
+ def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 4>], Attr.Pure>;
}
}
foreach coordTy = [Int, Float] in {
- def : Builtin<"read_imagef", [Float, ImageType<Image2dDepth, "RO">, Sampler, VectorType<coordTy, 2>]>;
- def : Builtin<"read_imagef", [Float, ImageType<Image2dArrayDepth, "RO">, Sampler, VectorType<coordTy, 4>]>;
+ def : Builtin<"read_imagef", [Float, ImageType<Image2dDepth, "RO">, Sampler, VectorType<coordTy, 2>], Attr.Pure>;
+ def : Builtin<"read_imagef", [Float, ImageType<Image2dArrayDepth, "RO">, Sampler, VectorType<coordTy, 4>], Attr.Pure>;
}
// --- Table 23: Sampler-less Read Functions ---
foreach aQual = ["RO", "RW"] in {
foreach imgTy = [Image2d, Image1dArray] in {
- def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>]>;
- def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>]>;
- def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>]>;
+ def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>], Attr.Pure>;
+ def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>], Attr.Pure>;
+ def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>], Attr.Pure>;
}
foreach imgTy = [Image3d, Image2dArray] in {
- def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>]>;
- def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>]>;
- def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>]>;
+ def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>], Attr.Pure>;
+ def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>], Attr.Pure>;
+ def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>], Attr.Pure>;
}
foreach imgTy = [Image1d, Image1dBuffer] in {
- def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, aQual>, Int]>;
- def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, aQual>, Int]>;
- def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, aQual>, Int]>;
+ def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, aQual>, Int], Attr.Pure>;
+ def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, aQual>, Int], Attr.Pure>;
+ def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, aQual>, Int], Attr.Pure>;
}
- def : Builtin<"read_imagef", [Float, ImageType<Image2dDepth, aQual>, VectorType<Int, 2>]>;
- def : Builtin<"read_imagef", [Float, ImageType<Image2dArrayDepth, aQual>, VectorType<Int, 4>]>;
+ def : Builtin<"read_imagef", [Float, ImageType<Image2dDepth, aQual>, VectorType<Int, 2>], Attr.Pure>;
+ def : Builtin<"read_imagef", [Float, ImageType<Image2dArrayDepth, aQual>, VectorType<Int, 4>], Attr.Pure>;
}
// --- Table 24: Image Write Functions ---
@@ -624,13 +1111,13 @@ foreach aQual = ["RO"] in {
foreach name = ["read_imageh"] in {
foreach coordTy = [Int, Float] in {
foreach imgTy = [Image2d, Image1dArray] in {
- def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<coordTy, 2>]>;
+ def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<coordTy, 2>], Attr.Pure>;
}
foreach imgTy = [Image3d, Image2dArray] in {
- def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<coordTy, 4>]>;
+ def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<coordTy, 4>], Attr.Pure>;
}
foreach imgTy = [Image1d] in {
- def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, Sampler, coordTy]>;
+ def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, Sampler, coordTy], Attr.Pure>;
}
}
}
@@ -640,13 +1127,13 @@ foreach aQual = ["RO"] in {
foreach aQual = ["RO", "RW"] in {
foreach name = ["read_imageh"] in {
foreach imgTy = [Image2d, Image1dArray] in {
- def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>]>;
+ def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>], Attr.Pure>;
}
foreach imgTy = [Image3d, Image2dArray] in {
- def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>]>;
+ def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>], Attr.Pure>;
}
foreach imgTy = [Image1d, Image1dBuffer] in {
- def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, Int]>;
+ def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, Int], Attr.Pure>;
}
}
}
@@ -664,11 +1151,201 @@ foreach aQual = ["WO", "RW"] in {
}
+//--------------------------------------------------------------------
+// OpenCL v2.0 s6.13.15 - Work-group Functions
+// --- Table 26 ---
+let MinVersion = CL20 in {
+ foreach name = ["work_group_all", "work_group_any"] in {
+ def : Builtin<name, [Int, Int], Attr.Convergent>;
+ }
+ foreach name = ["work_group_broadcast"] in {
+ def : Builtin<name, [IntLongFloatGenType1, IntLongFloatGenType1, Size], Attr.Convergent>;
+ def : Builtin<name, [IntLongFloatGenType1, IntLongFloatGenType1, Size, Size], Attr.Convergent>;
+ def : Builtin<name, [IntLongFloatGenType1, IntLongFloatGenType1, Size, Size, Size], Attr.Convergent>;
+ }
+ foreach op = ["add", "min", "max"] in {
+ foreach name = ["work_group_reduce_", "work_group_scan_exclusive_",
+ "work_group_scan_inclusive_"] in {
+ def : Builtin<name # op, [IntLongFloatGenType1, IntLongFloatGenType1], Attr.Convergent>;
+ }
+ }
+}
+
+
// OpenCL v2.0 s9.17.3: Additions to section 6.13.1: Work-Item Functions
let MinVersion = CL20 in {
- let Extension = "cl_khr_subgroups" in {
+ let Extension = FuncExtKhrSubgroups in {
def get_sub_group_size : Builtin<"get_sub_group_size", [UInt]>;
def get_max_sub_group_size : Builtin<"get_max_sub_group_size", [UInt]>;
def get_num_sub_groups : Builtin<"get_num_sub_groups", [UInt]>;
}
}
+
+//--------------------------------------------------------------------
+// End of the builtin functions defined in the OpenCL C specification.
+// Builtin functions defined in the OpenCL C Extension are below.
+//--------------------------------------------------------------------
+
+
+// OpenCL Extension v2.0 s9.18 - Mipmaps
+let Extension = FuncExtKhrMipmapImage in {
+ // Added to section 6.13.14.2.
+ foreach aQual = ["RO"] in {
+ foreach imgTy = [Image2d] in {
+ foreach name = ["read_imagef"] in {
+ def : Builtin<name, [VectorType<Float, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 2>, Float], Attr.Pure>;
+ def : Builtin<name, [VectorType<Float, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 2>, VectorType<Float, 2>, VectorType<Float, 2>], Attr.Pure>;
+ }
+ foreach name = ["read_imagei"] in {
+ def : Builtin<name, [VectorType<Int, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 2>, Float], Attr.Pure>;
+ def : Builtin<name, [VectorType<Int, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 2>, VectorType<Float, 2>, VectorType<Float, 2>], Attr.Pure>;
+ }
+ foreach name = ["read_imageui"] in {
+ def : Builtin<name, [VectorType<UInt, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 2>, Float], Attr.Pure>;
+ def : Builtin<name, [VectorType<UInt, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 2>, VectorType<Float, 2>, VectorType<Float, 2>], Attr.Pure>;
+ }
+ }
+ foreach imgTy = [Image2dDepth] in {
+ foreach name = ["read_imagef"] in {
+ def : Builtin<name, [Float, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 2>, Float], Attr.Pure>;
+ def : Builtin<name, [Float, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 2>, VectorType<Float, 2>, VectorType<Float, 2>], Attr.Pure>;
+ }
+ }
+ foreach imgTy = [Image1d] in {
+ foreach name = ["read_imagef"] in {
+ def : Builtin<name, [VectorType<Float, 4>, ImageType<imgTy, aQual>, Sampler, Float, Float], Attr.Pure>;
+ def : Builtin<name, [VectorType<Float, 4>, ImageType<imgTy, aQual>, Sampler, Float, Float, Float], Attr.Pure>;
+ }
+ foreach name = ["read_imagei"] in {
+ def : Builtin<name, [VectorType<Int, 4>, ImageType<imgTy, aQual>, Sampler, Float, Float], Attr.Pure>;
+ def : Builtin<name, [VectorType<Int, 4>, ImageType<imgTy, aQual>, Sampler, Float, Float, Float], Attr.Pure>;
+ }
+ foreach name = ["read_imageui"] in {
+ def : Builtin<name, [VectorType<UInt, 4>, ImageType<imgTy, aQual>, Sampler, Float, Float], Attr.Pure>;
+ def : Builtin<name, [VectorType<UInt, 4>, ImageType<imgTy, aQual>, Sampler, Float, Float, Float], Attr.Pure>;
+ }
+ }
+ foreach imgTy = [Image3d] in {
+ foreach name = ["read_imagef"] in {
+ def : Builtin<name, [VectorType<Float, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 4>, VectorType<Float, 4>, VectorType<Float, 4>], Attr.Pure>;
+ def : Builtin<name, [VectorType<Float, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 4>, Float], Attr.Pure>;
+ }
+ foreach name = ["read_imagei"] in {
+ def : Builtin<name, [VectorType<Int, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 4>, VectorType<Float, 4>, VectorType<Float, 4>], Attr.Pure>;
+ def : Builtin<name, [VectorType<Float, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 4>, Float], Attr.Pure>;
+ }
+ foreach name = ["read_imageui"] in {
+ def : Builtin<name, [VectorType<UInt, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 4>, VectorType<Float, 4>, VectorType<Float, 4>], Attr.Pure>;
+ def : Builtin<name, [VectorType<Float, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 4>, Float], Attr.Pure>;
+ }
+ }
+ foreach imgTy = [Image1dArray] in {
+ foreach name = ["read_imagef"] in {
+ def : Builtin<name, [VectorType<Float, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 2>, Float], Attr.Pure>;
+ def : Builtin<name, [VectorType<Float, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 2>, Float, Float], Attr.Pure>;
+ }
+ foreach name = ["read_imagei"] in {
+ def : Builtin<name, [VectorType<Int, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 2>, Float], Attr.Pure>;
+ def : Builtin<name, [VectorType<Int, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 2>, Float, Float], Attr.Pure>;
+ }
+ foreach name = ["read_imageui"] in {
+ def : Builtin<name, [VectorType<UInt, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 2>, Float], Attr.Pure>;
+ def : Builtin<name, [VectorType<UInt, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 2>, Float, Float], Attr.Pure>;
+ }
+ }
+ foreach imgTy = [Image2dArray] in {
+ foreach name = ["read_imagef"] in {
+ def : Builtin<name, [VectorType<Float, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 4>, Float], Attr.Pure>;
+ def : Builtin<name, [VectorType<Float, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 4>, VectorType<Float, 2>, VectorType<Float, 2>], Attr.Pure>;
+ }
+ foreach name = ["read_imagei"] in {
+ def : Builtin<name, [VectorType<Int, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 4>, Float], Attr.Pure>;
+ def : Builtin<name, [VectorType<Int, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 4>, VectorType<Float, 2>, VectorType<Float, 2>], Attr.Pure>;
+ }
+ foreach name = ["read_imageui"] in {
+ def : Builtin<name, [VectorType<UInt, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 4>, Float], Attr.Pure>;
+ def : Builtin<name, [VectorType<UInt, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 4>, VectorType<Float, 2>, VectorType<Float, 2>], Attr.Pure>;
+ }
+ }
+ foreach imgTy = [Image2dArrayDepth] in {
+ foreach name = ["read_imagef"] in {
+ def : Builtin<name, [VectorType<UInt, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 4>, Float], Attr.Pure>;
+ def : Builtin<name, [VectorType<UInt, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 4>, VectorType<Float, 2>, VectorType<Float, 2>], Attr.Pure>;
+ }
+ }
+ }
+ // Added to section 6.13.14.4.
+ foreach aQual = ["WO"] in {
+ foreach imgTy = [Image2d] in {
+ def : Builtin<"write_imagef", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, Int, VectorType<Float, 4>]>;
+ def : Builtin<"write_imagei", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, Int, VectorType<Int, 4>]>;
+ def : Builtin<"write_imageui", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, Int, VectorType<UInt, 4>]>;
+ }
+ def : Builtin<"write_imagef", [Void, ImageType<Image2dDepth, aQual>, VectorType<Int, 2>, Int, Float]>;
+ foreach imgTy = [Image1d] in {
+ def : Builtin<"write_imagef", [Void, ImageType<imgTy, aQual>, Int, Int, VectorType<Float, 4>]>;
+ def : Builtin<"write_imagei", [Void, ImageType<imgTy, aQual>, Int, Int, VectorType<Int, 4>]>;
+ def : Builtin<"write_imageui", [Void, ImageType<imgTy, aQual>, Int, Int, VectorType<UInt, 4>]>;
+ }
+ foreach imgTy = [Image1dArray] in {
+ def : Builtin<"write_imagef", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, Int, VectorType<Float, 4>]>;
+ def : Builtin<"write_imagei", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, Int, VectorType<Int, 4>]>;
+ def : Builtin<"write_imageui", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, Int, VectorType<UInt, 4>]>;
+ }
+ foreach imgTy = [Image2dArray] 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>]>;
+ }
+ def : Builtin<"write_imagef", [Void, ImageType<Image2dArrayDepth, aQual>, VectorType<Int, 4>, Int, Float]>;
+ let Extension = FuncExtKhrMipmapAndWrite3d 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>]>;
+ }
+ }
+ }
+ // Added to section 6.13.14.5
+ foreach aQual = ["RO", "WO", "RW"] in {
+ foreach imgTy = [Image1d, Image2d, Image3d, Image1dArray, Image2dArray, Image2dDepth, Image2dArrayDepth] in {
+ def : Builtin<"get_image_num_mip_levels", [Int, ImageType<imgTy, aQual>]>;
+ }
+ }
+}
+
+
+//--------------------------------------------------------------------
+// OpenCL Extension v2.0 s18.3 - Creating OpenCL Memory Objects from OpenGL MSAA Textures
+let Extension = FuncExtKhrGlMsaaSharing in {
+ // --- Table 6.13.14.3 ---
+ foreach aQual = ["RO", "RW"] in {
+ foreach imgTy = [Image2dMsaa] in {
+ def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>, Int], Attr.Pure>;
+ def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>, Int], Attr.Pure>;
+ def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>, Int], Attr.Pure>;
+ }
+ foreach imgTy = [Image2dArrayMsaa] in {
+ def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>, Int], Attr.Pure>;
+ def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>, Int], Attr.Pure>;
+ def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>, Int], Attr.Pure>;
+ }
+ foreach name = ["read_imagef"] in {
+ def : Builtin<name, [Float, ImageType<Image2dMsaaDepth, aQual>, VectorType<Int, 2>, Int], Attr.Pure>;
+ def : Builtin<name, [Float, ImageType<Image2dArrayMsaaDepth, aQual>, VectorType<Int, 4>, Int], Attr.Pure>;
+ }
+ }
+
+ // --- Table 6.13.14.5 ---
+ foreach aQual = ["RO", "WO", "RW"] in {
+ foreach imgTy = [Image2dMsaa, Image2dArrayMsaa, Image2dMsaaDepth, Image2dArrayMsaaDepth] in {
+ foreach name = ["get_image_width", "get_image_height",
+ "get_image_channel_data_type", "get_image_channel_order",
+ "get_image_num_samples"] in {
+ def : Builtin<name, [Int, ImageType<imgTy, aQual>], Attr.Const>;
+ }
+ def : Builtin<"get_image_dim", [VectorType<Int, 2>, ImageType<imgTy, aQual>], Attr.Const>;
+ }
+ def : Builtin<"get_image_array_size", [Size, ImageType<Image2dArrayMsaaDepth, aQual>], Attr.Const>;
+ }
+}
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index bedea2167950..2cd158a8b43c 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -137,7 +137,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
OriginalLexicalContext(nullptr), MSStructPragmaOn(false),
MSPointerToMemberRepresentationMethod(
LangOpts.getMSPointerToMemberRepresentationMethod()),
- VtorDispStack(MSVtorDispAttr::Mode(LangOpts.VtorDispMode)), PackStack(0),
+ VtorDispStack(LangOpts.getVtorDispMode()), PackStack(0),
DataSegStack(nullptr), BSSSegStack(nullptr), ConstSegStack(nullptr),
CodeSegStack(nullptr), CurInitSeg(nullptr), VisContext(nullptr),
PragmaAttributeCurrentTargetDecl(nullptr),
@@ -189,6 +189,9 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
SemaPPCallbackHandler->set(*this);
}
+// Anchor Sema's type info to this TU.
+void Sema::anchor() {}
+
void Sema::addImplicitTypedef(StringRef Name, QualType T) {
DeclarationName DN = &Context.Idents.get(Name);
if (IdResolver.begin(DN) == IdResolver.end())
@@ -921,8 +924,7 @@ void Sema::ActOnEndOfTranslationUnitFragment(TUFragmentKind Kind) {
}
{
- llvm::TimeTraceScope TimeScope("PerformPendingInstantiations",
- StringRef(""));
+ llvm::TimeTraceScope TimeScope("PerformPendingInstantiations");
PerformPendingInstantiations();
}
@@ -1134,6 +1136,13 @@ void Sema::ActOnEndOfTranslationUnit() {
Consumer.CompleteTentativeDefinition(VD);
}
+ for (auto D : ExternalDeclarations) {
+ if (!D || D->isInvalidDecl() || D->getPreviousDecl() || !D->isUsed())
+ continue;
+
+ Consumer.CompleteExternalDeclaration(D);
+ }
+
// If there were errors, disable 'unused' warnings since they will mostly be
// noise. Don't warn for a use from a module: either we should warn on all
// file-scope declarations in modules or not at all, but whether the
@@ -1287,6 +1296,12 @@ NamedDecl *Sema::getCurFunctionOrMethodDecl() {
return nullptr;
}
+LangAS Sema::getDefaultCXXMethodAddrSpace() const {
+ if (getLangOpts().OpenCL)
+ return LangAS::opencl_generic;
+ return LangAS::Default;
+}
+
void Sema::EmitCurrentDiagnostic(unsigned DiagID) {
// FIXME: It doesn't make sense to me that DiagID is an incoming argument here
// and yet we also use the current diag ID on the DiagnosticsEngine. This has
@@ -1902,6 +1917,7 @@ void Sema::ActOnComment(SourceRange Comment) {
// Pin this vtable to this file.
ExternalSemaSource::~ExternalSemaSource() {}
+char ExternalSemaSource::ID;
void ExternalSemaSource::ReadMethodPool(Selector Sel) { }
void ExternalSemaSource::updateOutOfDateSelector(Selector Sel) { }
diff --git a/clang/lib/Sema/SemaAccess.cpp b/clang/lib/Sema/SemaAccess.cpp
index 9dbb93322b7d..bd15b81cbed0 100644
--- a/clang/lib/Sema/SemaAccess.cpp
+++ b/clang/lib/Sema/SemaAccess.cpp
@@ -1560,21 +1560,24 @@ Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
return CheckAccess(*this, E->getMemberLoc(), Entity);
}
-/// Is the given special member function accessible for the purposes of
-/// deciding whether to define a special member function as deleted?
-bool Sema::isSpecialMemberAccessibleForDeletion(CXXMethodDecl *decl,
- AccessSpecifier access,
- QualType objectType) {
+/// Is the given member accessible for the purposes of deciding whether to
+/// define a special member function as deleted?
+bool Sema::isMemberAccessibleForDeletion(CXXRecordDecl *NamingClass,
+ DeclAccessPair Found,
+ QualType ObjectType,
+ SourceLocation Loc,
+ const PartialDiagnostic &Diag) {
// Fast path.
- if (access == AS_public || !getLangOpts().AccessControl) return true;
+ if (Found.getAccess() == AS_public || !getLangOpts().AccessControl)
+ return true;
- AccessTarget entity(Context, AccessTarget::Member, decl->getParent(),
- DeclAccessPair::make(decl, access), objectType);
+ AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found,
+ ObjectType);
// Suppress diagnostics.
- entity.setDiag(PDiag());
+ Entity.setDiag(Diag);
- switch (CheckAccess(*this, SourceLocation(), entity)) {
+ switch (CheckAccess(*this, Loc, Entity)) {
case AR_accessible: return true;
case AR_inaccessible: return false;
case AR_dependent: llvm_unreachable("dependent for =delete computation");
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index 70186c966f8f..cd2a65276b09 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -80,9 +80,9 @@ void Sema::AddMsStructLayoutForRecord(RecordDecl *RD) {
// FIXME: We should merge AddAlignmentAttributesForRecord with
// AddMsStructLayoutForRecord into AddPragmaAttributesForRecord, which takes
// all active pragmas and applies them as attributes to class definitions.
- if (VtorDispStack.CurrentValue != getLangOpts().VtorDispMode)
- RD->addAttr(
- MSVtorDispAttr::CreateImplicit(Context, VtorDispStack.CurrentValue));
+ if (VtorDispStack.CurrentValue != getLangOpts().getVtorDispMode())
+ RD->addAttr(MSVtorDispAttr::CreateImplicit(
+ Context, unsigned(VtorDispStack.CurrentValue)));
}
template <typename Attribute>
@@ -416,7 +416,7 @@ void Sema::ActOnPragmaMSPointersToMembers(
void Sema::ActOnPragmaMSVtorDisp(PragmaMsStackAction Action,
SourceLocation PragmaLoc,
- MSVtorDispAttr::Mode Mode) {
+ MSVtorDispMode Mode) {
if (Action & PSK_Pop && VtorDispStack.Stack.empty())
Diag(PragmaLoc, diag::warn_pragma_pop_failed) << "vtordisp"
<< "stack empty";
diff --git a/clang/lib/Sema/SemaCUDA.cpp b/clang/lib/Sema/SemaCUDA.cpp
index d0ddfd040c9c..0c61057e1072 100644
--- a/clang/lib/Sema/SemaCUDA.cpp
+++ b/clang/lib/Sema/SemaCUDA.cpp
@@ -492,6 +492,8 @@ void Sema::checkAllowedCUDAInitializer(VarDecl *VD) {
const Expr *Init = VD->getInit();
if (VD->hasAttr<CUDADeviceAttr>() || VD->hasAttr<CUDAConstantAttr>() ||
VD->hasAttr<CUDASharedAttr>()) {
+ if (LangOpts.GPUAllowDeviceInit)
+ return;
assert(!VD->isStaticLocal() || VD->hasAttr<CUDASharedAttr>());
bool AllowedInit = false;
if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(Init))
diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp
index 0ebb5c68f7c2..a905ebc67305 100644
--- a/clang/lib/Sema/SemaCast.cpp
+++ b/clang/lib/Sema/SemaCast.cpp
@@ -423,7 +423,7 @@ static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT,
case OR_Ambiguous:
msg = diag::err_ovl_ambiguous_conversion_in_cast;
- howManyCandidates = OCD_ViableCandidates;
+ howManyCandidates = OCD_AmbiguousCandidates;
break;
case OR_Deleted:
@@ -740,7 +740,7 @@ void CastOperation::CheckDynamicCast() {
assert(DestPointer && "Reference to void is not possible");
} else if (DestRecord) {
if (Self.RequireCompleteType(OpRange.getBegin(), DestPointee,
- diag::err_bad_dynamic_cast_incomplete,
+ diag::err_bad_cast_incomplete,
DestRange)) {
SrcExpr = ExprError();
return;
@@ -763,7 +763,7 @@ void CastOperation::CheckDynamicCast() {
SrcPointee = SrcPointer->getPointeeType();
} else {
Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_ptr)
- << OrigSrcType << SrcExpr.get()->getSourceRange();
+ << OrigSrcType << this->DestType << SrcExpr.get()->getSourceRange();
SrcExpr = ExprError();
return;
}
@@ -785,7 +785,7 @@ void CastOperation::CheckDynamicCast() {
const RecordType *SrcRecord = SrcPointee->getAs<RecordType>();
if (SrcRecord) {
if (Self.RequireCompleteType(OpRange.getBegin(), SrcPointee,
- diag::err_bad_dynamic_cast_incomplete,
+ diag::err_bad_cast_incomplete,
SrcExpr.get())) {
SrcExpr = ExprError();
return;
@@ -1182,6 +1182,11 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
// The same goes for reverse floating point promotion/conversion and
// floating-integral conversions. Again, only floating->enum is relevant.
if (DestType->isEnumeralType()) {
+ if (Self.RequireCompleteType(OpRange.getBegin(), DestType,
+ diag::err_bad_cast_incomplete)) {
+ SrcExpr = ExprError();
+ return TC_Failed;
+ }
if (SrcType->isIntegralOrEnumerationType()) {
Kind = CK_IntegralCast;
return TC_Success;
@@ -1301,10 +1306,6 @@ TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr,
// Because we try the reference downcast before this function, from now on
// this is the only cast possibility, so we issue an error if we fail now.
// FIXME: Should allow casting away constness if CStyle.
- bool DerivedToBase;
- bool ObjCConversion;
- bool ObjCLifetimeConversion;
- bool FunctionConversion;
QualType FromType = SrcExpr->getType();
QualType ToType = R->getPointeeType();
if (CStyle) {
@@ -1312,9 +1313,9 @@ TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr,
ToType = ToType.getUnqualifiedType();
}
+ Sema::ReferenceConversions RefConv;
Sema::ReferenceCompareResult RefResult = Self.CompareReferenceRelationship(
- SrcExpr->getBeginLoc(), ToType, FromType, DerivedToBase, ObjCConversion,
- ObjCLifetimeConversion, FunctionConversion);
+ SrcExpr->getBeginLoc(), ToType, FromType, &RefConv);
if (RefResult != Sema::Ref_Compatible) {
if (CStyle || RefResult == Sema::Ref_Incompatible)
return TC_NotApplicable;
@@ -1326,7 +1327,7 @@ TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr,
return TC_Failed;
}
- if (DerivedToBase) {
+ if (RefConv & Sema::ReferenceConversions::DerivedToBase) {
Kind = CK_DerivedToBase;
CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
/*DetectVirtual=*/true);
@@ -1651,7 +1652,7 @@ TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
CastKind &Kind, bool ListInitialization) {
if (DestType->isRecordType()) {
if (Self.RequireCompleteType(OpRange.getBegin(), DestType,
- diag::err_bad_dynamic_cast_incomplete) ||
+ diag::err_bad_cast_incomplete) ||
Self.RequireNonAbstractType(OpRange.getBegin(), DestType,
diag::err_allocation_of_abstract_type)) {
msg = 0;
@@ -2007,7 +2008,7 @@ static bool fixOverloadedReinterpretCastExpr(Sema &Self, QualType DestType,
// No guarantees that ResolveAndFixSingleFunctionTemplateSpecialization
// preserves Result.
Result = E;
- if (!Self.resolveAndFixAddressOfOnlyViableOverloadCandidate(
+ if (!Self.resolveAndFixAddressOfSingleOverloadCandidate(
Result, /*DoFunctionPointerConversion=*/true))
return false;
return Result.isUsable();
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index dca81d1d275f..74742023d1b3 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -201,6 +201,87 @@ static bool SemaBuiltinPreserveAI(Sema &S, CallExpr *TheCall) {
return false;
}
+/// Check that the value argument for __builtin_is_aligned(value, alignment) and
+/// __builtin_aligned_{up,down}(value, alignment) is an integer or a pointer
+/// type (but not a function pointer) and that the alignment is a power-of-two.
+static bool SemaBuiltinAlignment(Sema &S, CallExpr *TheCall, unsigned ID) {
+ if (checkArgCount(S, TheCall, 2))
+ return true;
+
+ clang::Expr *Source = TheCall->getArg(0);
+ bool IsBooleanAlignBuiltin = ID == Builtin::BI__builtin_is_aligned;
+
+ auto IsValidIntegerType = [](QualType Ty) {
+ return Ty->isIntegerType() && !Ty->isEnumeralType() && !Ty->isBooleanType();
+ };
+ QualType SrcTy = Source->getType();
+ // We should also be able to use it with arrays (but not functions!).
+ if (SrcTy->canDecayToPointerType() && SrcTy->isArrayType()) {
+ SrcTy = S.Context.getDecayedType(SrcTy);
+ }
+ if ((!SrcTy->isPointerType() && !IsValidIntegerType(SrcTy)) ||
+ SrcTy->isFunctionPointerType()) {
+ // FIXME: this is not quite the right error message since we don't allow
+ // floating point types, or member pointers.
+ S.Diag(Source->getExprLoc(), diag::err_typecheck_expect_scalar_operand)
+ << SrcTy;
+ return true;
+ }
+
+ clang::Expr *AlignOp = TheCall->getArg(1);
+ if (!IsValidIntegerType(AlignOp->getType())) {
+ S.Diag(AlignOp->getExprLoc(), diag::err_typecheck_expect_int)
+ << AlignOp->getType();
+ return true;
+ }
+ Expr::EvalResult AlignResult;
+ unsigned MaxAlignmentBits = S.Context.getIntWidth(SrcTy) - 1;
+ // We can't check validity of alignment if it is type dependent.
+ if (!AlignOp->isInstantiationDependent() &&
+ AlignOp->EvaluateAsInt(AlignResult, S.Context,
+ Expr::SE_AllowSideEffects)) {
+ llvm::APSInt AlignValue = AlignResult.Val.getInt();
+ llvm::APSInt MaxValue(
+ llvm::APInt::getOneBitSet(MaxAlignmentBits + 1, MaxAlignmentBits));
+ if (AlignValue < 1) {
+ S.Diag(AlignOp->getExprLoc(), diag::err_alignment_too_small) << 1;
+ return true;
+ }
+ if (llvm::APSInt::compareValues(AlignValue, MaxValue) > 0) {
+ S.Diag(AlignOp->getExprLoc(), diag::err_alignment_too_big)
+ << MaxValue.toString(10);
+ return true;
+ }
+ if (!AlignValue.isPowerOf2()) {
+ S.Diag(AlignOp->getExprLoc(), diag::err_alignment_not_power_of_two);
+ return true;
+ }
+ if (AlignValue == 1) {
+ S.Diag(AlignOp->getExprLoc(), diag::warn_alignment_builtin_useless)
+ << IsBooleanAlignBuiltin;
+ }
+ }
+
+ ExprResult SrcArg = S.PerformCopyInitialization(
+ InitializedEntity::InitializeParameter(S.Context, SrcTy, false),
+ SourceLocation(), Source);
+ if (SrcArg.isInvalid())
+ return true;
+ TheCall->setArg(0, SrcArg.get());
+ ExprResult AlignArg =
+ S.PerformCopyInitialization(InitializedEntity::InitializeParameter(
+ S.Context, AlignOp->getType(), false),
+ SourceLocation(), AlignOp);
+ if (AlignArg.isInvalid())
+ return true;
+ TheCall->setArg(1, AlignArg.get());
+ // For align_up/align_down, the return type is the same as the (potentially
+ // decayed) argument type including qualifiers. For is_aligned(), the result
+ // is always bool.
+ TheCall->setType(IsBooleanAlignBuiltin ? S.Context.BoolTy : SrcTy);
+ return false;
+}
+
static bool SemaBuiltinOverflow(Sema &S, CallExpr *TheCall) {
if (checkArgCount(S, TheCall, 3))
return true;
@@ -340,7 +421,8 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD,
case Builtin::BI__builtin___strncat_chk:
case Builtin::BI__builtin___strncpy_chk:
case Builtin::BI__builtin___stpncpy_chk:
- case Builtin::BI__builtin___memccpy_chk: {
+ case Builtin::BI__builtin___memccpy_chk:
+ case Builtin::BI__builtin___mempcpy_chk: {
DiagID = diag::warn_builtin_chk_overflow;
IsChkVariant = true;
SizeIndex = TheCall->getNumArgs() - 2;
@@ -379,7 +461,9 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD,
case Builtin::BImemmove:
case Builtin::BI__builtin_memmove:
case Builtin::BImemset:
- case Builtin::BI__builtin_memset: {
+ case Builtin::BI__builtin_memset:
+ case Builtin::BImempcpy:
+ case Builtin::BI__builtin_mempcpy: {
DiagID = diag::warn_fortify_source_overflow;
SizeIndex = TheCall->getNumArgs() - 1;
ObjectIndex = 0;
@@ -1354,6 +1438,12 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
if (SemaBuiltinAddressof(*this, TheCall))
return ExprError();
break;
+ case Builtin::BI__builtin_is_aligned:
+ case Builtin::BI__builtin_align_up:
+ case Builtin::BI__builtin_align_down:
+ if (SemaBuiltinAlignment(*this, TheCall, BuiltinID))
+ return ExprError();
+ break;
case Builtin::BI__builtin_add_overflow:
case Builtin::BI__builtin_sub_overflow:
case Builtin::BI__builtin_mul_overflow:
@@ -1536,6 +1626,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
return ExprError();
break;
case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_32:
case llvm::Triple::aarch64_be:
if (CheckAArch64BuiltinFunctionCall(BuiltinID, TheCall))
return ExprError();
@@ -1685,6 +1776,7 @@ bool Sema::CheckNeonBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
llvm::Triple::ArchType Arch = Context.getTargetInfo().getTriple().getArch();
bool IsPolyUnsigned = Arch == llvm::Triple::aarch64 ||
+ Arch == llvm::Triple::aarch64_32 ||
Arch == llvm::Triple::aarch64_be;
bool IsInt64Long =
Context.getTargetInfo().getInt64Type() == TargetInfo::SignedLong;
@@ -1717,6 +1809,14 @@ bool Sema::CheckNeonBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
return SemaBuiltinConstantArgRange(TheCall, i, l, u + l);
}
+bool Sema::CheckMVEBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
+ switch (BuiltinID) {
+ default:
+ return false;
+ #include "clang/Basic/arm_mve_builtin_sema.inc"
+ }
+}
+
bool Sema::CheckARMBuiltinExclusiveCall(unsigned BuiltinID, CallExpr *TheCall,
unsigned MaxWidth) {
assert((BuiltinID == ARM::BI__builtin_arm_ldrex ||
@@ -1857,6 +1957,8 @@ bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
if (CheckNeonBuiltinFunctionCall(BuiltinID, TheCall))
return true;
+ if (CheckMVEBuiltinFunctionCall(BuiltinID, TheCall))
+ return true;
// For intrinsics which take an immediate value as part of the instruction,
// range check them here.
@@ -3039,8 +3141,37 @@ bool Sema::CheckHexagonBuiltinFunctionCall(unsigned BuiltinID,
CheckHexagonBuiltinArgument(BuiltinID, TheCall);
}
+bool Sema::CheckMipsBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
+ return CheckMipsBuiltinCpu(BuiltinID, TheCall) ||
+ CheckMipsBuiltinArgument(BuiltinID, TheCall);
+}
+
+bool Sema::CheckMipsBuiltinCpu(unsigned BuiltinID, CallExpr *TheCall) {
+ const TargetInfo &TI = Context.getTargetInfo();
+
+ if (Mips::BI__builtin_mips_addu_qb <= BuiltinID &&
+ BuiltinID <= Mips::BI__builtin_mips_lwx) {
+ if (!TI.hasFeature("dsp"))
+ return Diag(TheCall->getBeginLoc(), diag::err_mips_builtin_requires_dsp);
+ }
-// CheckMipsBuiltinFunctionCall - Checks the constant value passed to the
+ if (Mips::BI__builtin_mips_absq_s_qb <= BuiltinID &&
+ BuiltinID <= Mips::BI__builtin_mips_subuh_r_qb) {
+ if (!TI.hasFeature("dspr2"))
+ return Diag(TheCall->getBeginLoc(),
+ diag::err_mips_builtin_requires_dspr2);
+ }
+
+ if (Mips::BI__builtin_msa_add_a_b <= BuiltinID &&
+ BuiltinID <= Mips::BI__builtin_msa_xori_b) {
+ if (!TI.hasFeature("msa"))
+ return Diag(TheCall->getBeginLoc(), diag::err_mips_builtin_requires_msa);
+ }
+
+ return false;
+}
+
+// CheckMipsBuiltinArgument - Checks the constant value passed to the
// intrinsic is correct. The switch statement is ordered by DSP, MSA. The
// ordering for DSP is unspecified. MSA is ordered by the data format used
// by the underlying instruction i.e., df/m, df/n and then by size.
@@ -3049,7 +3180,7 @@ bool Sema::CheckHexagonBuiltinFunctionCall(unsigned BuiltinID,
// definitions from include/clang/Basic/BuiltinsMips.def.
// FIXME: GCC is strict on signedness for some of these intrinsics, we should
// be too.
-bool Sema::CheckMipsBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
+bool Sema::CheckMipsBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall) {
unsigned i = 0, l = 0, u = 0, m = 0;
switch (BuiltinID) {
default: return false;
@@ -4560,20 +4691,19 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange,
&& sizeof(NumVals)/sizeof(NumVals[0]) == NumForm,
"need to update code for modified forms");
static_assert(AtomicExpr::AO__c11_atomic_init == 0 &&
- AtomicExpr::AO__c11_atomic_fetch_xor + 1 ==
+ AtomicExpr::AO__c11_atomic_fetch_min + 1 ==
AtomicExpr::AO__atomic_load,
"need to update code for modified C11 atomics");
bool IsOpenCL = Op >= AtomicExpr::AO__opencl_atomic_init &&
Op <= AtomicExpr::AO__opencl_atomic_fetch_max;
bool IsC11 = (Op >= AtomicExpr::AO__c11_atomic_init &&
- Op <= AtomicExpr::AO__c11_atomic_fetch_xor) ||
+ Op <= AtomicExpr::AO__c11_atomic_fetch_min) ||
IsOpenCL;
bool IsN = Op == AtomicExpr::AO__atomic_load_n ||
Op == AtomicExpr::AO__atomic_store_n ||
Op == AtomicExpr::AO__atomic_exchange_n ||
Op == AtomicExpr::AO__atomic_compare_exchange_n;
bool IsAddSub = false;
- bool IsMinMax = false;
switch (Op) {
case AtomicExpr::AO__c11_atomic_init:
@@ -4602,8 +4732,6 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange,
case AtomicExpr::AO__c11_atomic_fetch_sub:
case AtomicExpr::AO__opencl_atomic_fetch_add:
case AtomicExpr::AO__opencl_atomic_fetch_sub:
- case AtomicExpr::AO__opencl_atomic_fetch_min:
- case AtomicExpr::AO__opencl_atomic_fetch_max:
case AtomicExpr::AO__atomic_fetch_add:
case AtomicExpr::AO__atomic_fetch_sub:
case AtomicExpr::AO__atomic_add_fetch:
@@ -4624,12 +4752,14 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange,
case AtomicExpr::AO__atomic_or_fetch:
case AtomicExpr::AO__atomic_xor_fetch:
case AtomicExpr::AO__atomic_nand_fetch:
- Form = Arithmetic;
- break;
-
+ case AtomicExpr::AO__c11_atomic_fetch_min:
+ case AtomicExpr::AO__c11_atomic_fetch_max:
+ case AtomicExpr::AO__opencl_atomic_fetch_min:
+ case AtomicExpr::AO__opencl_atomic_fetch_max:
+ case AtomicExpr::AO__atomic_min_fetch:
+ case AtomicExpr::AO__atomic_max_fetch:
case AtomicExpr::AO__atomic_fetch_min:
case AtomicExpr::AO__atomic_fetch_max:
- IsMinMax = true;
Form = Arithmetic;
break;
@@ -4721,16 +4851,8 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange,
<< IsC11 << Ptr->getType() << Ptr->getSourceRange();
return ExprError();
}
- if (IsMinMax) {
- const BuiltinType *BT = ValType->getAs<BuiltinType>();
- if (!BT || (BT->getKind() != BuiltinType::Int &&
- BT->getKind() != BuiltinType::UInt)) {
- Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_int32_or_ptr);
- return ExprError();
- }
- }
- if (!IsAddSub && !IsMinMax && !ValType->isIntegerType()) {
- Diag(ExprRange.getBegin(), diag::err_atomic_op_bitwise_needs_atomic_int)
+ if (!IsAddSub && !ValType->isIntegerType()) {
+ Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_atomic_int)
<< IsC11 << Ptr->getType() << Ptr->getSourceRange();
return ExprError();
}
@@ -5506,7 +5628,8 @@ ExprResult Sema::CheckOSLogFormatStringArg(Expr *Arg) {
static bool checkVAStartABI(Sema &S, unsigned BuiltinID, Expr *Fn) {
const llvm::Triple &TT = S.Context.getTargetInfo().getTriple();
bool IsX64 = TT.getArch() == llvm::Triple::x86_64;
- bool IsAArch64 = TT.getArch() == llvm::Triple::aarch64;
+ bool IsAArch64 = (TT.getArch() == llvm::Triple::aarch64 ||
+ TT.getArch() == llvm::Triple::aarch64_32);
bool IsWindows = TT.isOSWindows();
bool IsMSVAStart = BuiltinID == Builtin::BI__builtin_ms_va_start;
if (IsX64 || IsAArch64) {
@@ -5723,7 +5846,8 @@ bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall) {
// Do standard promotions between the two arguments, returning their common
// type.
- QualType Res = UsualArithmeticConversions(OrigArg0, OrigArg1, false);
+ QualType Res = UsualArithmeticConversions(
+ OrigArg0, OrigArg1, TheCall->getExprLoc(), ACK_Comparison);
if (OrigArg0.isInvalid() || OrigArg1.isInvalid())
return true;
@@ -5763,36 +5887,41 @@ bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs) {
<< SourceRange(TheCall->getArg(NumArgs)->getBeginLoc(),
(*(TheCall->arg_end() - 1))->getEndLoc());
+ // __builtin_fpclassify is the only case where NumArgs != 1, so we can count
+ // on all preceding parameters just being int. Try all of those.
+ for (unsigned i = 0; i < NumArgs - 1; ++i) {
+ Expr *Arg = TheCall->getArg(i);
+
+ if (Arg->isTypeDependent())
+ return false;
+
+ ExprResult Res = PerformImplicitConversion(Arg, Context.IntTy, AA_Passing);
+
+ if (Res.isInvalid())
+ return true;
+ TheCall->setArg(i, Res.get());
+ }
+
Expr *OrigArg = TheCall->getArg(NumArgs-1);
if (OrigArg->isTypeDependent())
return false;
+ // Usual Unary Conversions will convert half to float, which we want for
+ // machines that use fp16 conversion intrinsics. Else, we wnat to leave the
+ // type how it is, but do normal L->Rvalue conversions.
+ if (Context.getTargetInfo().useFP16ConversionIntrinsics())
+ OrigArg = UsualUnaryConversions(OrigArg).get();
+ else
+ OrigArg = DefaultFunctionArrayLvalueConversion(OrigArg).get();
+ TheCall->setArg(NumArgs - 1, OrigArg);
+
// This operation requires a non-_Complex floating-point number.
if (!OrigArg->getType()->isRealFloatingType())
return Diag(OrigArg->getBeginLoc(),
diag::err_typecheck_call_invalid_unary_fp)
<< OrigArg->getType() << OrigArg->getSourceRange();
- // If this is an implicit conversion from float -> float, double, or
- // long double, remove it.
- if (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(OrigArg)) {
- // Only remove standard FloatCasts, leaving other casts inplace
- if (Cast->getCastKind() == CK_FloatingCast) {
- Expr *CastArg = Cast->getSubExpr();
- if (CastArg->getType()->isSpecificBuiltinType(BuiltinType::Float)) {
- assert(
- (Cast->getType()->isSpecificBuiltinType(BuiltinType::Double) ||
- Cast->getType()->isSpecificBuiltinType(BuiltinType::Float) ||
- Cast->getType()->isSpecificBuiltinType(BuiltinType::LongDouble)) &&
- "promotion from float to either float, double, or long double is "
- "the only expected cast here");
- Cast->setSubExpr(nullptr);
- TheCall->setArg(NumArgs-1, CastArg);
- }
- }
- }
-
return false;
}
@@ -6235,6 +6364,101 @@ bool Sema::SemaBuiltinConstantArgMultiple(CallExpr *TheCall, int ArgNum,
return false;
}
+/// SemaBuiltinConstantArgPower2 - Check if argument ArgNum of TheCall is a
+/// constant expression representing a power of 2.
+bool Sema::SemaBuiltinConstantArgPower2(CallExpr *TheCall, int ArgNum) {
+ llvm::APSInt Result;
+
+ // We can't check the value of a dependent argument.
+ Expr *Arg = TheCall->getArg(ArgNum);
+ if (Arg->isTypeDependent() || Arg->isValueDependent())
+ return false;
+
+ // Check constant-ness first.
+ if (SemaBuiltinConstantArg(TheCall, ArgNum, Result))
+ return true;
+
+ // Bit-twiddling to test for a power of 2: for x > 0, x & (x-1) is zero if
+ // and only if x is a power of 2.
+ if (Result.isStrictlyPositive() && (Result & (Result - 1)) == 0)
+ return false;
+
+ return Diag(TheCall->getBeginLoc(), diag::err_argument_not_power_of_2)
+ << Arg->getSourceRange();
+}
+
+static bool IsShiftedByte(llvm::APSInt Value) {
+ if (Value.isNegative())
+ return false;
+
+ // Check if it's a shifted byte, by shifting it down
+ while (true) {
+ // If the value fits in the bottom byte, the check passes.
+ if (Value < 0x100)
+ return true;
+
+ // Otherwise, if the value has _any_ bits in the bottom byte, the check
+ // fails.
+ if ((Value & 0xFF) != 0)
+ return false;
+
+ // If the bottom 8 bits are all 0, but something above that is nonzero,
+ // then shifting the value right by 8 bits won't affect whether it's a
+ // shifted byte or not. So do that, and go round again.
+ Value >>= 8;
+ }
+}
+
+/// SemaBuiltinConstantArgShiftedByte - Check if argument ArgNum of TheCall is
+/// a constant expression representing an arbitrary byte value shifted left by
+/// a multiple of 8 bits.
+bool Sema::SemaBuiltinConstantArgShiftedByte(CallExpr *TheCall, int ArgNum) {
+ llvm::APSInt Result;
+
+ // We can't check the value of a dependent argument.
+ Expr *Arg = TheCall->getArg(ArgNum);
+ if (Arg->isTypeDependent() || Arg->isValueDependent())
+ return false;
+
+ // Check constant-ness first.
+ if (SemaBuiltinConstantArg(TheCall, ArgNum, Result))
+ return true;
+
+ if (IsShiftedByte(Result))
+ return false;
+
+ return Diag(TheCall->getBeginLoc(), diag::err_argument_not_shifted_byte)
+ << Arg->getSourceRange();
+}
+
+/// SemaBuiltinConstantArgShiftedByteOr0xFF - Check if argument ArgNum of
+/// TheCall is a constant expression representing either a shifted byte value,
+/// or a value of the form 0x??FF (i.e. a member of the arithmetic progression
+/// 0x00FF, 0x01FF, ..., 0xFFFF). This strange range check is needed for some
+/// Arm MVE intrinsics.
+bool Sema::SemaBuiltinConstantArgShiftedByteOrXXFF(CallExpr *TheCall,
+ int ArgNum) {
+ llvm::APSInt Result;
+
+ // We can't check the value of a dependent argument.
+ Expr *Arg = TheCall->getArg(ArgNum);
+ if (Arg->isTypeDependent() || Arg->isValueDependent())
+ return false;
+
+ // Check constant-ness first.
+ if (SemaBuiltinConstantArg(TheCall, ArgNum, Result))
+ return true;
+
+ // Check to see if it's in either of the required forms.
+ if (IsShiftedByte(Result) ||
+ (Result > 0 && Result < 0x10000 && (Result & 0xFF) == 0xFF))
+ return false;
+
+ return Diag(TheCall->getBeginLoc(),
+ diag::err_argument_not_shifted_byte_or_xxff)
+ << Arg->getSourceRange();
+}
+
/// SemaBuiltinARMMemoryTaggingCall - Handle calls of memory tagging extensions
bool Sema::SemaBuiltinARMMemoryTaggingCall(unsigned BuiltinID, CallExpr *TheCall) {
if (BuiltinID == AArch64::BI__builtin_arm_irg) {
@@ -9162,7 +9386,7 @@ void Sema::CheckMaxUnsignedZero(const CallExpr *Call,
auto IsLiteralZeroArg = [](const Expr* E) -> bool {
const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E);
if (!MTE) return false;
- const auto *Num = dyn_cast<IntegerLiteral>(MTE->GetTemporaryExpr());
+ const auto *Num = dyn_cast<IntegerLiteral>(MTE->getSubExpr());
if (!Num) return false;
if (Num->getValue() != 0) return false;
return true;
@@ -11371,32 +11595,6 @@ static const IntegerLiteral *getIntegerLiteral(Expr *E) {
return IL;
}
-static void CheckConditionalWithEnumTypes(Sema &S, SourceLocation Loc,
- Expr *LHS, Expr *RHS) {
- QualType LHSStrippedType = LHS->IgnoreParenImpCasts()->getType();
- QualType RHSStrippedType = RHS->IgnoreParenImpCasts()->getType();
-
- const auto *LHSEnumType = LHSStrippedType->getAs<EnumType>();
- if (!LHSEnumType)
- return;
- const auto *RHSEnumType = RHSStrippedType->getAs<EnumType>();
- if (!RHSEnumType)
- return;
-
- // Ignore anonymous enums.
- if (!LHSEnumType->getDecl()->hasNameForLinkage())
- return;
- if (!RHSEnumType->getDecl()->hasNameForLinkage())
- return;
-
- if (S.Context.hasSameUnqualifiedType(LHSStrippedType, RHSStrippedType))
- return;
-
- S.Diag(Loc, diag::warn_conditional_mixed_enum_types)
- << LHSStrippedType << RHSStrippedType << LHS->getSourceRange()
- << RHS->getSourceRange();
-}
-
static void DiagnoseIntInBoolContext(Sema &S, Expr *E) {
E = E->IgnoreParenImpCasts();
SourceLocation ExprLoc = E->getExprLoc();
@@ -11737,7 +11935,7 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
return;
if (isObjCSignedCharBool(S, T) && !Source->isCharType() &&
- !E->isKnownToHaveBooleanValue()) {
+ !E->isKnownToHaveBooleanValue(/*Semantic=*/false)) {
return adornObjCBoolConversionDiagWithTernaryFixit(
S, E,
S.Diag(CC, diag::warn_impcast_int_to_objc_signed_char_bool)
@@ -11888,8 +12086,6 @@ static void CheckConditionalOperator(Sema &S, ConditionalOperator *E,
bool Suspicious = false;
CheckConditionalOperand(S, E->getTrueExpr(), T, CC, Suspicious);
CheckConditionalOperand(S, E->getFalseExpr(), T, CC, Suspicious);
- CheckConditionalWithEnumTypes(S, E->getBeginLoc(), E->getTrueExpr(),
- E->getFalseExpr());
if (T->isBooleanType())
DiagnoseIntInBoolContext(S, E);
@@ -12360,8 +12556,8 @@ namespace {
/// Visitor for expressions which looks for unsequenced operations on the
/// same object.
-class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
- using Base = EvaluatedExprVisitor<SequenceChecker>;
+class SequenceChecker : public ConstEvaluatedExprVisitor<SequenceChecker> {
+ using Base = ConstEvaluatedExprVisitor<SequenceChecker>;
/// A tree of sequenced regions within an expression. Two regions are
/// unsequenced if one is an ancestor or a descendent of the other. When we
@@ -12431,7 +12627,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
};
/// An object for which we can track unsequenced uses.
- using Object = NamedDecl *;
+ using Object = const NamedDecl *;
/// Different flavors of object usage which we track. We only track the
/// least-sequenced usage of each kind.
@@ -12450,17 +12646,19 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
UK_Count = UK_ModAsSideEffect + 1
};
+ /// Bundle together a sequencing region and the expression corresponding
+ /// to a specific usage. One Usage is stored for each usage kind in UsageInfo.
struct Usage {
- Expr *Use;
+ const Expr *UsageExpr;
SequenceTree::Seq Seq;
- Usage() : Use(nullptr), Seq() {}
+ Usage() : UsageExpr(nullptr), Seq() {}
};
struct UsageInfo {
Usage Uses[UK_Count];
- /// Have we issued a diagnostic for this variable already?
+ /// Have we issued a diagnostic for this object already?
bool Diagnosed;
UsageInfo() : Uses(), Diagnosed(false) {}
@@ -12484,7 +12682,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
/// Expressions to check later. We defer checking these to reduce
/// stack usage.
- SmallVectorImpl<Expr *> &WorkList;
+ SmallVectorImpl<const Expr *> &WorkList;
/// RAII object wrapping the visitation of a sequenced subexpression of an
/// expression. At the end of this process, the side-effects of the evaluation
@@ -12498,10 +12696,13 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
}
~SequencedSubexpression() {
- for (auto &M : llvm::reverse(ModAsSideEffect)) {
- UsageInfo &U = Self.UsageMap[M.first];
- auto &SideEffectUsage = U.Uses[UK_ModAsSideEffect];
- Self.addUsage(U, M.first, SideEffectUsage.Use, UK_ModAsValue);
+ for (const std::pair<Object, Usage> &M : llvm::reverse(ModAsSideEffect)) {
+ // Add a new usage with usage kind UK_ModAsValue, and then restore
+ // the previous usage with UK_ModAsSideEffect (thus clearing it if
+ // the previous one was empty).
+ UsageInfo &UI = Self.UsageMap[M.first];
+ auto &SideEffectUsage = UI.Uses[UK_ModAsSideEffect];
+ Self.addUsage(M.first, UI, SideEffectUsage.UsageExpr, UK_ModAsValue);
SideEffectUsage = M.second;
}
Self.ModAsSideEffect = OldModAsSideEffect;
@@ -12545,49 +12746,60 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
/// Find the object which is produced by the specified expression,
/// if any.
- Object getObject(Expr *E, bool Mod) const {
+ Object getObject(const Expr *E, bool Mod) const {
E = E->IgnoreParenCasts();
- if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
+ if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
if (Mod && (UO->getOpcode() == UO_PreInc || UO->getOpcode() == UO_PreDec))
return getObject(UO->getSubExpr(), Mod);
- } else if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
+ } else if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
if (BO->getOpcode() == BO_Comma)
return getObject(BO->getRHS(), Mod);
if (Mod && BO->isAssignmentOp())
return getObject(BO->getLHS(), Mod);
- } else if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
+ } else if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
// FIXME: Check for more interesting cases, like "x.n = ++x.n".
if (isa<CXXThisExpr>(ME->getBase()->IgnoreParenCasts()))
return ME->getMemberDecl();
- } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
+ } else if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
// FIXME: If this is a reference, map through to its value.
return DRE->getDecl();
return nullptr;
}
- /// Note that an object was modified or used by an expression.
- void addUsage(UsageInfo &UI, Object O, Expr *Ref, UsageKind UK) {
+ /// Note that an object \p O was modified or used by an expression
+ /// \p UsageExpr with usage kind \p UK. \p UI is the \p UsageInfo for
+ /// the object \p O as obtained via the \p UsageMap.
+ void addUsage(Object O, UsageInfo &UI, const Expr *UsageExpr, UsageKind UK) {
+ // Get the old usage for the given object and usage kind.
Usage &U = UI.Uses[UK];
- if (!U.Use || !Tree.isUnsequenced(Region, U.Seq)) {
+ if (!U.UsageExpr || !Tree.isUnsequenced(Region, U.Seq)) {
+ // If we have a modification as side effect and are in a sequenced
+ // subexpression, save the old Usage so that we can restore it later
+ // in SequencedSubexpression::~SequencedSubexpression.
if (UK == UK_ModAsSideEffect && ModAsSideEffect)
ModAsSideEffect->push_back(std::make_pair(O, U));
- U.Use = Ref;
+ // Then record the new usage with the current sequencing region.
+ U.UsageExpr = UsageExpr;
U.Seq = Region;
}
}
- /// Check whether a modification or use conflicts with a prior usage.
- void checkUsage(Object O, UsageInfo &UI, Expr *Ref, UsageKind OtherKind,
- bool IsModMod) {
+ /// Check whether a modification or use of an object \p O in an expression
+ /// \p UsageExpr conflicts with a prior usage of kind \p OtherKind. \p UI is
+ /// the \p UsageInfo for the object \p O as obtained via the \p UsageMap.
+ /// \p IsModMod is true when we are checking for a mod-mod unsequenced
+ /// usage and false we are checking for a mod-use unsequenced usage.
+ void checkUsage(Object O, UsageInfo &UI, const Expr *UsageExpr,
+ UsageKind OtherKind, bool IsModMod) {
if (UI.Diagnosed)
return;
const Usage &U = UI.Uses[OtherKind];
- if (!U.Use || !Tree.isUnsequenced(Region, U.Seq))
+ if (!U.UsageExpr || !Tree.isUnsequenced(Region, U.Seq))
return;
- Expr *Mod = U.Use;
- Expr *ModOrUse = Ref;
+ const Expr *Mod = U.UsageExpr;
+ const Expr *ModOrUse = UsageExpr;
if (OtherKind == UK_Use)
std::swap(Mod, ModOrUse);
@@ -12599,47 +12811,79 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
UI.Diagnosed = true;
}
- void notePreUse(Object O, Expr *Use) {
- UsageInfo &U = UsageMap[O];
+ // A note on note{Pre, Post}{Use, Mod}:
+ //
+ // (It helps to follow the algorithm with an expression such as
+ // "((++k)++, k) = k" or "k = (k++, k++)". Both contain unsequenced
+ // operations before C++17 and both are well-defined in C++17).
+ //
+ // When visiting a node which uses/modify an object we first call notePreUse
+ // or notePreMod before visiting its sub-expression(s). At this point the
+ // children of the current node have not yet been visited and so the eventual
+ // uses/modifications resulting from the children of the current node have not
+ // been recorded yet.
+ //
+ // We then visit the children of the current node. After that notePostUse or
+ // notePostMod is called. These will 1) detect an unsequenced modification
+ // as side effect (as in "k++ + k") and 2) add a new usage with the
+ // appropriate usage kind.
+ //
+ // We also have to be careful that some operation sequences modification as
+ // side effect as well (for example: || or ,). To account for this we wrap
+ // the visitation of such a sub-expression (for example: the LHS of || or ,)
+ // with SequencedSubexpression. SequencedSubexpression is an RAII object
+ // which record usages which are modifications as side effect, and then
+ // downgrade them (or more accurately restore the previous usage which was a
+ // modification as side effect) when exiting the scope of the sequenced
+ // subexpression.
+
+ void notePreUse(Object O, const Expr *UseExpr) {
+ UsageInfo &UI = UsageMap[O];
// Uses conflict with other modifications.
- checkUsage(O, U, Use, UK_ModAsValue, false);
+ checkUsage(O, UI, UseExpr, /*OtherKind=*/UK_ModAsValue, /*IsModMod=*/false);
}
- void notePostUse(Object O, Expr *Use) {
- UsageInfo &U = UsageMap[O];
- checkUsage(O, U, Use, UK_ModAsSideEffect, false);
- addUsage(U, O, Use, UK_Use);
+ void notePostUse(Object O, const Expr *UseExpr) {
+ UsageInfo &UI = UsageMap[O];
+ checkUsage(O, UI, UseExpr, /*OtherKind=*/UK_ModAsSideEffect,
+ /*IsModMod=*/false);
+ addUsage(O, UI, UseExpr, /*UsageKind=*/UK_Use);
}
- void notePreMod(Object O, Expr *Mod) {
- UsageInfo &U = UsageMap[O];
+ void notePreMod(Object O, const Expr *ModExpr) {
+ UsageInfo &UI = UsageMap[O];
// Modifications conflict with other modifications and with uses.
- checkUsage(O, U, Mod, UK_ModAsValue, true);
- checkUsage(O, U, Mod, UK_Use, false);
+ checkUsage(O, UI, ModExpr, /*OtherKind=*/UK_ModAsValue, /*IsModMod=*/true);
+ checkUsage(O, UI, ModExpr, /*OtherKind=*/UK_Use, /*IsModMod=*/false);
}
- void notePostMod(Object O, Expr *Use, UsageKind UK) {
- UsageInfo &U = UsageMap[O];
- checkUsage(O, U, Use, UK_ModAsSideEffect, true);
- addUsage(U, O, Use, UK);
+ void notePostMod(Object O, const Expr *ModExpr, UsageKind UK) {
+ UsageInfo &UI = UsageMap[O];
+ checkUsage(O, UI, ModExpr, /*OtherKind=*/UK_ModAsSideEffect,
+ /*IsModMod=*/true);
+ addUsage(O, UI, ModExpr, /*UsageKind=*/UK);
}
public:
- SequenceChecker(Sema &S, Expr *E, SmallVectorImpl<Expr *> &WorkList)
+ SequenceChecker(Sema &S, const Expr *E,
+ SmallVectorImpl<const Expr *> &WorkList)
: Base(S.Context), SemaRef(S), Region(Tree.root()), WorkList(WorkList) {
Visit(E);
+ // Silence a -Wunused-private-field since WorkList is now unused.
+ // TODO: Evaluate if it can be used, and if not remove it.
+ (void)this->WorkList;
}
- void VisitStmt(Stmt *S) {
+ void VisitStmt(const Stmt *S) {
// Skip all statements which aren't expressions for now.
}
- void VisitExpr(Expr *E) {
+ void VisitExpr(const Expr *E) {
// By default, just recurse to evaluated subexpressions.
Base::VisitStmt(E);
}
- void VisitCastExpr(CastExpr *E) {
+ void VisitCastExpr(const CastExpr *E) {
Object O = Object();
if (E->getCastKind() == CK_LValueToRValue)
O = getObject(E->getSubExpr(), false);
@@ -12651,7 +12895,8 @@ public:
notePostUse(O, E);
}
- void VisitSequencedExpressions(Expr *SequencedBefore, Expr *SequencedAfter) {
+ void VisitSequencedExpressions(const Expr *SequencedBefore,
+ const Expr *SequencedAfter) {
SequenceTree::Seq BeforeRegion = Tree.allocate(Region);
SequenceTree::Seq AfterRegion = Tree.allocate(Region);
SequenceTree::Seq OldRegion = Region;
@@ -12671,17 +12916,46 @@ public:
Tree.merge(AfterRegion);
}
- void VisitArraySubscriptExpr(ArraySubscriptExpr *ASE) {
+ void VisitArraySubscriptExpr(const ArraySubscriptExpr *ASE) {
// C++17 [expr.sub]p1:
// The expression E1[E2] is identical (by definition) to *((E1)+(E2)). The
// expression E1 is sequenced before the expression E2.
if (SemaRef.getLangOpts().CPlusPlus17)
VisitSequencedExpressions(ASE->getLHS(), ASE->getRHS());
- else
- Base::VisitStmt(ASE);
+ else {
+ Visit(ASE->getLHS());
+ Visit(ASE->getRHS());
+ }
+ }
+
+ void VisitBinPtrMemD(const BinaryOperator *BO) { VisitBinPtrMem(BO); }
+ void VisitBinPtrMemI(const BinaryOperator *BO) { VisitBinPtrMem(BO); }
+ void VisitBinPtrMem(const BinaryOperator *BO) {
+ // C++17 [expr.mptr.oper]p4:
+ // Abbreviating pm-expression.*cast-expression as E1.*E2, [...]
+ // the expression E1 is sequenced before the expression E2.
+ if (SemaRef.getLangOpts().CPlusPlus17)
+ VisitSequencedExpressions(BO->getLHS(), BO->getRHS());
+ else {
+ Visit(BO->getLHS());
+ Visit(BO->getRHS());
+ }
}
- void VisitBinComma(BinaryOperator *BO) {
+ void VisitBinShl(const BinaryOperator *BO) { VisitBinShlShr(BO); }
+ void VisitBinShr(const BinaryOperator *BO) { VisitBinShlShr(BO); }
+ void VisitBinShlShr(const BinaryOperator *BO) {
+ // C++17 [expr.shift]p4:
+ // The expression E1 is sequenced before the expression E2.
+ if (SemaRef.getLangOpts().CPlusPlus17)
+ VisitSequencedExpressions(BO->getLHS(), BO->getRHS());
+ else {
+ Visit(BO->getLHS());
+ Visit(BO->getRHS());
+ }
+ }
+
+ void VisitBinComma(const BinaryOperator *BO) {
// C++11 [expr.comma]p1:
// Every value computation and side effect associated with the left
// expression is sequenced before every value computation and side
@@ -12689,47 +12963,77 @@ public:
VisitSequencedExpressions(BO->getLHS(), BO->getRHS());
}
- void VisitBinAssign(BinaryOperator *BO) {
- // The modification is sequenced after the value computation of the LHS
- // and RHS, so check it before inspecting the operands and update the
+ void VisitBinAssign(const BinaryOperator *BO) {
+ SequenceTree::Seq RHSRegion;
+ SequenceTree::Seq LHSRegion;
+ if (SemaRef.getLangOpts().CPlusPlus17) {
+ RHSRegion = Tree.allocate(Region);
+ LHSRegion = Tree.allocate(Region);
+ } else {
+ RHSRegion = Region;
+ LHSRegion = Region;
+ }
+ SequenceTree::Seq OldRegion = Region;
+
+ // C++11 [expr.ass]p1:
+ // [...] the assignment is sequenced after the value computation
+ // of the right and left operands, [...]
+ //
+ // so check it before inspecting the operands and update the
// map afterwards.
- Object O = getObject(BO->getLHS(), true);
- if (!O)
- return VisitExpr(BO);
+ Object O = getObject(BO->getLHS(), /*Mod=*/true);
+ if (O)
+ notePreMod(O, BO);
+
+ if (SemaRef.getLangOpts().CPlusPlus17) {
+ // C++17 [expr.ass]p1:
+ // [...] The right operand is sequenced before the left operand. [...]
+ {
+ SequencedSubexpression SeqBefore(*this);
+ Region = RHSRegion;
+ Visit(BO->getRHS());
+ }
- notePreMod(O, BO);
+ Region = LHSRegion;
+ Visit(BO->getLHS());
- // C++11 [expr.ass]p7:
- // E1 op= E2 is equivalent to E1 = E1 op E2, except that E1 is evaluated
- // only once.
- //
- // Therefore, for a compound assignment operator, O is considered used
- // everywhere except within the evaluation of E1 itself.
- if (isa<CompoundAssignOperator>(BO))
- notePreUse(O, BO);
+ if (O && isa<CompoundAssignOperator>(BO))
+ notePostUse(O, BO);
- Visit(BO->getLHS());
+ } else {
+ // C++11 does not specify any sequencing between the LHS and RHS.
+ Region = LHSRegion;
+ Visit(BO->getLHS());
- if (isa<CompoundAssignOperator>(BO))
- notePostUse(O, BO);
+ if (O && isa<CompoundAssignOperator>(BO))
+ notePostUse(O, BO);
- Visit(BO->getRHS());
+ Region = RHSRegion;
+ Visit(BO->getRHS());
+ }
// C++11 [expr.ass]p1:
- // the assignment is sequenced [...] before the value computation of the
- // assignment expression.
+ // the assignment is sequenced [...] before the value computation of the
+ // assignment expression.
// C11 6.5.16/3 has no such rule.
- notePostMod(O, BO, SemaRef.getLangOpts().CPlusPlus ? UK_ModAsValue
- : UK_ModAsSideEffect);
+ Region = OldRegion;
+ if (O)
+ notePostMod(O, BO,
+ SemaRef.getLangOpts().CPlusPlus ? UK_ModAsValue
+ : UK_ModAsSideEffect);
+ if (SemaRef.getLangOpts().CPlusPlus17) {
+ Tree.merge(RHSRegion);
+ Tree.merge(LHSRegion);
+ }
}
- void VisitCompoundAssignOperator(CompoundAssignOperator *CAO) {
+ void VisitCompoundAssignOperator(const CompoundAssignOperator *CAO) {
VisitBinAssign(CAO);
}
- void VisitUnaryPreInc(UnaryOperator *UO) { VisitUnaryPreIncDec(UO); }
- void VisitUnaryPreDec(UnaryOperator *UO) { VisitUnaryPreIncDec(UO); }
- void VisitUnaryPreIncDec(UnaryOperator *UO) {
+ void VisitUnaryPreInc(const UnaryOperator *UO) { VisitUnaryPreIncDec(UO); }
+ void VisitUnaryPreDec(const UnaryOperator *UO) { VisitUnaryPreIncDec(UO); }
+ void VisitUnaryPreIncDec(const UnaryOperator *UO) {
Object O = getObject(UO->getSubExpr(), true);
if (!O)
return VisitExpr(UO);
@@ -12738,13 +13042,14 @@ public:
Visit(UO->getSubExpr());
// C++11 [expr.pre.incr]p1:
// the expression ++x is equivalent to x+=1
- notePostMod(O, UO, SemaRef.getLangOpts().CPlusPlus ? UK_ModAsValue
- : UK_ModAsSideEffect);
+ notePostMod(O, UO,
+ SemaRef.getLangOpts().CPlusPlus ? UK_ModAsValue
+ : UK_ModAsSideEffect);
}
- void VisitUnaryPostInc(UnaryOperator *UO) { VisitUnaryPostIncDec(UO); }
- void VisitUnaryPostDec(UnaryOperator *UO) { VisitUnaryPostIncDec(UO); }
- void VisitUnaryPostIncDec(UnaryOperator *UO) {
+ void VisitUnaryPostInc(const UnaryOperator *UO) { VisitUnaryPostIncDec(UO); }
+ void VisitUnaryPostDec(const UnaryOperator *UO) { VisitUnaryPostIncDec(UO); }
+ void VisitUnaryPostIncDec(const UnaryOperator *UO) {
Object O = getObject(UO->getSubExpr(), true);
if (!O)
return VisitExpr(UO);
@@ -12754,67 +13059,129 @@ public:
notePostMod(O, UO, UK_ModAsSideEffect);
}
- /// Don't visit the RHS of '&&' or '||' if it might not be evaluated.
- void VisitBinLOr(BinaryOperator *BO) {
- // The side-effects of the LHS of an '&&' are sequenced before the
- // value computation of the RHS, and hence before the value computation
- // of the '&&' itself, unless the LHS evaluates to zero. We treat them
- // as if they were unconditionally sequenced.
+ void VisitBinLOr(const BinaryOperator *BO) {
+ // C++11 [expr.log.or]p2:
+ // If the second expression is evaluated, every value computation and
+ // side effect associated with the first expression is sequenced before
+ // every value computation and side effect associated with the
+ // second expression.
+ SequenceTree::Seq LHSRegion = Tree.allocate(Region);
+ SequenceTree::Seq RHSRegion = Tree.allocate(Region);
+ SequenceTree::Seq OldRegion = Region;
+
EvaluationTracker Eval(*this);
{
SequencedSubexpression Sequenced(*this);
+ Region = LHSRegion;
Visit(BO->getLHS());
}
- bool Result;
- if (Eval.evaluate(BO->getLHS(), Result)) {
- if (!Result)
- Visit(BO->getRHS());
- } else {
- // Check for unsequenced operations in the RHS, treating it as an
- // entirely separate evaluation.
- //
- // FIXME: If there are operations in the RHS which are unsequenced
- // with respect to operations outside the RHS, and those operations
- // are unconditionally evaluated, diagnose them.
- WorkList.push_back(BO->getRHS());
+ // C++11 [expr.log.or]p1:
+ // [...] the second operand is not evaluated if the first operand
+ // evaluates to true.
+ bool EvalResult = false;
+ bool EvalOK = Eval.evaluate(BO->getLHS(), EvalResult);
+ bool ShouldVisitRHS = !EvalOK || (EvalOK && !EvalResult);
+ if (ShouldVisitRHS) {
+ Region = RHSRegion;
+ Visit(BO->getRHS());
}
- }
- void VisitBinLAnd(BinaryOperator *BO) {
+
+ Region = OldRegion;
+ Tree.merge(LHSRegion);
+ Tree.merge(RHSRegion);
+ }
+
+ void VisitBinLAnd(const BinaryOperator *BO) {
+ // C++11 [expr.log.and]p2:
+ // If the second expression is evaluated, every value computation and
+ // side effect associated with the first expression is sequenced before
+ // every value computation and side effect associated with the
+ // second expression.
+ SequenceTree::Seq LHSRegion = Tree.allocate(Region);
+ SequenceTree::Seq RHSRegion = Tree.allocate(Region);
+ SequenceTree::Seq OldRegion = Region;
+
EvaluationTracker Eval(*this);
{
SequencedSubexpression Sequenced(*this);
+ Region = LHSRegion;
Visit(BO->getLHS());
}
- bool Result;
- if (Eval.evaluate(BO->getLHS(), Result)) {
- if (Result)
- Visit(BO->getRHS());
- } else {
- WorkList.push_back(BO->getRHS());
+ // C++11 [expr.log.and]p1:
+ // [...] the second operand is not evaluated if the first operand is false.
+ bool EvalResult = false;
+ bool EvalOK = Eval.evaluate(BO->getLHS(), EvalResult);
+ bool ShouldVisitRHS = !EvalOK || (EvalOK && EvalResult);
+ if (ShouldVisitRHS) {
+ Region = RHSRegion;
+ Visit(BO->getRHS());
}
- }
- // Only visit the condition, unless we can be sure which subexpression will
- // be chosen.
- void VisitAbstractConditionalOperator(AbstractConditionalOperator *CO) {
+ Region = OldRegion;
+ Tree.merge(LHSRegion);
+ Tree.merge(RHSRegion);
+ }
+
+ void VisitAbstractConditionalOperator(const AbstractConditionalOperator *CO) {
+ // C++11 [expr.cond]p1:
+ // [...] Every value computation and side effect associated with the first
+ // expression is sequenced before every value computation and side effect
+ // associated with the second or third expression.
+ SequenceTree::Seq ConditionRegion = Tree.allocate(Region);
+
+ // No sequencing is specified between the true and false expression.
+ // However since exactly one of both is going to be evaluated we can
+ // consider them to be sequenced. This is needed to avoid warning on
+ // something like "x ? y+= 1 : y += 2;" in the case where we will visit
+ // both the true and false expressions because we can't evaluate x.
+ // This will still allow us to detect an expression like (pre C++17)
+ // "(x ? y += 1 : y += 2) = y".
+ //
+ // We don't wrap the visitation of the true and false expression with
+ // SequencedSubexpression because we don't want to downgrade modifications
+ // as side effect in the true and false expressions after the visition
+ // is done. (for example in the expression "(x ? y++ : y++) + y" we should
+ // not warn between the two "y++", but we should warn between the "y++"
+ // and the "y".
+ SequenceTree::Seq TrueRegion = Tree.allocate(Region);
+ SequenceTree::Seq FalseRegion = Tree.allocate(Region);
+ SequenceTree::Seq OldRegion = Region;
+
EvaluationTracker Eval(*this);
{
SequencedSubexpression Sequenced(*this);
+ Region = ConditionRegion;
Visit(CO->getCond());
}
- bool Result;
- if (Eval.evaluate(CO->getCond(), Result))
- Visit(Result ? CO->getTrueExpr() : CO->getFalseExpr());
- else {
- WorkList.push_back(CO->getTrueExpr());
- WorkList.push_back(CO->getFalseExpr());
+ // C++11 [expr.cond]p1:
+ // [...] The first expression is contextually converted to bool (Clause 4).
+ // It is evaluated and if it is true, the result of the conditional
+ // expression is the value of the second expression, otherwise that of the
+ // third expression. Only one of the second and third expressions is
+ // evaluated. [...]
+ bool EvalResult = false;
+ bool EvalOK = Eval.evaluate(CO->getCond(), EvalResult);
+ bool ShouldVisitTrueExpr = !EvalOK || (EvalOK && EvalResult);
+ bool ShouldVisitFalseExpr = !EvalOK || (EvalOK && !EvalResult);
+ if (ShouldVisitTrueExpr) {
+ Region = TrueRegion;
+ Visit(CO->getTrueExpr());
+ }
+ if (ShouldVisitFalseExpr) {
+ Region = FalseRegion;
+ Visit(CO->getFalseExpr());
}
+
+ Region = OldRegion;
+ Tree.merge(ConditionRegion);
+ Tree.merge(TrueRegion);
+ Tree.merge(FalseRegion);
}
- void VisitCallExpr(CallExpr *CE) {
+ void VisitCallExpr(const CallExpr *CE) {
// C++11 [intro.execution]p15:
// When calling a function [...], every value computation and side effect
// associated with any argument expression, or with the postfix expression
@@ -12822,12 +13189,13 @@ public:
// expression or statement in the body of the function [and thus before
// the value computation of its result].
SequencedSubexpression Sequenced(*this);
- Base::VisitCallExpr(CE);
+ SemaRef.runWithSufficientStackSpace(CE->getExprLoc(),
+ [&] { Base::VisitCallExpr(CE); });
// FIXME: CXXNewExpr and CXXDeleteExpr implicitly call functions.
}
- void VisitCXXConstructExpr(CXXConstructExpr *CCE) {
+ void VisitCXXConstructExpr(const CXXConstructExpr *CCE) {
// This is a call, so all subexpressions are sequenced before the result.
SequencedSubexpression Sequenced(*this);
@@ -12837,8 +13205,8 @@ public:
// In C++11, list initializations are sequenced.
SmallVector<SequenceTree::Seq, 32> Elts;
SequenceTree::Seq Parent = Region;
- for (CXXConstructExpr::arg_iterator I = CCE->arg_begin(),
- E = CCE->arg_end();
+ for (CXXConstructExpr::const_arg_iterator I = CCE->arg_begin(),
+ E = CCE->arg_end();
I != E; ++I) {
Region = Tree.allocate(Parent);
Elts.push_back(Region);
@@ -12851,7 +13219,7 @@ public:
Tree.merge(Elts[I]);
}
- void VisitInitListExpr(InitListExpr *ILE) {
+ void VisitInitListExpr(const InitListExpr *ILE) {
if (!SemaRef.getLangOpts().CPlusPlus11)
return VisitExpr(ILE);
@@ -12859,8 +13227,9 @@ public:
SmallVector<SequenceTree::Seq, 32> Elts;
SequenceTree::Seq Parent = Region;
for (unsigned I = 0; I < ILE->getNumInits(); ++I) {
- Expr *E = ILE->getInit(I);
- if (!E) continue;
+ const Expr *E = ILE->getInit(I);
+ if (!E)
+ continue;
Region = Tree.allocate(Parent);
Elts.push_back(Region);
Visit(E);
@@ -12875,11 +13244,11 @@ public:
} // namespace
-void Sema::CheckUnsequencedOperations(Expr *E) {
- SmallVector<Expr *, 8> WorkList;
+void Sema::CheckUnsequencedOperations(const Expr *E) {
+ SmallVector<const Expr *, 8> WorkList;
WorkList.push_back(E);
while (!WorkList.empty()) {
- Expr *Item = WorkList.pop_back_val();
+ const Expr *Item = WorkList.pop_back_val();
SequenceChecker(*this, Item, WorkList);
}
}
@@ -14577,6 +14946,8 @@ void Sema::RefersToMemberWithReducedAlignment(
bool AnyIsPacked = false;
do {
QualType BaseType = ME->getBase()->getType();
+ if (BaseType->isDependentType())
+ return;
if (ME->isArrow())
BaseType = BaseType->getPointeeType();
RecordDecl *RD = BaseType->castAs<RecordType>()->getDecl();
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index f24c3b234ff2..7260977c634d 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -692,18 +692,6 @@ getRequiredQualification(ASTContext &Context, const DeclContext *CurContext,
return Result;
}
-/// Determine whether \p Id is a name reserved for the implementation (C99
-/// 7.1.3, C++ [lib.global.names]).
-static bool isReservedName(const IdentifierInfo *Id,
- bool doubleUnderscoreOnly = false) {
- if (Id->getLength() < 2)
- return false;
- const char *Name = Id->getNameStart();
- return Name[0] == '_' &&
- (Name[1] == '_' ||
- (Name[1] >= 'A' && Name[1] <= 'Z' && !doubleUnderscoreOnly));
-}
-
// Some declarations have reserved names that we don't want to ever show.
// Filter out names reserved for the implementation if they come from a
// system header.
@@ -713,13 +701,13 @@ static bool shouldIgnoreDueToReservedName(const NamedDecl *ND, Sema &SemaRef) {
return false;
// Ignore reserved names for compiler provided decls.
- if (isReservedName(Id) && ND->getLocation().isInvalid())
+ if (Id->isReservedName() && ND->getLocation().isInvalid())
return true;
// For system headers ignore only double-underscore names.
// This allows for system headers providing private symbols with a single
// underscore.
- if (isReservedName(Id, /*doubleUnderscoreOnly=*/true) &&
+ if (Id->isReservedName(/*doubleUnderscoreOnly=*/true) &&
SemaRef.SourceMgr.isInSystemHeader(
SemaRef.SourceMgr.getSpellingLoc(ND->getLocation())))
return true;
@@ -1321,7 +1309,7 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext,
/// Motivating case is const_iterator begin() const vs iterator begin().
auto &OverloadSet = OverloadMap[std::make_pair(
CurContext, Method->getDeclName().getAsOpaqueInteger())];
- for (const DeclIndexPair& Entry : OverloadSet) {
+ for (const DeclIndexPair Entry : OverloadSet) {
Result &Incumbent = Results[Entry.second];
switch (compareOverloads(*Method,
*cast<CXXMethodDecl>(Incumbent.Declaration),
@@ -2324,6 +2312,13 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S,
Builder.AddChunk(CodeCompletionString::CK_SemiColon);
Results.AddResult(Result(Builder.TakeString()));
}
+ // For pointers, suggest 'return nullptr' in C++.
+ if (SemaRef.getLangOpts().CPlusPlus11 &&
+ (ReturnType->isPointerType() || ReturnType->isMemberPointerType())) {
+ Builder.AddTypedTextChunk("return nullptr");
+ Builder.AddChunk(CodeCompletionString::CK_SemiColon);
+ Results.AddResult(Result(Builder.TakeString()));
+ }
}
// goto identifier ;
@@ -2991,7 +2986,11 @@ static void AddTemplateParameterChunks(
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*P)) {
if (TTP->wasDeclaredWithTypename())
PlaceholderStr = "typename";
- else
+ else if (const auto *TC = TTP->getTypeConstraint()) {
+ llvm::raw_string_ostream OS(PlaceholderStr);
+ TC->print(OS, Policy);
+ OS.flush();
+ } else
PlaceholderStr = "class";
if (TTP->getIdentifier()) {
@@ -3327,6 +3326,18 @@ CodeCompletionResult::createCodeCompletionStringForOverride(
return Result.TakeString();
}
+// FIXME: Right now this works well with lambdas. Add support for other functor
+// types like std::function.
+static const NamedDecl *extractFunctorCallOperator(const NamedDecl *ND) {
+ const auto *VD = dyn_cast<VarDecl>(ND);
+ if (!VD)
+ return nullptr;
+ const auto *RecordDecl = VD->getType()->getAsCXXRecordDecl();
+ if (!RecordDecl || !RecordDecl->isLambda())
+ return nullptr;
+ return RecordDecl->getLambdaCallOperator();
+}
+
CodeCompletionString *CodeCompletionResult::createCodeCompletionStringForDecl(
Preprocessor &PP, ASTContext &Ctx, CodeCompletionBuilder &Result,
bool IncludeBriefComments, const CodeCompletionContext &CCContext,
@@ -3351,9 +3362,8 @@ CodeCompletionString *CodeCompletionResult::createCodeCompletionStringForDecl(
for (const auto *I : ND->specific_attrs<AnnotateAttr>())
Result.AddAnnotation(Result.getAllocator().CopyString(I->getAnnotation()));
- AddResultTypeChunk(Ctx, Policy, ND, CCContext.getBaseType(), Result);
-
- if (const auto *Function = dyn_cast<FunctionDecl>(ND)) {
+ auto AddFunctionTypeAndResult = [&](const FunctionDecl *Function) {
+ AddResultTypeChunk(Ctx, Policy, Function, CCContext.getBaseType(), Result);
AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
Ctx, Policy);
AddTypedNameChunk(Ctx, Policy, ND, Result);
@@ -3361,9 +3371,21 @@ CodeCompletionString *CodeCompletionResult::createCodeCompletionStringForDecl(
AddFunctionParameterChunks(PP, Policy, Function, Result);
Result.AddChunk(CodeCompletionString::CK_RightParen);
AddFunctionTypeQualsToCompletionString(Result, Function);
+ };
+
+ if (const auto *Function = dyn_cast<FunctionDecl>(ND)) {
+ AddFunctionTypeAndResult(Function);
+ return Result.TakeString();
+ }
+
+ if (const auto *CallOperator =
+ dyn_cast_or_null<FunctionDecl>(extractFunctorCallOperator(ND))) {
+ AddFunctionTypeAndResult(CallOperator);
return Result.TakeString();
}
+ AddResultTypeChunk(Ctx, Policy, ND, CCContext.getBaseType(), Result);
+
if (const FunctionTemplateDecl *FunTmpl =
dyn_cast<FunctionTemplateDecl>(ND)) {
AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
@@ -3429,6 +3451,7 @@ CodeCompletionString *CodeCompletionResult::createCodeCompletionStringForDecl(
Result.AddChunk(CodeCompletionString::CK_RightAngle);
return Result.TakeString();
}
+
if (const auto *Method = dyn_cast<ObjCMethodDecl>(ND)) {
Selector Sel = Method->getSelector();
if (Sel.isUnarySelector()) {
@@ -3653,6 +3676,10 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString(
unsigned CurrentArg, Sema &S, CodeCompletionAllocator &Allocator,
CodeCompletionTUInfo &CCTUInfo, bool IncludeBriefComments) const {
PrintingPolicy Policy = getCompletionPrintingPolicy(S);
+ // Show signatures of constructors as they are declared:
+ // vector(int n) rather than vector<string>(int n)
+ // This is less noisy without being less clear, and avoids tricky cases.
+ Policy.SuppressTemplateArgsInCXXConstructors = true;
// FIXME: Set priority, availability appropriately.
CodeCompletionBuilder Result(Allocator, CCTUInfo, 1,
@@ -4783,7 +4810,7 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base,
}
// Add properties from the protocols in a qualified interface.
- for (auto *I : BaseType->getAs<ObjCObjectPointerType>()->quals())
+ for (auto *I : BaseType->castAs<ObjCObjectPointerType>()->quals())
AddObjCProperties(CCContext, I, true, /*AllowNullaryMethods=*/true,
CurContext, AddedProperties, Results,
IsBaseExprStatement, /*IsClassProperty*/ false,
@@ -4796,7 +4823,7 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base,
BaseType->getAs<ObjCObjectPointerType>())
Class = ObjCPtr->getInterfaceDecl();
else
- Class = BaseType->getAs<ObjCObjectType>()->getInterface();
+ Class = BaseType->castAs<ObjCObjectType>()->getInterface();
// Add all ivars from this class and its superclasses.
if (Class) {
@@ -5330,18 +5357,21 @@ void Sema::CodeCompleteAfterIf(Scope *S) {
}
void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS,
- bool EnteringContext, QualType BaseType,
+ bool EnteringContext,
+ bool IsUsingDeclaration, QualType BaseType,
QualType PreferredType) {
if (SS.isEmpty() || !CodeCompleter)
return;
+ CodeCompletionContext CC(CodeCompletionContext::CCC_Symbol, PreferredType);
+ CC.setIsUsingDeclaration(IsUsingDeclaration);
+ CC.setCXXScopeSpecifier(SS);
+
// We want to keep the scope specifier even if it's invalid (e.g. the scope
// "a::b::" is not corresponding to any context/namespace in the AST), since
// it can be useful for global code completion which have information about
// contexts/symbols that are not in the AST.
if (SS.isInvalid()) {
- CodeCompletionContext CC(CodeCompletionContext::CCC_Symbol, PreferredType);
- CC.setCXXScopeSpecifier(SS);
// As SS is invalid, we try to collect accessible contexts from the current
// scope with a dummy lookup so that the completion consumer can try to
// guess what the specified scope is.
@@ -5371,10 +5401,8 @@ void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS,
if (!isDependentScopeSpecifier(SS) && RequireCompleteDeclContext(SS, Ctx))
return;
- ResultBuilder Results(
- *this, CodeCompleter->getAllocator(),
- CodeCompleter->getCodeCompletionTUInfo(),
- CodeCompletionContext(CodeCompletionContext::CCC_Symbol, PreferredType));
+ ResultBuilder Results(*this, CodeCompleter->getAllocator(),
+ CodeCompleter->getCodeCompletionTUInfo(), CC);
if (!PreferredType.isNull())
Results.setPreferredType(PreferredType);
Results.EnterNewScope();
@@ -5403,23 +5431,21 @@ void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS,
CodeCompleter->loadExternal());
}
- auto CC = Results.getCompletionContext();
- CC.setCXXScopeSpecifier(SS);
-
- HandleCodeCompleteResults(this, CodeCompleter, CC, Results.data(),
- Results.size());
+ HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(),
+ Results.data(), Results.size());
}
void Sema::CodeCompleteUsing(Scope *S) {
if (!CodeCompleter)
return;
+ // This can be both a using alias or using declaration, in the former we
+ // expect a new name and a symbol in the latter case.
+ CodeCompletionContext Context(CodeCompletionContext::CCC_SymbolOrNewName);
+ Context.setIsUsingDeclaration(true);
+
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
- CodeCompleter->getCodeCompletionTUInfo(),
- // This can be both a using alias or using
- // declaration, in the former we expect a new name and a
- // symbol in the latter case.
- CodeCompletionContext::CCC_SymbolOrNewName,
+ CodeCompleter->getCodeCompletionTUInfo(), Context,
&ResultBuilder::IsNestedNameSpecifier);
Results.EnterNewScope();
@@ -7721,8 +7747,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() == "NSArray"))) {
std::string SelectorName = (Twine(Property->getName()) + "AtIndexes").str();
@@ -8108,8 +8134,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() == "NSSet"))) {
std::string SelectorName =
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 848ccf543445..018ac2d7dc9d 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -11,15 +11,24 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Sema/SemaConcept.h"
#include "clang/Sema/Sema.h"
+#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaDiagnostic.h"
#include "clang/Sema/TemplateDeduction.h"
#include "clang/Sema/Template.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Basic/OperatorPrecedence.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/PointerUnion.h"
using namespace clang;
using namespace sema;
-bool Sema::CheckConstraintExpression(Expr *ConstraintExpression) {
+bool
+Sema::CheckConstraintExpression(Expr *ConstraintExpression, Token NextToken,
+ bool *PossibleNonPrimary,
+ bool IsTrailingRequiresClause) {
// C++2a [temp.constr.atomic]p1
// ..E shall be a constant expression of type bool.
@@ -27,99 +36,793 @@ bool Sema::CheckConstraintExpression(Expr *ConstraintExpression) {
if (auto *BinOp = dyn_cast<BinaryOperator>(ConstraintExpression)) {
if (BinOp->getOpcode() == BO_LAnd || BinOp->getOpcode() == BO_LOr)
- return CheckConstraintExpression(BinOp->getLHS()) &&
- CheckConstraintExpression(BinOp->getRHS());
+ return CheckConstraintExpression(BinOp->getLHS(), NextToken,
+ PossibleNonPrimary) &&
+ CheckConstraintExpression(BinOp->getRHS(), NextToken,
+ PossibleNonPrimary);
} else if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpression))
- return CheckConstraintExpression(C->getSubExpr());
+ return CheckConstraintExpression(C->getSubExpr(), NextToken,
+ PossibleNonPrimary);
+
+ QualType Type = ConstraintExpression->getType();
+
+ auto CheckForNonPrimary = [&] {
+ if (PossibleNonPrimary)
+ *PossibleNonPrimary =
+ // We have the following case:
+ // template<typename> requires func(0) struct S { };
+ // The user probably isn't aware of the parentheses required around
+ // the function call, and we're only going to parse 'func' as the
+ // primary-expression, and complain that it is of non-bool type.
+ (NextToken.is(tok::l_paren) &&
+ (IsTrailingRequiresClause ||
+ (Type->isDependentType() &&
+ IsDependentFunctionNameExpr(ConstraintExpression)) ||
+ Type->isFunctionType() ||
+ Type->isSpecificBuiltinType(BuiltinType::Overload))) ||
+ // We have the following case:
+ // template<typename T> requires size_<T> == 0 struct S { };
+ // The user probably isn't aware of the parentheses required around
+ // the binary operator, and we're only going to parse 'func' as the
+ // first operand, and complain that it is of non-bool type.
+ getBinOpPrecedence(NextToken.getKind(),
+ /*GreaterThanIsOperator=*/true,
+ getLangOpts().CPlusPlus11) > prec::LogicalAnd;
+ };
// An atomic constraint!
- if (ConstraintExpression->isTypeDependent())
+ if (ConstraintExpression->isTypeDependent()) {
+ CheckForNonPrimary();
return true;
+ }
- QualType Type = ConstraintExpression->getType();
if (!Context.hasSameUnqualifiedType(Type, Context.BoolTy)) {
Diag(ConstraintExpression->getExprLoc(),
diag::err_non_bool_atomic_constraint) << Type
<< ConstraintExpression->getSourceRange();
+ CheckForNonPrimary();
return false;
}
+
+ if (PossibleNonPrimary)
+ *PossibleNonPrimary = false;
return true;
}
-bool
-Sema::CalculateConstraintSatisfaction(ConceptDecl *NamedConcept,
- MultiLevelTemplateArgumentList &MLTAL,
- Expr *ConstraintExpr,
- bool &IsSatisfied) {
+template <typename AtomicEvaluator>
+static bool
+calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr,
+ ConstraintSatisfaction &Satisfaction,
+ AtomicEvaluator &&Evaluator) {
ConstraintExpr = ConstraintExpr->IgnoreParenImpCasts();
if (auto *BO = dyn_cast<BinaryOperator>(ConstraintExpr)) {
- if (BO->getOpcode() == BO_LAnd) {
- if (CalculateConstraintSatisfaction(NamedConcept, MLTAL, BO->getLHS(),
- IsSatisfied))
+ if (BO->getOpcode() == BO_LAnd || BO->getOpcode() == BO_LOr) {
+ if (calculateConstraintSatisfaction(S, BO->getLHS(), Satisfaction,
+ Evaluator))
return true;
- if (!IsSatisfied)
+
+ bool IsLHSSatisfied = Satisfaction.IsSatisfied;
+
+ if (BO->getOpcode() == BO_LOr && IsLHSSatisfied)
+ // [temp.constr.op] p3
+ // A disjunction is a constraint taking two operands. To determine if
+ // a disjunction is satisfied, the satisfaction of the first operand
+ // is checked. If that is satisfied, the disjunction is satisfied.
+ // Otherwise, the disjunction is satisfied if and only if the second
+ // operand is satisfied.
return false;
- return CalculateConstraintSatisfaction(NamedConcept, MLTAL, BO->getRHS(),
- IsSatisfied);
- } else if (BO->getOpcode() == BO_LOr) {
- if (CalculateConstraintSatisfaction(NamedConcept, MLTAL, BO->getLHS(),
- IsSatisfied))
- return true;
- if (IsSatisfied)
+
+ if (BO->getOpcode() == BO_LAnd && !IsLHSSatisfied)
+ // [temp.constr.op] p2
+ // A conjunction is a constraint taking two operands. To determine if
+ // a conjunction is satisfied, the satisfaction of the first operand
+ // is checked. If that is not satisfied, the conjunction is not
+ // satisfied. Otherwise, the conjunction is satisfied if and only if
+ // the second operand is satisfied.
return false;
- return CalculateConstraintSatisfaction(NamedConcept, MLTAL, BO->getRHS(),
- IsSatisfied);
+
+ return calculateConstraintSatisfaction(S, BO->getRHS(), Satisfaction,
+ std::forward<AtomicEvaluator>(Evaluator));
}
}
else if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpr))
- return CalculateConstraintSatisfaction(NamedConcept, MLTAL, C->getSubExpr(),
- IsSatisfied);
+ return calculateConstraintSatisfaction(S, C->getSubExpr(), Satisfaction,
+ std::forward<AtomicEvaluator>(Evaluator));
- EnterExpressionEvaluationContext ConstantEvaluated(
- *this, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+ // An atomic constraint expression
+ ExprResult SubstitutedAtomicExpr = Evaluator(ConstraintExpr);
- // Atomic constraint - substitute arguments and check satisfaction.
- ExprResult E;
- {
- TemplateDeductionInfo Info(ConstraintExpr->getBeginLoc());
- InstantiatingTemplate Inst(*this, ConstraintExpr->getBeginLoc(),
- InstantiatingTemplate::ConstraintSubstitution{},
- NamedConcept, Info,
- ConstraintExpr->getSourceRange());
- if (Inst.isInvalid())
- return true;
- // We do not want error diagnostics escaping here.
- Sema::SFINAETrap Trap(*this);
+ if (SubstitutedAtomicExpr.isInvalid())
+ return true;
+
+ if (!SubstitutedAtomicExpr.isUsable())
+ // Evaluator has decided satisfaction without yielding an expression.
+ return false;
- E = SubstExpr(ConstraintExpr, MLTAL);
- if (E.isInvalid() || Trap.hasErrorOccurred()) {
+ EnterExpressionEvaluationContext ConstantEvaluated(
+ S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+ SmallVector<PartialDiagnosticAt, 2> EvaluationDiags;
+ Expr::EvalResult EvalResult;
+ EvalResult.Diag = &EvaluationDiags;
+ if (!SubstitutedAtomicExpr.get()->EvaluateAsRValue(EvalResult, S.Context)) {
// C++2a [temp.constr.atomic]p1
- // ...If substitution results in an invalid type or expression, the
- // constraint is not satisfied.
- IsSatisfied = false;
+ // ...E shall be a constant expression of type bool.
+ S.Diag(SubstitutedAtomicExpr.get()->getBeginLoc(),
+ diag::err_non_constant_constraint_expression)
+ << SubstitutedAtomicExpr.get()->getSourceRange();
+ for (const PartialDiagnosticAt &PDiag : EvaluationDiags)
+ S.Diag(PDiag.first, PDiag.second);
+ return true;
+ }
+
+ Satisfaction.IsSatisfied = EvalResult.Val.getInt().getBoolValue();
+ if (!Satisfaction.IsSatisfied)
+ Satisfaction.Details.emplace_back(ConstraintExpr,
+ SubstitutedAtomicExpr.get());
+
+ return false;
+}
+
+template <typename TemplateDeclT>
+static bool calculateConstraintSatisfaction(
+ Sema &S, TemplateDeclT *Template, ArrayRef<TemplateArgument> TemplateArgs,
+ SourceLocation TemplateNameLoc, MultiLevelTemplateArgumentList &MLTAL,
+ const Expr *ConstraintExpr, ConstraintSatisfaction &Satisfaction) {
+ return calculateConstraintSatisfaction(
+ S, ConstraintExpr, Satisfaction, [&](const Expr *AtomicExpr) {
+ EnterExpressionEvaluationContext ConstantEvaluated(
+ S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+
+ // Atomic constraint - substitute arguments and check satisfaction.
+ ExprResult SubstitutedExpression;
+ {
+ TemplateDeductionInfo Info(TemplateNameLoc);
+ Sema::InstantiatingTemplate Inst(S, AtomicExpr->getBeginLoc(),
+ Sema::InstantiatingTemplate::ConstraintSubstitution{}, Template,
+ Info, AtomicExpr->getSourceRange());
+ if (Inst.isInvalid())
+ return ExprError();
+ // We do not want error diagnostics escaping here.
+ Sema::SFINAETrap Trap(S);
+ SubstitutedExpression = S.SubstExpr(const_cast<Expr *>(AtomicExpr),
+ MLTAL);
+ if (SubstitutedExpression.isInvalid() || Trap.hasErrorOccurred()) {
+ // C++2a [temp.constr.atomic]p1
+ // ...If substitution results in an invalid type or expression, the
+ // constraint is not satisfied.
+ if (!Trap.hasErrorOccurred())
+ // A non-SFINAE error has occured as a result of this
+ // substitution.
+ return ExprError();
+
+ PartialDiagnosticAt SubstDiag{SourceLocation(),
+ PartialDiagnostic::NullDiagnostic()};
+ Info.takeSFINAEDiagnostic(SubstDiag);
+ // FIXME: Concepts: This is an unfortunate consequence of there
+ // being no serialization code for PartialDiagnostics and the fact
+ // that serializing them would likely take a lot more storage than
+ // just storing them as strings. We would still like, in the
+ // future, to serialize the proper PartialDiagnostic as serializing
+ // it as a string defeats the purpose of the diagnostic mechanism.
+ SmallString<128> DiagString;
+ DiagString = ": ";
+ SubstDiag.second.EmitToString(S.getDiagnostics(), DiagString);
+ unsigned MessageSize = DiagString.size();
+ char *Mem = new (S.Context) char[MessageSize];
+ memcpy(Mem, DiagString.c_str(), MessageSize);
+ Satisfaction.Details.emplace_back(
+ AtomicExpr,
+ new (S.Context) ConstraintSatisfaction::SubstitutionDiagnostic{
+ SubstDiag.first, StringRef(Mem, MessageSize)});
+ Satisfaction.IsSatisfied = false;
+ return ExprEmpty();
+ }
+ }
+
+ if (!S.CheckConstraintExpression(SubstitutedExpression.get()))
+ return ExprError();
+
+ return SubstitutedExpression;
+ });
+}
+
+template<typename TemplateDeclT>
+static bool CheckConstraintSatisfaction(Sema &S, TemplateDeclT *Template,
+ ArrayRef<const Expr *> ConstraintExprs,
+ ArrayRef<TemplateArgument> TemplateArgs,
+ SourceRange TemplateIDRange,
+ ConstraintSatisfaction &Satisfaction) {
+ if (ConstraintExprs.empty()) {
+ Satisfaction.IsSatisfied = true;
+ return false;
+ }
+
+ for (auto& Arg : TemplateArgs)
+ if (Arg.isInstantiationDependent()) {
+ // No need to check satisfaction for dependent constraint expressions.
+ Satisfaction.IsSatisfied = true;
return false;
}
+
+ Sema::InstantiatingTemplate Inst(S, TemplateIDRange.getBegin(),
+ Sema::InstantiatingTemplate::ConstraintsCheck{}, Template, TemplateArgs,
+ TemplateIDRange);
+ if (Inst.isInvalid())
+ return true;
+
+ MultiLevelTemplateArgumentList MLTAL;
+ MLTAL.addOuterTemplateArguments(TemplateArgs);
+
+ for (const Expr *ConstraintExpr : ConstraintExprs) {
+ if (calculateConstraintSatisfaction(S, Template, TemplateArgs,
+ TemplateIDRange.getBegin(), MLTAL,
+ ConstraintExpr, Satisfaction))
+ return true;
+ if (!Satisfaction.IsSatisfied)
+ // [temp.constr.op] p2
+ // [...] To determine if a conjunction is satisfied, the satisfaction
+ // of the first operand is checked. If that is not satisfied, the
+ // conjunction is not satisfied. [...]
+ return false;
}
+ return false;
+}
+
+bool Sema::CheckConstraintSatisfaction(TemplateDecl *Template,
+ ArrayRef<const Expr *> ConstraintExprs,
+ ArrayRef<TemplateArgument> TemplateArgs,
+ SourceRange TemplateIDRange,
+ ConstraintSatisfaction &Satisfaction) {
+ return ::CheckConstraintSatisfaction(*this, Template, ConstraintExprs,
+ TemplateArgs, TemplateIDRange,
+ Satisfaction);
+}
- if (!CheckConstraintExpression(E.get()))
+bool
+Sema::CheckConstraintSatisfaction(ClassTemplatePartialSpecializationDecl* Part,
+ ArrayRef<const Expr *> ConstraintExprs,
+ ArrayRef<TemplateArgument> TemplateArgs,
+ SourceRange TemplateIDRange,
+ ConstraintSatisfaction &Satisfaction) {
+ return ::CheckConstraintSatisfaction(*this, Part, ConstraintExprs,
+ TemplateArgs, TemplateIDRange,
+ Satisfaction);
+}
+
+bool
+Sema::CheckConstraintSatisfaction(VarTemplatePartialSpecializationDecl* Partial,
+ ArrayRef<const Expr *> ConstraintExprs,
+ ArrayRef<TemplateArgument> TemplateArgs,
+ SourceRange TemplateIDRange,
+ ConstraintSatisfaction &Satisfaction) {
+ return ::CheckConstraintSatisfaction(*this, Partial, ConstraintExprs,
+ TemplateArgs, TemplateIDRange,
+ Satisfaction);
+}
+
+bool Sema::CheckConstraintSatisfaction(const Expr *ConstraintExpr,
+ ConstraintSatisfaction &Satisfaction) {
+ return calculateConstraintSatisfaction(
+ *this, ConstraintExpr, Satisfaction,
+ [](const Expr *AtomicExpr) -> ExprResult {
+ return ExprResult(const_cast<Expr *>(AtomicExpr));
+ });
+}
+
+bool Sema::EnsureTemplateArgumentListConstraints(
+ TemplateDecl *TD, ArrayRef<TemplateArgument> TemplateArgs,
+ SourceRange TemplateIDRange) {
+ ConstraintSatisfaction Satisfaction;
+ llvm::SmallVector<const Expr *, 3> AssociatedConstraints;
+ TD->getAssociatedConstraints(AssociatedConstraints);
+ if (CheckConstraintSatisfaction(TD, AssociatedConstraints, TemplateArgs,
+ TemplateIDRange, Satisfaction))
return true;
- SmallVector<PartialDiagnosticAt, 2> EvaluationDiags;
- Expr::EvalResult EvalResult;
- EvalResult.Diag = &EvaluationDiags;
- if (!E.get()->EvaluateAsRValue(EvalResult, Context)) {
- // C++2a [temp.constr.atomic]p1
- // ...E shall be a constant expression of type bool.
- Diag(E.get()->getBeginLoc(),
- diag::err_non_constant_constraint_expression)
- << E.get()->getSourceRange();
- for (const PartialDiagnosticAt &PDiag : EvaluationDiags)
- Diag(PDiag.first, PDiag.second);
+ if (!Satisfaction.IsSatisfied) {
+ SmallString<128> TemplateArgString;
+ TemplateArgString = " ";
+ TemplateArgString += getTemplateArgumentBindingsText(
+ TD->getTemplateParameters(), TemplateArgs.data(), TemplateArgs.size());
+
+ Diag(TemplateIDRange.getBegin(),
+ diag::err_template_arg_list_constraints_not_satisfied)
+ << (int)getTemplateNameKindForDiagnostics(TemplateName(TD)) << TD
+ << TemplateArgString << TemplateIDRange;
+ DiagnoseUnsatisfiedConstraint(Satisfaction);
+ return true;
+ }
+ return false;
+}
+
+static void diagnoseWellFormedUnsatisfiedConstraintExpr(Sema &S,
+ Expr *SubstExpr,
+ bool First = true) {
+ SubstExpr = SubstExpr->IgnoreParenImpCasts();
+ if (BinaryOperator *BO = dyn_cast<BinaryOperator>(SubstExpr)) {
+ switch (BO->getOpcode()) {
+ // These two cases will in practice only be reached when using fold
+ // expressions with || and &&, since otherwise the || and && will have been
+ // broken down into atomic constraints during satisfaction checking.
+ case BO_LOr:
+ // Or evaluated to false - meaning both RHS and LHS evaluated to false.
+ diagnoseWellFormedUnsatisfiedConstraintExpr(S, BO->getLHS(), First);
+ diagnoseWellFormedUnsatisfiedConstraintExpr(S, BO->getRHS(),
+ /*First=*/false);
+ return;
+ case BO_LAnd:
+ bool LHSSatisfied;
+ BO->getLHS()->EvaluateAsBooleanCondition(LHSSatisfied, S.Context);
+ if (LHSSatisfied) {
+ // LHS is true, so RHS must be false.
+ diagnoseWellFormedUnsatisfiedConstraintExpr(S, BO->getRHS(), First);
+ return;
+ }
+ // LHS is false
+ diagnoseWellFormedUnsatisfiedConstraintExpr(S, BO->getLHS(), First);
+
+ // RHS might also be false
+ bool RHSSatisfied;
+ BO->getRHS()->EvaluateAsBooleanCondition(RHSSatisfied, S.Context);
+ if (!RHSSatisfied)
+ diagnoseWellFormedUnsatisfiedConstraintExpr(S, BO->getRHS(),
+ /*First=*/false);
+ return;
+ case BO_GE:
+ case BO_LE:
+ case BO_GT:
+ case BO_LT:
+ case BO_EQ:
+ case BO_NE:
+ if (BO->getLHS()->getType()->isIntegerType() &&
+ BO->getRHS()->getType()->isIntegerType()) {
+ Expr::EvalResult SimplifiedLHS;
+ Expr::EvalResult SimplifiedRHS;
+ BO->getLHS()->EvaluateAsInt(SimplifiedLHS, S.Context);
+ BO->getRHS()->EvaluateAsInt(SimplifiedRHS, S.Context);
+ if (!SimplifiedLHS.Diag && ! SimplifiedRHS.Diag) {
+ S.Diag(SubstExpr->getBeginLoc(),
+ diag::note_atomic_constraint_evaluated_to_false_elaborated)
+ << (int)First << SubstExpr
+ << SimplifiedLHS.Val.getInt().toString(10)
+ << BinaryOperator::getOpcodeStr(BO->getOpcode())
+ << SimplifiedRHS.Val.getInt().toString(10);
+ return;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ } else if (auto *CSE = dyn_cast<ConceptSpecializationExpr>(SubstExpr)) {
+ if (CSE->getTemplateArgsAsWritten()->NumTemplateArgs == 1) {
+ S.Diag(
+ CSE->getSourceRange().getBegin(),
+ diag::
+ note_single_arg_concept_specialization_constraint_evaluated_to_false)
+ << (int)First
+ << CSE->getTemplateArgsAsWritten()->arguments()[0].getArgument()
+ << CSE->getNamedConcept();
+ } else {
+ S.Diag(SubstExpr->getSourceRange().getBegin(),
+ diag::note_concept_specialization_constraint_evaluated_to_false)
+ << (int)First << CSE;
+ }
+ S.DiagnoseUnsatisfiedConstraint(CSE->getSatisfaction());
+ return;
+ }
+
+ S.Diag(SubstExpr->getSourceRange().getBegin(),
+ diag::note_atomic_constraint_evaluated_to_false)
+ << (int)First << SubstExpr;
+}
+
+template<typename SubstitutionDiagnostic>
+static void diagnoseUnsatisfiedConstraintExpr(
+ Sema &S, const Expr *E,
+ const llvm::PointerUnion<Expr *, SubstitutionDiagnostic *> &Record,
+ bool First = true) {
+ if (auto *Diag = Record.template dyn_cast<SubstitutionDiagnostic *>()){
+ S.Diag(Diag->first, diag::note_substituted_constraint_expr_is_ill_formed)
+ << Diag->second;
+ return;
+ }
+
+ diagnoseWellFormedUnsatisfiedConstraintExpr(S,
+ Record.template get<Expr *>(), First);
+}
+
+void Sema::DiagnoseUnsatisfiedConstraint(
+ const ConstraintSatisfaction& Satisfaction) {
+ assert(!Satisfaction.IsSatisfied &&
+ "Attempted to diagnose a satisfied constraint");
+ bool First = true;
+ for (auto &Pair : Satisfaction.Details) {
+ diagnoseUnsatisfiedConstraintExpr(*this, Pair.first, Pair.second, First);
+ First = false;
+ }
+}
+
+void Sema::DiagnoseUnsatisfiedConstraint(
+ const ASTConstraintSatisfaction &Satisfaction) {
+ assert(!Satisfaction.IsSatisfied &&
+ "Attempted to diagnose a satisfied constraint");
+ bool First = true;
+ for (auto &Pair : Satisfaction) {
+ diagnoseUnsatisfiedConstraintExpr(*this, Pair.first, Pair.second, First);
+ First = false;
+ }
+}
+
+const NormalizedConstraint *
+Sema::getNormalizedAssociatedConstraints(
+ NamedDecl *ConstrainedDecl, ArrayRef<const Expr *> AssociatedConstraints) {
+ auto CacheEntry = NormalizationCache.find(ConstrainedDecl);
+ if (CacheEntry == NormalizationCache.end()) {
+ auto Normalized =
+ NormalizedConstraint::fromConstraintExprs(*this, ConstrainedDecl,
+ AssociatedConstraints);
+ CacheEntry =
+ NormalizationCache
+ .try_emplace(ConstrainedDecl,
+ Normalized
+ ? new (Context) NormalizedConstraint(
+ std::move(*Normalized))
+ : nullptr)
+ .first;
+ }
+ return CacheEntry->second;
+}
+
+static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N,
+ ConceptDecl *Concept, ArrayRef<TemplateArgument> TemplateArgs,
+ const ASTTemplateArgumentListInfo *ArgsAsWritten) {
+ if (!N.isAtomic()) {
+ if (substituteParameterMappings(S, N.getLHS(), Concept, TemplateArgs,
+ ArgsAsWritten))
+ return true;
+ return substituteParameterMappings(S, N.getRHS(), Concept, TemplateArgs,
+ ArgsAsWritten);
+ }
+ TemplateParameterList *TemplateParams = Concept->getTemplateParameters();
+
+ AtomicConstraint &Atomic = *N.getAtomicConstraint();
+ TemplateArgumentListInfo SubstArgs;
+ MultiLevelTemplateArgumentList MLTAL;
+ MLTAL.addOuterTemplateArguments(TemplateArgs);
+ if (!Atomic.ParameterMapping) {
+ llvm::SmallBitVector OccurringIndices(TemplateParams->size());
+ S.MarkUsedTemplateParameters(Atomic.ConstraintExpr, /*OnlyDeduced=*/false,
+ /*Depth=*/0, OccurringIndices);
+ Atomic.ParameterMapping.emplace(
+ MutableArrayRef<TemplateArgumentLoc>(
+ new (S.Context) TemplateArgumentLoc[OccurringIndices.count()],
+ OccurringIndices.count()));
+ for (unsigned I = 0, J = 0, C = TemplateParams->size(); I != C; ++I)
+ if (OccurringIndices[I])
+ new (&(*Atomic.ParameterMapping)[J++]) TemplateArgumentLoc(
+ S.getIdentityTemplateArgumentLoc(TemplateParams->begin()[I],
+ // Here we assume we do not support things like
+ // template<typename A, typename B>
+ // concept C = ...;
+ //
+ // template<typename... Ts> requires C<Ts...>
+ // struct S { };
+ // The above currently yields a diagnostic.
+ // We still might have default arguments for concept parameters.
+ ArgsAsWritten->NumTemplateArgs > I ?
+ ArgsAsWritten->arguments()[I].getLocation() :
+ SourceLocation()));
+ }
+ Sema::InstantiatingTemplate Inst(
+ S, ArgsAsWritten->arguments().front().getSourceRange().getBegin(),
+ Sema::InstantiatingTemplate::ParameterMappingSubstitution{}, Concept,
+ SourceRange(ArgsAsWritten->arguments()[0].getSourceRange().getBegin(),
+ ArgsAsWritten->arguments().back().getSourceRange().getEnd()));
+ if (S.SubstTemplateArguments(*Atomic.ParameterMapping, MLTAL, SubstArgs))
+ return true;
+ std::copy(SubstArgs.arguments().begin(), SubstArgs.arguments().end(),
+ N.getAtomicConstraint()->ParameterMapping->begin());
+ return false;
+}
+
+Optional<NormalizedConstraint>
+NormalizedConstraint::fromConstraintExprs(Sema &S, NamedDecl *D,
+ ArrayRef<const Expr *> E) {
+ assert(E.size() != 0);
+ auto First = fromConstraintExpr(S, D, E[0]);
+ if (E.size() == 1)
+ return First;
+ auto Second = fromConstraintExpr(S, D, E[1]);
+ if (!Second)
+ return None;
+ llvm::Optional<NormalizedConstraint> Conjunction;
+ Conjunction.emplace(S.Context, std::move(*First), std::move(*Second),
+ CCK_Conjunction);
+ for (unsigned I = 2; I < E.size(); ++I) {
+ auto Next = fromConstraintExpr(S, D, E[I]);
+ if (!Next)
+ return llvm::Optional<NormalizedConstraint>{};
+ NormalizedConstraint NewConjunction(S.Context, std::move(*Conjunction),
+ std::move(*Next), CCK_Conjunction);
+ *Conjunction = std::move(NewConjunction);
+ }
+ return Conjunction;
+}
+
+llvm::Optional<NormalizedConstraint>
+NormalizedConstraint::fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E) {
+ assert(E != nullptr);
+
+ // C++ [temp.constr.normal]p1.1
+ // [...]
+ // - The normal form of an expression (E) is the normal form of E.
+ // [...]
+ E = E->IgnoreParenImpCasts();
+ if (auto *BO = dyn_cast<const BinaryOperator>(E)) {
+ if (BO->getOpcode() == BO_LAnd || BO->getOpcode() == BO_LOr) {
+ auto LHS = fromConstraintExpr(S, D, BO->getLHS());
+ if (!LHS)
+ return None;
+ auto RHS = fromConstraintExpr(S, D, BO->getRHS());
+ if (!RHS)
+ return None;
+
+ return NormalizedConstraint(
+ S.Context, std::move(*LHS), std::move(*RHS),
+ BO->getOpcode() == BO_LAnd ? CCK_Conjunction : CCK_Disjunction);
+ }
+ } else if (auto *CSE = dyn_cast<const ConceptSpecializationExpr>(E)) {
+ const NormalizedConstraint *SubNF;
+ {
+ Sema::InstantiatingTemplate Inst(
+ S, CSE->getExprLoc(),
+ Sema::InstantiatingTemplate::ConstraintNormalization{}, D,
+ CSE->getSourceRange());
+ // C++ [temp.constr.normal]p1.1
+ // [...]
+ // The normal form of an id-expression of the form C<A1, A2, ..., AN>,
+ // where C names a concept, is the normal form of the
+ // constraint-expression of C, after substituting A1, A2, ..., AN for C’s
+ // respective template parameters in the parameter mappings in each atomic
+ // constraint. If any such substitution results in an invalid type or
+ // expression, the program is ill-formed; no diagnostic is required.
+ // [...]
+ ConceptDecl *CD = CSE->getNamedConcept();
+ SubNF = S.getNormalizedAssociatedConstraints(CD,
+ {CD->getConstraintExpr()});
+ if (!SubNF)
+ return None;
+ }
+
+ Optional<NormalizedConstraint> New;
+ New.emplace(S.Context, *SubNF);
+
+ if (substituteParameterMappings(
+ S, *New, CSE->getNamedConcept(),
+ CSE->getTemplateArguments(), CSE->getTemplateArgsAsWritten()))
+ return None;
+
+ return New;
+ }
+ return NormalizedConstraint{new (S.Context) AtomicConstraint(S, E)};
+}
+
+using NormalForm =
+ llvm::SmallVector<llvm::SmallVector<AtomicConstraint *, 2>, 4>;
+
+static NormalForm makeCNF(const NormalizedConstraint &Normalized) {
+ if (Normalized.isAtomic())
+ return {{Normalized.getAtomicConstraint()}};
+
+ NormalForm LCNF = makeCNF(Normalized.getLHS());
+ NormalForm RCNF = makeCNF(Normalized.getRHS());
+ if (Normalized.getCompoundKind() == NormalizedConstraint::CCK_Conjunction) {
+ LCNF.reserve(LCNF.size() + RCNF.size());
+ while (!RCNF.empty())
+ LCNF.push_back(RCNF.pop_back_val());
+ return LCNF;
+ }
+
+ // Disjunction
+ NormalForm Res;
+ Res.reserve(LCNF.size() * RCNF.size());
+ for (auto &LDisjunction : LCNF)
+ for (auto &RDisjunction : RCNF) {
+ NormalForm::value_type Combined;
+ Combined.reserve(LDisjunction.size() + RDisjunction.size());
+ std::copy(LDisjunction.begin(), LDisjunction.end(),
+ std::back_inserter(Combined));
+ std::copy(RDisjunction.begin(), RDisjunction.end(),
+ std::back_inserter(Combined));
+ Res.emplace_back(Combined);
+ }
+ return Res;
+}
+
+static NormalForm makeDNF(const NormalizedConstraint &Normalized) {
+ if (Normalized.isAtomic())
+ return {{Normalized.getAtomicConstraint()}};
+
+ NormalForm LDNF = makeDNF(Normalized.getLHS());
+ NormalForm RDNF = makeDNF(Normalized.getRHS());
+ if (Normalized.getCompoundKind() == NormalizedConstraint::CCK_Disjunction) {
+ LDNF.reserve(LDNF.size() + RDNF.size());
+ while (!RDNF.empty())
+ LDNF.push_back(RDNF.pop_back_val());
+ return LDNF;
+ }
+
+ // Conjunction
+ NormalForm Res;
+ Res.reserve(LDNF.size() * RDNF.size());
+ for (auto &LConjunction : LDNF) {
+ for (auto &RConjunction : RDNF) {
+ NormalForm::value_type Combined;
+ Combined.reserve(LConjunction.size() + RConjunction.size());
+ std::copy(LConjunction.begin(), LConjunction.end(),
+ std::back_inserter(Combined));
+ std::copy(RConjunction.begin(), RConjunction.end(),
+ std::back_inserter(Combined));
+ Res.emplace_back(Combined);
+ }
+ }
+ return Res;
+}
+
+template<typename AtomicSubsumptionEvaluator>
+static bool subsumes(NormalForm PDNF, NormalForm QCNF,
+ AtomicSubsumptionEvaluator E) {
+ // C++ [temp.constr.order] p2
+ // Then, P subsumes Q if and only if, for every disjunctive clause Pi in the
+ // disjunctive normal form of P, Pi subsumes every conjunctive clause Qj in
+ // the conjuctive normal form of Q, where [...]
+ for (const auto &Pi : PDNF) {
+ for (const auto &Qj : QCNF) {
+ // C++ [temp.constr.order] p2
+ // - [...] a disjunctive clause Pi subsumes a conjunctive clause Qj if
+ // and only if there exists an atomic constraint Pia in Pi for which
+ // there exists an atomic constraint, Qjb, in Qj such that Pia
+ // subsumes Qjb.
+ bool Found = false;
+ for (const AtomicConstraint *Pia : Pi) {
+ for (const AtomicConstraint *Qjb : Qj) {
+ if (E(*Pia, *Qjb)) {
+ Found = true;
+ break;
+ }
+ }
+ if (Found)
+ break;
+ }
+ if (!Found)
+ return false;
+ }
+ }
+ return true;
+}
+
+template<typename AtomicSubsumptionEvaluator>
+static bool subsumes(Sema &S, NamedDecl *DP, ArrayRef<const Expr *> P,
+ NamedDecl *DQ, ArrayRef<const Expr *> Q, bool &Subsumes,
+ AtomicSubsumptionEvaluator E) {
+ // C++ [temp.constr.order] p2
+ // In order to determine if a constraint P subsumes a constraint Q, P is
+ // transformed into disjunctive normal form, and Q is transformed into
+ // conjunctive normal form. [...]
+ auto *PNormalized = S.getNormalizedAssociatedConstraints(DP, P);
+ if (!PNormalized)
+ return true;
+ const NormalForm PDNF = makeDNF(*PNormalized);
+
+ auto *QNormalized = S.getNormalizedAssociatedConstraints(DQ, Q);
+ if (!QNormalized)
return true;
+ const NormalForm QCNF = makeCNF(*QNormalized);
+
+ Subsumes = subsumes(PDNF, QCNF, E);
+ return false;
+}
+
+bool Sema::IsAtLeastAsConstrained(NamedDecl *D1, ArrayRef<const Expr *> AC1,
+ NamedDecl *D2, ArrayRef<const Expr *> AC2,
+ bool &Result) {
+ if (AC1.empty()) {
+ Result = AC2.empty();
+ return false;
+ }
+ if (AC2.empty()) {
+ // TD1 has associated constraints and TD2 does not.
+ Result = true;
+ return false;
}
- IsSatisfied = EvalResult.Val.getInt().getBoolValue();
+ std::pair<NamedDecl *, NamedDecl *> Key{D1, D2};
+ auto CacheEntry = SubsumptionCache.find(Key);
+ if (CacheEntry != SubsumptionCache.end()) {
+ Result = CacheEntry->second;
+ return false;
+ }
+ if (subsumes(*this, D1, AC1, D2, AC2, Result,
+ [this] (const AtomicConstraint &A, const AtomicConstraint &B) {
+ return A.subsumes(Context, B);
+ }))
+ return true;
+ SubsumptionCache.try_emplace(Key, Result);
return false;
-} \ No newline at end of file
+}
+
+bool Sema::MaybeEmitAmbiguousAtomicConstraintsDiagnostic(NamedDecl *D1,
+ ArrayRef<const Expr *> AC1, NamedDecl *D2, ArrayRef<const Expr *> AC2) {
+ if (isSFINAEContext())
+ // No need to work here because our notes would be discarded.
+ return false;
+
+ if (AC1.empty() || AC2.empty())
+ return false;
+
+ auto NormalExprEvaluator =
+ [this] (const AtomicConstraint &A, const AtomicConstraint &B) {
+ return A.subsumes(Context, B);
+ };
+
+ const Expr *AmbiguousAtomic1 = nullptr, *AmbiguousAtomic2 = nullptr;
+ auto IdenticalExprEvaluator =
+ [&] (const AtomicConstraint &A, const AtomicConstraint &B) {
+ if (!A.hasMatchingParameterMapping(Context, B))
+ return false;
+ const Expr *EA = A.ConstraintExpr, *EB = B.ConstraintExpr;
+ if (EA == EB)
+ return true;
+
+ // Not the same source level expression - are the expressions
+ // identical?
+ llvm::FoldingSetNodeID IDA, IDB;
+ EA->Profile(IDA, Context, /*Cannonical=*/true);
+ EB->Profile(IDB, Context, /*Cannonical=*/true);
+ if (IDA != IDB)
+ return false;
+
+ AmbiguousAtomic1 = EA;
+ AmbiguousAtomic2 = EB;
+ return true;
+ };
+
+ {
+ // The subsumption checks might cause diagnostics
+ SFINAETrap Trap(*this);
+ auto *Normalized1 = getNormalizedAssociatedConstraints(D1, AC1);
+ if (!Normalized1)
+ return false;
+ const NormalForm DNF1 = makeDNF(*Normalized1);
+ const NormalForm CNF1 = makeCNF(*Normalized1);
+
+ auto *Normalized2 = getNormalizedAssociatedConstraints(D2, AC2);
+ if (!Normalized2)
+ return false;
+ const NormalForm DNF2 = makeDNF(*Normalized2);
+ const NormalForm CNF2 = makeCNF(*Normalized2);
+
+ bool Is1AtLeastAs2Normally = subsumes(DNF1, CNF2, NormalExprEvaluator);
+ bool Is2AtLeastAs1Normally = subsumes(DNF2, CNF1, NormalExprEvaluator);
+ bool Is1AtLeastAs2 = subsumes(DNF1, CNF2, IdenticalExprEvaluator);
+ bool Is2AtLeastAs1 = subsumes(DNF2, CNF1, IdenticalExprEvaluator);
+ if (Is1AtLeastAs2 == Is1AtLeastAs2Normally &&
+ Is2AtLeastAs1 == Is2AtLeastAs1Normally)
+ // Same result - no ambiguity was caused by identical atomic expressions.
+ return false;
+ }
+
+ // A different result! Some ambiguous atomic constraint(s) caused a difference
+ assert(AmbiguousAtomic1 && AmbiguousAtomic2);
+
+ Diag(AmbiguousAtomic1->getBeginLoc(), diag::note_ambiguous_atomic_constraints)
+ << AmbiguousAtomic1->getSourceRange();
+ Diag(AmbiguousAtomic2->getBeginLoc(),
+ diag::note_ambiguous_atomic_constraints_similar_expression)
+ << AmbiguousAtomic2->getSourceRange();
+ return true;
+}
diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp
index fd2fd35921ce..6dc9e342beb9 100644
--- a/clang/lib/Sema/SemaCoroutine.cpp
+++ b/clang/lib/Sema/SemaCoroutine.cpp
@@ -18,6 +18,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/StmtCXX.h"
+#include "clang/Basic/Builtins.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Overload.h"
@@ -1227,7 +1228,7 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() {
return false;
if (RequiresNoThrowAlloc) {
- const auto *FT = OperatorNew->getType()->getAs<FunctionProtoType>();
+ const auto *FT = OperatorNew->getType()->castAs<FunctionProtoType>();
if (!FT->isNothrow(/*ResultIfDependent*/ false)) {
S.Diag(OperatorNew->getLocation(),
diag::err_coroutine_promise_new_requires_nothrow)
@@ -1280,7 +1281,7 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() {
// Check if we need to pass the size.
const auto *OpDeleteType =
- OpDeleteQualType.getTypePtr()->getAs<FunctionProtoType>();
+ OpDeleteQualType.getTypePtr()->castAs<FunctionProtoType>();
if (OpDeleteType->getNumParams() > 1)
DeleteArgs.push_back(FrameSize);
@@ -1526,8 +1527,8 @@ bool Sema::buildCoroutineParameterMoves(SourceLocation Loc) {
auto *FD = cast<FunctionDecl>(CurContext);
auto *ScopeInfo = getCurFunction();
- assert(ScopeInfo->CoroutineParameterMoves.empty() &&
- "Should not build parameter moves twice");
+ if (!ScopeInfo->CoroutineParameterMoves.empty())
+ return false;
for (auto *PD : FD->parameters()) {
if (PD->getType()->isDependentType())
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 62ec83967bff..507e4a6cd436 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -867,6 +867,9 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS,
LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName);
LookupParsedName(Result, S, &SS, !CurMethod);
+ if (SS.isInvalid())
+ return NameClassification::Error();
+
// For unqualified lookup in a class template in MSVC mode, look into
// dependent base classes where the primary class template is known.
if (Result.empty() && SS.isEmpty() && getLangOpts().MSVCCompat) {
@@ -879,7 +882,7 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS,
// synthesized instance variables), if we're in an Objective-C method.
// FIXME: This lookup really, really needs to be folded in to the normal
// unqualified lookup mechanism.
- if (!SS.isSet() && CurMethod && !isResultTypeOrTemplate(Result, NextToken)) {
+ if (SS.isEmpty() && CurMethod && !isResultTypeOrTemplate(Result, NextToken)) {
DeclResult Ivar = LookupIvarInObjCMethod(Result, S, Name);
if (Ivar.isInvalid())
return NameClassification::Error();
@@ -899,7 +902,7 @@ Corrected:
case LookupResult::NotFound:
// If an unqualified-id is followed by a '(', then we have a function
// call.
- if (!SS.isSet() && NextToken.is(tok::l_paren)) {
+ if (SS.isEmpty() && NextToken.is(tok::l_paren)) {
// In C++, this is an ADL-only call.
// FIXME: Reference?
if (getLangOpts().CPlusPlus)
@@ -921,7 +924,7 @@ Corrected:
return NameClassification::NonType(D);
}
- if (getLangOpts().CPlusPlus2a && !SS.isSet() && NextToken.is(tok::less)) {
+ if (getLangOpts().CPlusPlus2a && SS.isEmpty() && NextToken.is(tok::less)) {
// In C++20 onwards, this could be an ADL-only call to a function
// template, and we're required to assume that this is a template name.
//
@@ -1063,7 +1066,7 @@ Corrected:
hasAnyAcceptableTemplateNames(
Result, /*AllowFunctionTemplates=*/true,
/*AllowDependent=*/false,
- /*AllowNonTemplateFunctions*/ !SS.isSet() &&
+ /*AllowNonTemplateFunctions*/ SS.isEmpty() &&
getLangOpts().CPlusPlus2a))) {
// C++ [temp.names]p3:
// After name lookup (3.4) finds that a name is a template-name or that
@@ -1092,7 +1095,7 @@ Corrected:
IsFunctionTemplate = isa<FunctionTemplateDecl>(TD);
IsVarTemplate = isa<VarTemplateDecl>(TD);
- if (SS.isSet() && !SS.isInvalid())
+ if (SS.isNotEmpty())
Template =
Context.getQualifiedTemplateName(SS.getScopeRep(),
/*TemplateKeyword=*/false, TD);
@@ -1802,6 +1805,13 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
(VD->getInit()->isValueDependent() || !VD->evaluateValue()))
return false;
}
+
+ // Suppress the warning if we don't know how this is constructed, and
+ // it could possibly be non-trivial constructor.
+ if (Init->isTypeDependent())
+ for (const CXXConstructorDecl *Ctor : RD->ctors())
+ if (!Ctor->isTrivial())
+ return false;
}
}
}
@@ -2549,7 +2559,7 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
NewAttr = S.mergeCodeSegAttr(D, *CSA, CSA->getName());
else if (const auto *IA = dyn_cast<MSInheritanceAttr>(Attr))
NewAttr = S.mergeMSInheritanceAttr(D, *IA, IA->getBestCase(),
- IA->getSemanticSpelling());
+ IA->getInheritanceModel());
else if (const auto *AA = dyn_cast<AlwaysInlineAttr>(Attr))
NewAttr = S.mergeAlwaysInlineAttr(D, *AA,
&S.Context.Idents.get(AA->getSpelling()));
@@ -2675,6 +2685,10 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) {
// C's _Noreturn is allowed to be added to a function after it is defined.
++I;
continue;
+ } else if (isa<UuidAttr>(NewAttribute)) {
+ // msvc will allow a subsequent definition to add an uuid to a class
+ ++I;
+ continue;
} else if (const AlignedAttr *AA = dyn_cast<AlignedAttr>(NewAttribute)) {
if (AA->isAlignas()) {
// C++11 [dcl.align]p6:
@@ -2993,28 +3007,6 @@ struct GNUCompatibleParamWarning {
} // end anonymous namespace
-/// getSpecialMember - get the special member enum for a method.
-Sema::CXXSpecialMember Sema::getSpecialMember(const CXXMethodDecl *MD) {
- if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(MD)) {
- if (Ctor->isDefaultConstructor())
- return Sema::CXXDefaultConstructor;
-
- if (Ctor->isCopyConstructor())
- return Sema::CXXCopyConstructor;
-
- if (Ctor->isMoveConstructor())
- return Sema::CXXMoveConstructor;
- } else if (isa<CXXDestructorDecl>(MD)) {
- return Sema::CXXDestructor;
- } else if (MD->isCopyAssignmentOperator()) {
- return Sema::CXXCopyAssignment;
- } else if (MD->isMoveAssignmentOperator()) {
- return Sema::CXXMoveAssignment;
- }
-
- return Sema::CXXInvalid;
-}
-
// Determine whether the previous declaration was a definition, implicit
// declaration, or a declaration.
template <typename T>
@@ -3668,6 +3660,11 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD,
return MergeCompatibleFunctionDecls(New, Old, S, MergeTypeWithOld);
}
+ // Check if the function types are compatible when pointer size address
+ // spaces are ignored.
+ if (Context.hasSameFunctionTypeIgnoringPtrSizes(OldQType, NewQType))
+ return false;
+
// GNU C permits a K&R definition to follow a prototype declaration
// if the declared types of the parameters in the K&R definition
// match the types in the prototype declaration, even when the
@@ -5032,6 +5029,8 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
/*BitWidth=*/nullptr, /*Mutable=*/false,
/*InitStyle=*/ICIS_NoInit);
Anon->setAccess(AS);
+ ProcessDeclAttributes(S, Anon, Dc);
+
if (getLangOpts().CPlusPlus)
FieldCollector->Add(cast<FieldDecl>(Anon));
} else {
@@ -5045,6 +5044,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
SC = SC_None;
}
+ assert(DS.getAttributes().empty() && "No attribute expected");
Anon = VarDecl::Create(Context, Owner, DS.getBeginLoc(),
Record->getLocation(), /*IdentifierInfo=*/nullptr,
Context.getTypeDeclType(Record), TInfo, SC);
@@ -6139,6 +6139,41 @@ bool Sema::inferObjCARCLifetime(ValueDecl *decl) {
return false;
}
+void Sema::deduceOpenCLAddressSpace(ValueDecl *Decl) {
+ if (Decl->getType().hasAddressSpace())
+ return;
+ if (VarDecl *Var = dyn_cast<VarDecl>(Decl)) {
+ QualType Type = Var->getType();
+ if (Type->isSamplerT() || Type->isVoidType())
+ return;
+ LangAS ImplAS = LangAS::opencl_private;
+ if ((getLangOpts().OpenCLCPlusPlus || getLangOpts().OpenCLVersion >= 200) &&
+ Var->hasGlobalStorage())
+ ImplAS = LangAS::opencl_global;
+ // If the original type from a decayed type is an array type and that array
+ // type has no address space yet, deduce it now.
+ if (auto DT = dyn_cast<DecayedType>(Type)) {
+ auto OrigTy = DT->getOriginalType();
+ if (!OrigTy.hasAddressSpace() && OrigTy->isArrayType()) {
+ // Add the address space to the original array type and then propagate
+ // that to the element type through `getAsArrayType`.
+ OrigTy = Context.getAddrSpaceQualType(OrigTy, ImplAS);
+ OrigTy = QualType(Context.getAsArrayType(OrigTy), 0);
+ // Re-generate the decayed type.
+ Type = Context.getDecayedType(OrigTy);
+ }
+ }
+ Type = Context.getAddrSpaceQualType(Type, ImplAS);
+ // Apply any qualifiers (including address space) from the array type to
+ // the element type. This implements C99 6.7.3p8: "If the specification of
+ // an array type includes any type qualifiers, the element type is so
+ // qualified, not the array type."
+ if (Type->isArrayType())
+ Type = QualType(Context.getAsArrayType(Type), 0);
+ Decl->setType(Type);
+ }
+}
+
static void checkAttributesAfterMerging(Sema &S, NamedDecl &ND) {
// Ensure that an auto decl is deduced otherwise the checks below might cache
// the wrong linkage.
@@ -6496,6 +6531,105 @@ static bool isDeclExternC(const Decl *D) {
llvm_unreachable("Unknown type of decl!");
}
+/// Returns true if there hasn't been any invalid type diagnosed.
+static bool diagnoseOpenCLTypes(Scope *S, Sema &Se, Declarator &D,
+ DeclContext *DC, QualType R) {
+ // OpenCL v2.0 s6.9.b - Image type can only be used as a function argument.
+ // OpenCL v2.0 s6.13.16.1 - Pipe type can only be used as a function
+ // argument.
+ if (R->isImageType() || R->isPipeType()) {
+ Se.Diag(D.getIdentifierLoc(),
+ diag::err_opencl_type_can_only_be_used_as_function_parameter)
+ << R;
+ D.setInvalidType();
+ return false;
+ }
+
+ // OpenCL v1.2 s6.9.r:
+ // The event type cannot be used to declare a program scope variable.
+ // OpenCL v2.0 s6.9.q:
+ // The clk_event_t and reserve_id_t types cannot be declared in program
+ // scope.
+ if (NULL == S->getParent()) {
+ if (R->isReserveIDT() || R->isClkEventT() || R->isEventT()) {
+ Se.Diag(D.getIdentifierLoc(),
+ diag::err_invalid_type_for_program_scope_var)
+ << R;
+ D.setInvalidType();
+ return false;
+ }
+ }
+
+ // OpenCL v1.0 s6.8.a.3: Pointers to functions are not allowed.
+ QualType NR = R;
+ while (NR->isPointerType()) {
+ if (NR->isFunctionPointerType()) {
+ Se.Diag(D.getIdentifierLoc(), diag::err_opencl_function_pointer);
+ D.setInvalidType();
+ return false;
+ }
+ NR = NR->getPointeeType();
+ }
+
+ if (!Se.getOpenCLOptions().isEnabled("cl_khr_fp16")) {
+ // OpenCL v1.2 s6.1.1.1: reject declaring variables of the half and
+ // half array type (unless the cl_khr_fp16 extension is enabled).
+ if (Se.Context.getBaseElementType(R)->isHalfType()) {
+ Se.Diag(D.getIdentifierLoc(), diag::err_opencl_half_declaration) << R;
+ D.setInvalidType();
+ return false;
+ }
+ }
+
+ // OpenCL v1.2 s6.9.r:
+ // The event type cannot be used with the __local, __constant and __global
+ // address space qualifiers.
+ if (R->isEventT()) {
+ if (R.getAddressSpace() != LangAS::opencl_private) {
+ Se.Diag(D.getBeginLoc(), diag::err_event_t_addr_space_qual);
+ D.setInvalidType();
+ return false;
+ }
+ }
+
+ // C++ for OpenCL does not allow the thread_local storage qualifier.
+ // OpenCL C does not support thread_local either, and
+ // also reject all other thread storage class specifiers.
+ DeclSpec::TSCS TSC = D.getDeclSpec().getThreadStorageClassSpec();
+ if (TSC != TSCS_unspecified) {
+ bool IsCXX = Se.getLangOpts().OpenCLCPlusPlus;
+ Se.Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(),
+ diag::err_opencl_unknown_type_specifier)
+ << IsCXX << Se.getLangOpts().getOpenCLVersionTuple().getAsString()
+ << DeclSpec::getSpecifierName(TSC) << 1;
+ D.setInvalidType();
+ return false;
+ }
+
+ if (R->isSamplerT()) {
+ // OpenCL v1.2 s6.9.b p4:
+ // The sampler type cannot be used with the __local and __global address
+ // space qualifiers.
+ if (R.getAddressSpace() == LangAS::opencl_local ||
+ R.getAddressSpace() == LangAS::opencl_global) {
+ Se.Diag(D.getIdentifierLoc(), diag::err_wrong_sampler_addressspace);
+ D.setInvalidType();
+ }
+
+ // OpenCL v1.2 s6.12.14.1:
+ // A global sampler must be declared with either the constant address
+ // space qualifier or with the const qualifier.
+ if (DC->isTranslationUnit() &&
+ !(R.getAddressSpace() == LangAS::opencl_constant ||
+ R.isConstQualified())) {
+ Se.Diag(D.getIdentifierLoc(), diag::err_opencl_nonconst_global_sampler);
+ D.setInvalidType();
+ }
+ if (D.isInvalidType())
+ return false;
+ }
+ return true;
+}
NamedDecl *Sema::ActOnVariableDeclarator(
Scope *S, Declarator &D, DeclContext *DC, TypeSourceInfo *TInfo,
@@ -6519,95 +6653,6 @@ NamedDecl *Sema::ActOnVariableDeclarator(
return nullptr;
}
- if (getLangOpts().OpenCL) {
- // OpenCL v2.0 s6.9.b - Image type can only be used as a function argument.
- // OpenCL v2.0 s6.13.16.1 - Pipe type can only be used as a function
- // argument.
- if (R->isImageType() || R->isPipeType()) {
- Diag(D.getIdentifierLoc(),
- diag::err_opencl_type_can_only_be_used_as_function_parameter)
- << R;
- D.setInvalidType();
- return nullptr;
- }
-
- // OpenCL v1.2 s6.9.r:
- // The event type cannot be used to declare a program scope variable.
- // OpenCL v2.0 s6.9.q:
- // The clk_event_t and reserve_id_t types cannot be declared in program scope.
- if (NULL == S->getParent()) {
- if (R->isReserveIDT() || R->isClkEventT() || R->isEventT()) {
- Diag(D.getIdentifierLoc(),
- diag::err_invalid_type_for_program_scope_var) << R;
- D.setInvalidType();
- return nullptr;
- }
- }
-
- // OpenCL v1.0 s6.8.a.3: Pointers to functions are not allowed.
- QualType NR = R;
- while (NR->isPointerType()) {
- if (NR->isFunctionPointerType()) {
- Diag(D.getIdentifierLoc(), diag::err_opencl_function_pointer);
- D.setInvalidType();
- break;
- }
- NR = NR->getPointeeType();
- }
-
- if (!getOpenCLOptions().isEnabled("cl_khr_fp16")) {
- // OpenCL v1.2 s6.1.1.1: reject declaring variables of the half and
- // half array type (unless the cl_khr_fp16 extension is enabled).
- if (Context.getBaseElementType(R)->isHalfType()) {
- Diag(D.getIdentifierLoc(), diag::err_opencl_half_declaration) << R;
- D.setInvalidType();
- }
- }
-
- if (R->isSamplerT()) {
- // OpenCL v1.2 s6.9.b p4:
- // The sampler type cannot be used with the __local and __global address
- // space qualifiers.
- if (R.getAddressSpace() == LangAS::opencl_local ||
- R.getAddressSpace() == LangAS::opencl_global) {
- Diag(D.getIdentifierLoc(), diag::err_wrong_sampler_addressspace);
- }
-
- // OpenCL v1.2 s6.12.14.1:
- // A global sampler must be declared with either the constant address
- // space qualifier or with the const qualifier.
- if (DC->isTranslationUnit() &&
- !(R.getAddressSpace() == LangAS::opencl_constant ||
- R.isConstQualified())) {
- Diag(D.getIdentifierLoc(), diag::err_opencl_nonconst_global_sampler);
- D.setInvalidType();
- }
- }
-
- // OpenCL v1.2 s6.9.r:
- // The event type cannot be used with the __local, __constant and __global
- // address space qualifiers.
- if (R->isEventT()) {
- if (R.getAddressSpace() != LangAS::opencl_private) {
- Diag(D.getBeginLoc(), diag::err_event_t_addr_space_qual);
- D.setInvalidType();
- }
- }
-
- // C++ for OpenCL does not allow the thread_local storage qualifier.
- // OpenCL C does not support thread_local either, and
- // also reject all other thread storage class specifiers.
- DeclSpec::TSCS TSC = D.getDeclSpec().getThreadStorageClassSpec();
- if (TSC != TSCS_unspecified) {
- bool IsCXX = getLangOpts().OpenCLCPlusPlus;
- Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(),
- diag::err_opencl_unknown_type_specifier)
- << IsCXX << getLangOpts().getOpenCLVersionTuple().getAsString()
- << DeclSpec::getSpecifierName(TSC) << 1;
- D.setInvalidType();
- return nullptr;
- }
- }
DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpec();
StorageClass SC = StorageClassSpecToVarDeclStorageClass(D.getDeclSpec());
@@ -6964,6 +7009,13 @@ NamedDecl *Sema::ActOnVariableDeclarator(
}
}
+ if (getLangOpts().OpenCL) {
+
+ deduceOpenCLAddressSpace(NewVD);
+
+ diagnoseOpenCLTypes(S, *this, D, DC, NewVD->getType());
+ }
+
// Handle attributes prior to checking for duplicates in MergeVarDecl
ProcessDeclAttributes(S, NewVD, D);
@@ -7039,8 +7091,9 @@ NamedDecl *Sema::ActOnVariableDeclarator(
}
}
- NewVD->addAttr(::new (Context) AsmLabelAttr(
- Context, SE->getStrTokenLoc(0), Label, /*IsLiteralLabel=*/true));
+ NewVD->addAttr(AsmLabelAttr::Create(Context, Label,
+ /*IsLiteralLabel=*/true,
+ SE->getStrTokenLoc(0)));
} else if (!ExtnameUndeclaredIdentifiers.empty()) {
llvm::DenseMap<IdentifierInfo*,AsmLabelAttr*>::iterator I =
ExtnameUndeclaredIdentifiers.find(NewVD->getIdentifier());
@@ -7842,7 +7895,13 @@ struct FindOverriddenMethod {
Path.Decls = Path.Decls.slice(1)) {
NamedDecl *D = Path.Decls.front();
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
- if (MD->isVirtual() && !S->IsOverload(Method, MD, false))
+ if (MD->isVirtual() &&
+ !S->IsOverload(
+ Method, MD, /*UseMemberUsingDeclRules=*/false,
+ /*ConsiderCudaAttrs=*/true,
+ // C++2a [class.virtual]p2 does not consider requires clauses
+ // when overriding.
+ /*ConsiderRequiresClauses=*/false))
return true;
}
}
@@ -8187,7 +8246,8 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
NewFD = FunctionDecl::Create(SemaRef.Context, DC, D.getBeginLoc(), NameInfo,
R, TInfo, SC, isInline, HasPrototype,
- CSK_unspecified);
+ CSK_unspecified,
+ /*TrailingRequiresClause=*/nullptr);
if (D.isInvalidType())
NewFD->setInvalidDecl();
@@ -8204,6 +8264,7 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
ConstexprKind = CSK_unspecified;
D.getMutableDeclSpec().ClearConstexprSpec();
}
+ Expr *TrailingRequiresClause = D.getTrailingRequiresClause();
// Check that the return type is not an abstract class type.
// For record types, this is done by the AbstractClassUsageDiagnoser once
@@ -8223,7 +8284,8 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
return CXXConstructorDecl::Create(
SemaRef.Context, cast<CXXRecordDecl>(DC), D.getBeginLoc(), NameInfo, R,
TInfo, ExplicitSpecifier, isInline,
- /*isImplicitlyDeclared=*/false, ConstexprKind);
+ /*isImplicitlyDeclared=*/false, ConstexprKind, InheritedConstructor(),
+ TrailingRequiresClause);
} else if (Name.getNameKind() == DeclarationName::CXXDestructorName) {
// This is a C++ destructor declaration.
@@ -8232,8 +8294,8 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
CXXDestructorDecl *NewDD = CXXDestructorDecl::Create(
SemaRef.Context, Record, D.getBeginLoc(), NameInfo, R, TInfo,
- isInline,
- /*isImplicitlyDeclared=*/false, ConstexprKind);
+ isInline, /*isImplicitlyDeclared=*/false, ConstexprKind,
+ TrailingRequiresClause);
// 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
@@ -8253,7 +8315,8 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
return FunctionDecl::Create(SemaRef.Context, DC, D.getBeginLoc(),
D.getIdentifierLoc(), Name, R, TInfo, SC,
isInline,
- /*hasPrototype=*/true, ConstexprKind);
+ /*hasPrototype=*/true, ConstexprKind,
+ TrailingRequiresClause);
}
} else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) {
@@ -8270,9 +8333,14 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
IsVirtualOkay = true;
return CXXConversionDecl::Create(
SemaRef.Context, cast<CXXRecordDecl>(DC), D.getBeginLoc(), NameInfo, R,
- TInfo, isInline, ExplicitSpecifier, ConstexprKind, SourceLocation());
+ TInfo, isInline, ExplicitSpecifier, ConstexprKind, SourceLocation(),
+ TrailingRequiresClause);
} else if (Name.getNameKind() == DeclarationName::CXXDeductionGuideName) {
+ if (TrailingRequiresClause)
+ SemaRef.Diag(TrailingRequiresClause->getBeginLoc(),
+ diag::err_trailing_requires_clause_on_deduction_guide)
+ << TrailingRequiresClause->getSourceRange();
SemaRef.CheckDeductionGuideDeclarator(D, R, SC);
return CXXDeductionGuideDecl::Create(SemaRef.Context, DC, D.getBeginLoc(),
@@ -8294,7 +8362,8 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
// This is a C++ method declaration.
CXXMethodDecl *Ret = CXXMethodDecl::Create(
SemaRef.Context, cast<CXXRecordDecl>(DC), D.getBeginLoc(), NameInfo, R,
- TInfo, SC, isInline, ConstexprKind, SourceLocation());
+ TInfo, SC, isInline, ConstexprKind, SourceLocation(),
+ TrailingRequiresClause);
IsVirtualOkay = !Ret->isStatic();
return Ret;
} else {
@@ -8308,7 +8377,7 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
// - we're in C++ (where every function has a prototype),
return FunctionDecl::Create(SemaRef.Context, DC, D.getBeginLoc(), NameInfo,
R, TInfo, SC, isInline, true /*HasPrototype*/,
- ConstexprKind);
+ ConstexprKind, TrailingRequiresClause);
}
}
@@ -8332,7 +8401,7 @@ static bool isOpenCLSizeDependentType(ASTContext &C, QualType Ty) {
QualType DesugaredTy = Ty;
do {
ArrayRef<StringRef> Names(SizeTypeNames);
- auto Match = llvm::find(Names, DesugaredTy.getAsString());
+ auto Match = llvm::find(Names, DesugaredTy.getUnqualifiedType().getAsString());
if (Names.end() != Match)
return true;
@@ -8943,9 +9012,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (Expr *E = (Expr*) D.getAsmLabel()) {
// The parser guarantees this is a string.
StringLiteral *SE = cast<StringLiteral>(E);
- NewFD->addAttr(::new (Context)
- AsmLabelAttr(Context, SE->getStrTokenLoc(0),
- SE->getString(), /*IsLiteralLabel=*/true));
+ NewFD->addAttr(AsmLabelAttr::Create(Context, SE->getString(),
+ /*IsLiteralLabel=*/true,
+ SE->getStrTokenLoc(0)));
} else if (!ExtnameUndeclaredIdentifiers.empty()) {
llvm::DenseMap<IdentifierInfo*,AsmLabelAttr*>::iterator I =
ExtnameUndeclaredIdentifiers.find(NewFD->getIdentifier());
@@ -9551,6 +9620,29 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
}
+ // Diagnose no_builtin attribute on function declaration that are not a
+ // definition.
+ // FIXME: We should really be doing this in
+ // SemaDeclAttr.cpp::handleNoBuiltinAttr, unfortunately we only have access to
+ // the FunctionDecl and at this point of the code
+ // FunctionDecl::isThisDeclarationADefinition() which always returns `false`
+ // because Sema::ActOnStartOfFunctionDef has not been called yet.
+ if (const auto *NBA = NewFD->getAttr<NoBuiltinAttr>())
+ switch (D.getFunctionDefinitionKind()) {
+ case FDK_Defaulted:
+ case FDK_Deleted:
+ Diag(NBA->getLocation(),
+ diag::err_attribute_no_builtin_on_defaulted_deleted_function)
+ << NBA->getSpelling();
+ break;
+ case FDK_Declaration:
+ Diag(NBA->getLocation(), diag::err_attribute_no_builtin_on_non_definition)
+ << NBA->getSpelling();
+ break;
+ case FDK_Definition:
+ break;
+ }
+
return NewFD;
}
@@ -9687,7 +9779,7 @@ bool Sema::shouldLinkDependentDeclWithPrevious(Decl *D, Decl *PrevDecl) {
static bool CheckMultiVersionValue(Sema &S, const FunctionDecl *FD) {
const auto *TA = FD->getAttr<TargetAttr>();
assert(TA && "MultiVersion Candidate requires a target attribute");
- TargetAttr::ParsedTargetAttr ParseInfo = TA->parse();
+ ParsedTargetAttr ParseInfo = TA->parse();
const TargetInfo &TargetInfo = S.Context.getTargetInfo();
enum ErrType { Feature = 0, Architecture = 1 };
@@ -9764,13 +9856,15 @@ bool Sema::areMultiversionVariantFunctionsCompatible(
Linkage = 5,
};
- if (OldFD && !OldFD->getType()->getAs<FunctionProtoType>()) {
+ if (NoProtoDiagID.getDiagID() != 0 && OldFD &&
+ !OldFD->getType()->getAs<FunctionProtoType>()) {
Diag(OldFD->getLocation(), NoProtoDiagID);
Diag(NoteCausedDiagIDAt.first, NoteCausedDiagIDAt.second);
return true;
}
- if (!NewFD->getType()->getAs<FunctionProtoType>())
+ if (NoProtoDiagID.getDiagID() != 0 &&
+ !NewFD->getType()->getAs<FunctionProtoType>())
return Diag(NewFD->getLocation(), NoProtoDiagID);
if (!TemplatesSupported &&
@@ -9938,7 +10032,7 @@ static bool CheckTargetCausesMultiVersioning(
bool &Redeclaration, NamedDecl *&OldDecl, bool &MergeTypeWithPrevious,
LookupResult &Previous) {
const auto *OldTA = OldFD->getAttr<TargetAttr>();
- TargetAttr::ParsedTargetAttr NewParsed = NewTA->parse();
+ ParsedTargetAttr NewParsed = NewTA->parse();
// Sort order doesn't matter, it just needs to be consistent.
llvm::sort(NewParsed.Features);
@@ -9982,8 +10076,7 @@ static bool CheckTargetCausesMultiVersioning(
return true;
}
- TargetAttr::ParsedTargetAttr OldParsed =
- OldTA->parse(std::less<std::string>());
+ ParsedTargetAttr OldParsed = OldTA->parse(std::less<std::string>());
if (OldParsed == NewParsed) {
S.Diag(NewFD->getLocation(), diag::err_multiversion_duplicate);
@@ -10036,7 +10129,7 @@ static bool CheckMultiVersionAdditionalDecl(
return true;
}
- TargetAttr::ParsedTargetAttr NewParsed;
+ ParsedTargetAttr NewParsed;
if (NewTA) {
NewParsed = NewTA->parse();
llvm::sort(NewParsed.Features);
@@ -10063,8 +10156,7 @@ static bool CheckMultiVersionAdditionalDecl(
return false;
}
- TargetAttr::ParsedTargetAttr CurParsed =
- CurTA->parse(std::less<std::string>());
+ ParsedTargetAttr CurParsed = CurTA->parse(std::less<std::string>());
if (CurParsed == NewParsed) {
S.Diag(NewFD->getLocation(), diag::err_multiversion_duplicate);
S.Diag(CurFD->getLocation(), diag::note_previous_declaration);
@@ -10496,6 +10588,11 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
}
}
}
+ if (Method->isVirtual() && NewFD->getTrailingRequiresClause())
+ // C++2a [class.virtual]p6
+ // A virtual method shall not have a requires-clause.
+ Diag(NewFD->getTrailingRequiresClause()->getBeginLoc(),
+ diag::err_constrained_virtual_method);
if (Method->isStatic())
checkThisInStaticMemberFunctionType(Method);
@@ -11281,6 +11378,9 @@ bool Sema::DeduceVariableDeclarationType(VarDecl *VDecl, bool DirectInit,
if (getLangOpts().ObjCAutoRefCount && inferObjCARCLifetime(VDecl))
VDecl->setInvalidDecl();
+ if (getLangOpts().OpenCL)
+ deduceOpenCLAddressSpace(VDecl);
+
// If this is a redeclaration, check that the type we just deduced matches
// the previously declared type.
if (VarDecl *Old = VDecl->getPreviousDecl()) {
@@ -12145,6 +12245,10 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
Diag(Var->getLocation(), diag::note_private_extern);
}
+ if (Context.getTargetInfo().allowDebugInfoForExternalVar() &&
+ !Var->isInvalidDecl() && !getLangOpts().CPlusPlus)
+ ExternalDeclarations.push_back(Var);
+
return;
case VarDecl::TentativeDefinition:
@@ -13103,6 +13207,10 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
if (New->hasAttr<BlocksAttr>()) {
Diag(New->getLocation(), diag::err_block_on_nonlocal);
}
+
+ if (getLangOpts().OpenCL)
+ deduceOpenCLAddressSpace(New);
+
return New;
}
@@ -13315,8 +13423,10 @@ ShouldWarnAboutMissingPrototype(const FunctionDecl *FD,
return false;
// Don't warn about 'main'.
- if (FD->isMain())
- return false;
+ if (isa<TranslationUnitDecl>(FD->getDeclContext()->getRedeclContext()))
+ if (IdentifierInfo *II = FD->getIdentifier())
+ if (II->isStr("main"))
+ return false;
// Don't warn about inline functions.
if (FD->isInlined())
@@ -13826,8 +13936,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
LSI->ReturnType.isNull() ? Context.VoidTy : LSI->ReturnType;
// Update the return type to the deduced type.
- const FunctionProtoType *Proto =
- FD->getType()->getAs<FunctionProtoType>();
+ const auto *Proto = FD->getType()->castAs<FunctionProtoType>();
FD->setType(Context.getFunctionType(RetType, Proto->getParamTypes(),
Proto->getExtProtoInfo()));
}
@@ -16031,7 +16140,7 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
}
// TR 18037 does not allow fields to be declared with address space
- if (T.getQualifiers().hasAddressSpace() || T->isDependentAddressSpaceType() ||
+ if (T.hasAddressSpace() || T->isDependentAddressSpaceType() ||
T->getBaseElementTypeUnsafe()->isDependentAddressSpaceType()) {
Diag(Loc, diag::err_field_with_address_space);
Record->setInvalidDecl();
@@ -16754,7 +16863,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
if (const MSInheritanceAttr *IA = Record->getAttr<MSInheritanceAttr>())
checkMSInheritanceAttrOnDefinition(cast<CXXRecordDecl>(Record),
IA->getRange(), IA->getBestCase(),
- IA->getSemanticSpelling());
+ IA->getInheritanceModel());
}
// Check if the structure/union declaration is a type that can have zero
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index b2be6245a814..5c51b0f9b8cb 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -23,6 +23,7 @@
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetBuiltins.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/DeclSpec.h"
@@ -1068,6 +1069,56 @@ static void handleDiagnoseIfAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
S.Context, AL, Cond, Msg, DiagType, ArgDependent, cast<NamedDecl>(D)));
}
+static void handleNoBuiltinAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ static constexpr const StringRef kWildcard = "*";
+
+ llvm::SmallVector<StringRef, 16> Names;
+ bool HasWildcard = false;
+
+ const auto AddBuiltinName = [&Names, &HasWildcard](StringRef Name) {
+ if (Name == kWildcard)
+ HasWildcard = true;
+ Names.push_back(Name);
+ };
+
+ // Add previously defined attributes.
+ if (const auto *NBA = D->getAttr<NoBuiltinAttr>())
+ for (StringRef BuiltinName : NBA->builtinNames())
+ AddBuiltinName(BuiltinName);
+
+ // Add current attributes.
+ if (AL.getNumArgs() == 0)
+ AddBuiltinName(kWildcard);
+ else
+ for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) {
+ StringRef BuiltinName;
+ SourceLocation LiteralLoc;
+ if (!S.checkStringLiteralArgumentAttr(AL, I, BuiltinName, &LiteralLoc))
+ return;
+
+ if (Builtin::Context::isBuiltinFunc(BuiltinName))
+ AddBuiltinName(BuiltinName);
+ else
+ S.Diag(LiteralLoc, diag::warn_attribute_no_builtin_invalid_builtin_name)
+ << BuiltinName << AL.getAttrName()->getName();
+ }
+
+ // Repeating the same attribute is fine.
+ llvm::sort(Names);
+ Names.erase(std::unique(Names.begin(), Names.end()), Names.end());
+
+ // Empty no_builtin must be on its own.
+ if (HasWildcard && Names.size() > 1)
+ S.Diag(D->getLocation(),
+ diag::err_attribute_no_builtin_wildcard_or_builtin_name)
+ << AL.getAttrName()->getName();
+
+ if (D->hasAttr<NoBuiltinAttr>())
+ D->dropAttr<NoBuiltinAttr>();
+ D->addAttr(::new (S.Context)
+ NoBuiltinAttr(S.Context, AL, Names.data(), Names.size()));
+}
+
static void handlePassObjectSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (D->hasAttr<PassObjectSizeAttr>()) {
S.Diag(D->getBeginLoc(), diag::err_attribute_only_once_per_parameter) << AL;
@@ -2549,6 +2600,29 @@ static void handleVisibilityAttr(Sema &S, Decl *D, const ParsedAttr &AL,
D->addAttr(newAttr);
}
+static void handleObjCDirectAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ // objc_direct cannot be set on methods declared in the context of a protocol
+ if (isa<ObjCProtocolDecl>(D->getDeclContext())) {
+ S.Diag(AL.getLoc(), diag::err_objc_direct_on_protocol) << false;
+ return;
+ }
+
+ if (S.getLangOpts().ObjCRuntime.allowsDirectDispatch()) {
+ handleSimpleAttribute<ObjCDirectAttr>(S, D, AL);
+ } else {
+ S.Diag(AL.getLoc(), diag::warn_objc_direct_ignored) << AL;
+ }
+}
+
+static void handleObjCDirectMembersAttr(Sema &S, Decl *D,
+ const ParsedAttr &AL) {
+ if (S.getLangOpts().ObjCRuntime.allowsDirectDispatch()) {
+ handleSimpleAttribute<ObjCDirectMembersAttr>(S, D, AL);
+ } else {
+ S.Diag(AL.getLoc(), diag::warn_objc_direct_ignored) << AL;
+ }
+}
+
static void handleObjCMethodFamilyAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
const auto *M = cast<ObjCMethodDecl>(D);
if (!AL.isArgIdent(0)) {
@@ -2839,7 +2913,7 @@ static void handleVecTypeHint(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!ParmType->isExtVectorType() && !ParmType->isFloatingType() &&
(ParmType->isBooleanType() ||
!ParmType->isIntegralType(S.getASTContext()))) {
- S.Diag(AL.getLoc(), diag::err_attribute_invalid_argument) << 3 << AL;
+ S.Diag(AL.getLoc(), diag::err_attribute_invalid_argument) << 2 << AL;
return;
}
@@ -2972,7 +3046,7 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) {
return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
<< Unsupported << None << Str;
- TargetAttr::ParsedTargetAttr ParsedAttrs = TargetAttr::parse(AttrStr);
+ ParsedTargetAttr ParsedAttrs = TargetAttr::parse(AttrStr);
if (!ParsedAttrs.Architecture.empty() &&
!Context.getTargetInfo().isValidCPUName(ParsedAttrs.Architecture))
@@ -2990,6 +3064,19 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) {
<< Unsupported << None << CurFeature;
}
+ TargetInfo::BranchProtectionInfo BPI;
+ StringRef Error;
+ if (!ParsedAttrs.BranchProtection.empty() &&
+ !Context.getTargetInfo().validateBranchProtection(
+ ParsedAttrs.BranchProtection, BPI, Error)) {
+ if (Error.empty())
+ return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
+ << Unsupported << None << "branch-protection";
+ else
+ return Diag(LiteralLoc, diag::err_invalid_branch_protection_spec)
+ << Error;
+ }
+
return false;
}
@@ -3798,7 +3885,7 @@ void Sema::CheckAlignasUnderalignment(Decl *D) {
bool Sema::checkMSInheritanceAttrOnDefinition(
CXXRecordDecl *RD, SourceRange Range, bool BestCase,
- MSInheritanceAttr::Spelling SemanticSpelling) {
+ MSInheritanceModel ExplicitModel) {
assert(RD->hasDefinition() && "RD has no definition!");
// We may not have seen base specifiers or any virtual methods yet. We will
@@ -3807,14 +3894,14 @@ bool Sema::checkMSInheritanceAttrOnDefinition(
return false;
// The unspecified model never matches what a definition could need.
- if (SemanticSpelling == MSInheritanceAttr::Keyword_unspecified_inheritance)
+ if (ExplicitModel == MSInheritanceModel::Unspecified)
return false;
if (BestCase) {
- if (RD->calculateInheritanceModel() == SemanticSpelling)
+ if (RD->calculateInheritanceModel() == ExplicitModel)
return false;
} else {
- if (RD->calculateInheritanceModel() <= SemanticSpelling)
+ if (RD->calculateInheritanceModel() <= ExplicitModel)
return false;
}
@@ -4367,12 +4454,10 @@ static void handleLifetimeCategoryAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
ParmType = S.GetTypeFromParser(AL.getTypeArg(), &DerefTypeLoc);
unsigned SelectIdx = ~0U;
- if (ParmType->isVoidType())
+ if (ParmType->isReferenceType())
SelectIdx = 0;
- else if (ParmType->isReferenceType())
- SelectIdx = 1;
else if (ParmType->isArrayType())
- SelectIdx = 2;
+ SelectIdx = 1;
if (SelectIdx != ~0U) {
S.Diag(AL.getLoc(), diag::err_attribute_invalid_argument)
@@ -4830,6 +4915,54 @@ static void handleXRayLogArgsAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
XRayLogArgsAttr(S.Context, AL, ArgCount.getSourceIndex()));
}
+static void handlePatchableFunctionEntryAttr(Sema &S, Decl *D,
+ const ParsedAttr &AL) {
+ uint32_t Count = 0, Offset = 0;
+ if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(0), Count, 0, true))
+ return;
+ if (AL.getNumArgs() == 2) {
+ Expr *Arg = AL.getArgAsExpr(1);
+ if (!checkUInt32Argument(S, AL, Arg, Offset, 1, true))
+ return;
+ if (Offset) {
+ S.Diag(getAttrLoc(AL), diag::err_attribute_argument_out_of_range)
+ << &AL << 0 << 0 << Arg->getBeginLoc();
+ return;
+ }
+ }
+ D->addAttr(::new (S.Context)
+ PatchableFunctionEntryAttr(S.Context, AL, Count, Offset));
+}
+
+static bool ArmMveAliasValid(unsigned BuiltinID, StringRef AliasName) {
+ if (AliasName.startswith("__arm_"))
+ AliasName = AliasName.substr(6);
+ switch (BuiltinID) {
+#include "clang/Basic/arm_mve_builtin_aliases.inc"
+ default:
+ return false;
+ }
+}
+
+static void handleArmMveAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ if (!AL.isArgIdent(0)) {
+ S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
+ << AL << 1 << AANT_ArgumentIdentifier;
+ return;
+ }
+
+ IdentifierInfo *Ident = AL.getArgAsIdent(0)->Ident;
+ unsigned BuiltinID = Ident->getBuiltinID();
+
+ if (!ArmMveAliasValid(BuiltinID,
+ cast<FunctionDecl>(D)->getIdentifier()->getName())) {
+ S.Diag(AL.getLoc(), diag::err_attribute_arm_mve_alias);
+ return;
+ }
+
+ D->addAttr(::new (S.Context) ArmMveAliasAttr(S.Context, AL, Ident));
+}
+
//===----------------------------------------------------------------------===//
// Checker-specific attribute handlers.
//===----------------------------------------------------------------------===//
@@ -5278,9 +5411,11 @@ UuidAttr *Sema::mergeUuidAttr(Decl *D, const AttributeCommonInfo &CI,
if (const auto *UA = D->getAttr<UuidAttr>()) {
if (UA->getGuid().equals_lower(Uuid))
return nullptr;
- Diag(UA->getLocation(), diag::err_mismatched_uuid);
- Diag(CI.getLoc(), diag::note_previous_uuid);
- D->dropAttr<UuidAttr>();
+ if (!UA->getGuid().empty()) {
+ Diag(UA->getLocation(), diag::err_mismatched_uuid);
+ Diag(CI.getLoc(), diag::note_previous_uuid);
+ D->dropAttr<UuidAttr>();
+ }
}
return ::new (Context) UuidAttr(Context, CI, Uuid);
@@ -5342,8 +5477,7 @@ static void handleMSInheritanceAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
MSInheritanceAttr *IA = S.mergeMSInheritanceAttr(
- D, AL, /*BestCase=*/true,
- (MSInheritanceAttr::Spelling)AL.getSemanticSpelling());
+ D, AL, /*BestCase=*/true, (MSInheritanceModel)AL.getSemanticSpelling());
if (IA) {
D->addAttr(IA);
S.Consumer.AssignInheritanceModel(cast<CXXRecordDecl>(D));
@@ -5620,6 +5754,47 @@ static void handleAVRSignalAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
handleSimpleAttribute<AVRSignalAttr>(S, D, AL);
}
+static void handleBPFPreserveAIRecord(Sema &S, RecordDecl *RD) {
+ // Add preserve_access_index attribute to all fields and inner records.
+ for (auto D : RD->decls()) {
+ if (D->hasAttr<BPFPreserveAccessIndexAttr>())
+ continue;
+
+ D->addAttr(BPFPreserveAccessIndexAttr::CreateImplicit(S.Context));
+ if (auto *Rec = dyn_cast<RecordDecl>(D))
+ handleBPFPreserveAIRecord(S, Rec);
+ }
+}
+
+static void handleBPFPreserveAccessIndexAttr(Sema &S, Decl *D,
+ const ParsedAttr &AL) {
+ auto *Rec = cast<RecordDecl>(D);
+ handleBPFPreserveAIRecord(S, Rec);
+ Rec->addAttr(::new (S.Context) BPFPreserveAccessIndexAttr(S.Context, AL));
+}
+
+static void handleWebAssemblyExportNameAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ if (!isFunctionOrMethod(D)) {
+ S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
+ << "'export_name'" << ExpectedFunction;
+ return;
+ }
+
+ auto *FD = cast<FunctionDecl>(D);
+ if (FD->isThisDeclarationADefinition()) {
+ S.Diag(D->getLocation(), diag::err_alias_is_definition) << FD << 0;
+ return;
+ }
+
+ StringRef Str;
+ SourceLocation ArgLoc;
+ if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
+ return;
+
+ D->addAttr(::new (S.Context) WebAssemblyExportNameAttr(S.Context, AL, Str));
+ D->addAttr(UsedAttr::CreateImplicit(S.Context));
+}
+
static void handleWebAssemblyImportModuleAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!isFunctionOrMethod(D)) {
S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
@@ -5977,9 +6152,9 @@ static void handleDLLAttr(Sema &S, Decl *D, const ParsedAttr &A) {
MSInheritanceAttr *
Sema::mergeMSInheritanceAttr(Decl *D, const AttributeCommonInfo &CI,
bool BestCase,
- MSInheritanceAttr::Spelling SemanticSpelling) {
+ MSInheritanceModel Model) {
if (MSInheritanceAttr *IA = D->getAttr<MSInheritanceAttr>()) {
- if (IA->getSemanticSpelling() == SemanticSpelling)
+ if (IA->getInheritanceModel() == Model)
return nullptr;
Diag(IA->getLocation(), diag::err_mismatched_ms_inheritance)
<< 1 /*previous declaration*/;
@@ -5990,7 +6165,7 @@ Sema::mergeMSInheritanceAttr(Decl *D, const AttributeCommonInfo &CI,
auto *RD = cast<CXXRecordDecl>(D);
if (RD->hasDefinition()) {
if (checkMSInheritanceAttrOnDefinition(RD, CI.getRange(), BestCase,
- SemanticSpelling)) {
+ Model)) {
return nullptr;
}
} else {
@@ -6278,6 +6453,45 @@ static void handleOpenCLAccessAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
D->addAttr(::new (S.Context) OpenCLAccessAttr(S.Context, 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);
+ const FunctionTemplateDecl *FT = FD->getDescribedFunctionTemplate();
+ assert(FT && "Function template is expected");
+
+ // Function template must have at least two template parameters.
+ const TemplateParameterList *TL = FT->getTemplateParameters();
+ if (TL->size() < 2) {
+ S.Diag(FT->getLocation(), diag::warn_sycl_kernel_num_of_template_params);
+ return;
+ }
+
+ // Template parameters must be typenames.
+ for (unsigned I = 0; I < 2; ++I) {
+ const NamedDecl *TParam = TL->getParam(I);
+ if (isa<NonTypeTemplateParmDecl>(TParam)) {
+ S.Diag(FT->getLocation(),
+ diag::warn_sycl_kernel_invalid_template_param_type);
+ return;
+ }
+ }
+
+ // Function must have at least one argument.
+ if (getFunctionOrMethodNumParams(D) != 1) {
+ S.Diag(FT->getLocation(), diag::warn_sycl_kernel_num_of_function_params);
+ return;
+ }
+
+ // Function must return void.
+ QualType RetTy = getFunctionOrMethodResultType(D);
+ if (!RetTy->isVoidType()) {
+ S.Diag(FT->getLocation(), diag::warn_sycl_kernel_return_type);
+ return;
+ }
+
+ handleSimpleAttribute<SYCLKernelAttr>(S, D, AL);
+}
+
static void handleDestroyAttr(Sema &S, Decl *D, const ParsedAttr &A) {
if (!cast<VarDecl>(D)->hasGlobalStorage()) {
S.Diag(D->getLocation(), diag::err_destroy_attr_on_non_static_var)
@@ -6406,6 +6620,50 @@ static void handleMSAllocatorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
handleSimpleAttribute<MSAllocatorAttr>(S, D, AL);
}
+static void handeAcquireHandleAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ if (AL.isUsedAsTypeAttr())
+ return;
+ // Warn if the parameter is definitely not an output parameter.
+ if (const auto *PVD = dyn_cast<ParmVarDecl>(D)) {
+ if (PVD->getType()->isIntegerType()) {
+ S.Diag(AL.getLoc(), diag::err_attribute_output_parameter)
+ << AL.getRange();
+ return;
+ }
+ }
+ StringRef Argument;
+ if (!S.checkStringLiteralArgumentAttr(AL, 0, Argument))
+ return;
+ D->addAttr(AcquireHandleAttr::Create(S.Context, Argument, AL));
+}
+
+template<typename Attr>
+static void handleHandleAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ StringRef Argument;
+ if (!S.checkStringLiteralArgumentAttr(AL, 0, Argument))
+ return;
+ D->addAttr(Attr::Create(S.Context, Argument, AL));
+}
+
+static void handleCFGuardAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ // The guard attribute takes a single identifier argument.
+
+ if (!AL.isArgIdent(0)) {
+ S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
+ << AL << AANT_ArgumentIdentifier;
+ return;
+ }
+
+ CFGuardAttr::GuardArg Arg;
+ IdentifierInfo *II = AL.getArgAsIdent(0)->Ident;
+ if (!CFGuardAttr::ConvertStrToGuardArg(II->getName(), Arg)) {
+ S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) << AL << II;
+ return;
+ }
+
+ D->addAttr(::new (S.Context) CFGuardAttr(S.Context, AL, Arg));
+}
+
//===----------------------------------------------------------------------===//
// Top Level Sema Entry Points
//===----------------------------------------------------------------------===//
@@ -6496,6 +6754,12 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_AVRSignal:
handleAVRSignalAttr(S, D, AL);
break;
+ case ParsedAttr::AT_BPFPreserveAccessIndex:
+ handleBPFPreserveAccessIndexAttr(S, D, AL);
+ break;
+ case ParsedAttr::AT_WebAssemblyExportName:
+ handleWebAssemblyExportNameAttr(S, D, AL);
+ break;
case ParsedAttr::AT_WebAssemblyImportModule:
handleWebAssemblyImportModuleAttr(S, D, AL);
break;
@@ -6578,6 +6842,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_DiagnoseIf:
handleDiagnoseIfAttr(S, D, AL);
break;
+ case ParsedAttr::AT_NoBuiltin:
+ handleNoBuiltinAttr(S, D, AL);
+ break;
case ParsedAttr::AT_ExtVectorType:
handleExtVectorTypeAttr(S, D, AL);
break;
@@ -6599,6 +6866,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_Flatten:
handleSimpleAttribute<FlattenAttr>(S, D, AL);
break;
+ case ParsedAttr::AT_SYCLKernel:
+ handleSYCLKernelAttr(S, D, AL);
+ break;
case ParsedAttr::AT_Format:
handleFormatAttr(S, D, AL);
break;
@@ -6826,6 +7096,13 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_ObjCRootClass:
handleSimpleAttribute<ObjCRootClassAttr>(S, D, AL);
break;
+ case ParsedAttr::AT_ObjCDirect:
+ handleObjCDirectAttr(S, D, AL);
+ break;
+ case ParsedAttr::AT_ObjCDirectMembers:
+ handleObjCDirectMembersAttr(S, D, AL);
+ handleSimpleAttribute<ObjCDirectMembersAttr>(S, D, AL);
+ break;
case ParsedAttr::AT_ObjCNonLazyClass:
handleSimpleAttribute<ObjCNonLazyClassAttr>(S, D, AL);
break;
@@ -7015,6 +7292,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_AbiTag:
handleAbiTagAttr(S, D, AL);
break;
+ case ParsedAttr::AT_CFGuard:
+ handleCFGuardAttr(S, D, AL);
+ break;
// Thread safety attributes:
case ParsedAttr::AT_AssertExclusiveLock:
@@ -7135,6 +7415,10 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
handleXRayLogArgsAttr(S, D, AL);
break;
+ case ParsedAttr::AT_PatchableFunctionEntry:
+ handlePatchableFunctionEntryAttr(S, D, AL);
+ break;
+
// Move semantics attribute.
case ParsedAttr::AT_Reinitializes:
handleSimpleAttribute<ReinitializesAttr>(S, D, AL);
@@ -7160,6 +7444,22 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_MSAllocator:
handleMSAllocatorAttr(S, D, AL);
break;
+
+ case ParsedAttr::AT_ArmMveAlias:
+ handleArmMveAliasAttr(S, D, AL);
+ break;
+
+ case ParsedAttr::AT_AcquireHandle:
+ handeAcquireHandleAttr(S, D, AL);
+ break;
+
+ case ParsedAttr::AT_ReleaseHandle:
+ handleHandleAttr<ReleaseHandleAttr>(S, D, AL);
+ break;
+
+ case ParsedAttr::AT_UseHandle:
+ handleHandleAttr<UseHandleAttr>(S, D, AL);
+ break;
}
}
@@ -7238,7 +7538,8 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D,
}
}
-// Helper for delayed processing TransparentUnion attribute.
+// Helper for delayed processing TransparentUnion or BPFPreserveAccessIndexAttr
+// attribute.
void Sema::ProcessDeclAttributeDelayed(Decl *D,
const ParsedAttributesView &AttrList) {
for (const ParsedAttr &AL : AttrList)
@@ -7246,6 +7547,11 @@ void Sema::ProcessDeclAttributeDelayed(Decl *D,
handleTransparentUnionAttr(*this, D, AL);
break;
}
+
+ // For BPFPreserveAccessIndexAttr, we want to populate the attributes
+ // to fields and inner records as well.
+ if (D && D->hasAttr<BPFPreserveAccessIndexAttr>())
+ handleBPFPreserveAIRecord(*this, cast<RecordDecl>(D));
}
// Annotation attributes are the only attributes allowed after an access
@@ -7308,7 +7614,8 @@ NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II,
NewFD = FunctionDecl::Create(
FD->getASTContext(), FD->getDeclContext(), Loc, Loc,
DeclarationName(II), FD->getType(), FD->getTypeSourceInfo(), SC_None,
- false /*isInlineSpecified*/, FD->hasPrototype(), CSK_unspecified);
+ false /*isInlineSpecified*/, FD->hasPrototype(), CSK_unspecified,
+ FD->getTrailingRequiresClause());
NewD = NewFD;
if (FD->getQualifier())
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index ff90b9548e29..9916d3be77e1 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -217,8 +217,8 @@ Sema::ImplicitExceptionSpecification::CalledDecl(SourceLocation CallLoc,
Exceptions.push_back(E);
}
-void Sema::ImplicitExceptionSpecification::CalledExpr(Expr *E) {
- if (!E || ComputedEST == EST_MSAny)
+void Sema::ImplicitExceptionSpecification::CalledStmt(Stmt *S) {
+ if (!S || ComputedEST == EST_MSAny)
return;
// FIXME:
@@ -242,7 +242,7 @@ void Sema::ImplicitExceptionSpecification::CalledExpr(Expr *E) {
// implicit definition. For now, we assume that any non-nothrow expression can
// throw any exception.
- if (Self->canThrow(E))
+ if (Self->canThrow(S))
ComputedEST = EST_None;
}
@@ -1501,13 +1501,13 @@ void Sema::MergeVarDeclExceptionSpecs(VarDecl *New, VarDecl *Old) {
// as pointers to member functions.
if (const ReferenceType *R = NewType->getAs<ReferenceType>()) {
NewType = R->getPointeeType();
- OldType = OldType->getAs<ReferenceType>()->getPointeeType();
+ OldType = OldType->castAs<ReferenceType>()->getPointeeType();
} else if (const PointerType *P = NewType->getAs<PointerType>()) {
NewType = P->getPointeeType();
- OldType = OldType->getAs<PointerType>()->getPointeeType();
+ OldType = OldType->castAs<PointerType>()->getPointeeType();
} else if (const MemberPointerType *M = NewType->getAs<MemberPointerType>()) {
NewType = M->getPointeeType();
- OldType = OldType->getAs<MemberPointerType>()->getPointeeType();
+ OldType = OldType->castAs<MemberPointerType>()->getPointeeType();
}
if (!NewType->isFunctionProtoType())
@@ -1627,14 +1627,13 @@ static bool CheckConstexprDestructorSubobjects(Sema &SemaRef,
return true;
}
-// CheckConstexprParameterTypes - Check whether a function's parameter types
-// are all literal types. If so, return true. If not, produce a suitable
-// diagnostic and return false.
+/// Check whether a function's parameter types are all literal types. If so,
+/// return true. If not, produce a suitable diagnostic and return false.
static bool CheckConstexprParameterTypes(Sema &SemaRef,
const FunctionDecl *FD,
Sema::CheckConstexprKind Kind) {
unsigned ArgIndex = 0;
- const FunctionProtoType *FT = FD->getType()->getAs<FunctionProtoType>();
+ const auto *FT = FD->getType()->castAs<FunctionProtoType>();
for (FunctionProtoType::param_type_iterator i = FT->param_type_begin(),
e = FT->param_type_end();
i != e; ++i, ++ArgIndex) {
@@ -1649,6 +1648,17 @@ static bool CheckConstexprParameterTypes(Sema &SemaRef,
return true;
}
+/// Check whether a function's return type is a literal type. If so, return
+/// true. If not, produce a suitable diagnostic and return false.
+static bool CheckConstexprReturnType(Sema &SemaRef, const FunctionDecl *FD,
+ Sema::CheckConstexprKind Kind) {
+ if (CheckLiteralType(SemaRef, Kind, FD->getLocation(), FD->getReturnType(),
+ diag::err_constexpr_non_literal_return,
+ FD->isConsteval()))
+ return false;
+ return true;
+}
+
/// Get diagnostic %select index for tag kind for
/// record diagnostic message.
/// WARNING: Indexes apply to particular diagnostics only!
@@ -1729,10 +1739,7 @@ bool Sema::CheckConstexprFunctionDefinition(const FunctionDecl *NewFD,
}
// - its return type shall be a literal type;
- QualType RT = NewFD->getReturnType();
- if (CheckLiteralType(*this, Kind, NewFD->getLocation(), RT,
- diag::err_constexpr_non_literal_return,
- NewFD->isConsteval()))
+ if (!CheckConstexprReturnType(*this, NewFD, Kind))
return false;
}
@@ -3800,7 +3807,7 @@ namespace {
const CXXRecordDecl *RD = Constructor->getParent();
- if (RD->getDescribedClassTemplate())
+ if (RD->isDependentContext())
return;
// Holds fields that are uninitialized.
@@ -3861,6 +3868,26 @@ void Sema::ActOnStartCXXInClassMemberInitializer() {
PushFunctionScope();
}
+void Sema::ActOnStartTrailingRequiresClause(Scope *S, Declarator &D) {
+ if (!D.isFunctionDeclarator())
+ return;
+ auto &FTI = D.getFunctionTypeInfo();
+ if (!FTI.Params)
+ return;
+ for (auto &Param : ArrayRef<DeclaratorChunk::ParamInfo>(FTI.Params,
+ FTI.NumParams)) {
+ auto *ParamDecl = cast<NamedDecl>(Param.Param);
+ if (ParamDecl->getDeclName())
+ PushOnScopeChains(ParamDecl, S, /*AddToContext=*/false);
+ }
+}
+
+ExprResult Sema::ActOnFinishTrailingRequiresClause(ExprResult ConstraintExpr) {
+ if (ConstraintExpr.isInvalid())
+ return ExprError();
+ return CorrectDelayedTyposInExpr(ConstraintExpr);
+}
+
/// This is invoked after parsing an in-class initializer for a
/// non-static C++ class member, and after instantiating an in-class initializer
/// in a class template. Such actions are deferred until the class is complete.
@@ -6084,6 +6111,67 @@ void Sema::propagateDLLAttrToBaseClassTemplate(
}
}
+/// Determine the kind of defaulting that would be done for a given function.
+///
+/// If the function is both a default constructor and a copy / move constructor
+/// (due to having a default argument for the first parameter), this picks
+/// CXXDefaultConstructor.
+///
+/// FIXME: Check that case is properly handled by all callers.
+Sema::DefaultedFunctionKind
+Sema::getDefaultedFunctionKind(const FunctionDecl *FD) {
+ if (auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
+ if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(FD)) {
+ if (Ctor->isDefaultConstructor())
+ return Sema::CXXDefaultConstructor;
+
+ if (Ctor->isCopyConstructor())
+ return Sema::CXXCopyConstructor;
+
+ if (Ctor->isMoveConstructor())
+ return Sema::CXXMoveConstructor;
+ }
+
+ if (MD->isCopyAssignmentOperator())
+ return Sema::CXXCopyAssignment;
+
+ if (MD->isMoveAssignmentOperator())
+ return Sema::CXXMoveAssignment;
+
+ if (isa<CXXDestructorDecl>(FD))
+ return Sema::CXXDestructor;
+ }
+
+ switch (FD->getDeclName().getCXXOverloadedOperator()) {
+ case OO_EqualEqual:
+ return DefaultedComparisonKind::Equal;
+
+ case OO_ExclaimEqual:
+ return DefaultedComparisonKind::NotEqual;
+
+ case OO_Spaceship:
+ // No point allowing this if <=> doesn't exist in the current language mode.
+ if (!getLangOpts().CPlusPlus2a)
+ break;
+ return DefaultedComparisonKind::ThreeWay;
+
+ case OO_Less:
+ case OO_LessEqual:
+ case OO_Greater:
+ case OO_GreaterEqual:
+ // No point allowing this if <=> doesn't exist in the current language mode.
+ if (!getLangOpts().CPlusPlus2a)
+ break;
+ return DefaultedComparisonKind::Relational;
+
+ default:
+ break;
+ }
+
+ // Not defaultable.
+ return DefaultedFunctionKind();
+}
+
static void DefineImplicitSpecialMember(Sema &S, CXXMethodDecl *MD,
SourceLocation DefaultLoc) {
switch (S.getSpecialMember(MD)) {
@@ -6228,7 +6316,11 @@ static bool canPassInRegisters(Sema &S, CXXRecordDecl *D,
/// Perform semantic checks on a class definition that has been
/// completing, introducing implicitly-declared members, checking for
/// abstract types, etc.
-void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
+///
+/// \param S The scope in which the class was parsed. Null if we didn't just
+/// parse a class definition.
+/// \param Record The completed class.
+void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) {
if (!Record)
return;
@@ -6330,10 +6422,30 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
if (HasTrivialABI)
Record->setHasTrivialSpecialMemberForCall();
+ // Explicitly-defaulted secondary comparison functions (!=, <, <=, >, >=).
+ // We check these last because they can depend on the properties of the
+ // primary comparison functions (==, <=>).
+ llvm::SmallVector<FunctionDecl*, 5> DefaultedSecondaryComparisons;
+
+ auto CheckForDefaultedFunction = [&](FunctionDecl *FD) {
+ if (!FD || FD->isInvalidDecl() || !FD->isExplicitlyDefaulted())
+ return;
+
+ DefaultedFunctionKind DFK = getDefaultedFunctionKind(FD);
+ if (DFK.asComparison() == DefaultedComparisonKind::NotEqual ||
+ DFK.asComparison() == DefaultedComparisonKind::Relational)
+ DefaultedSecondaryComparisons.push_back(FD);
+ else
+ CheckExplicitlyDefaultedFunction(S, FD);
+ };
+
auto CompleteMemberFunction = [&](CXXMethodDecl *M) {
- // Check whether the explicitly-defaulted special members are valid.
- if (!M->isInvalidDecl() && M->isExplicitlyDefaulted())
- CheckExplicitlyDefaultedSpecialMember(M);
+ // Check whether the explicitly-defaulted members are valid.
+ CheckForDefaultedFunction(M);
+
+ // Skip the rest of the checks for a member of a dependent class.
+ if (Record->isDependentType())
+ return;
// For an explicitly defaulted or deleted special member, we defer
// determining triviality until the class is complete. That time is now!
@@ -6379,40 +6491,52 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
DefineImplicitSpecialMember(*this, M, M->getLocation());
};
+ // Check the destructor before any other member function. We need to
+ // determine whether it's trivial in order to determine whether the claas
+ // type is a literal type, which is a prerequisite for determining whether
+ // other special member functions are valid and whether they're implicitly
+ // 'constexpr'.
+ if (CXXDestructorDecl *Dtor = Record->getDestructor())
+ CompleteMemberFunction(Dtor);
+
bool HasMethodWithOverrideControl = false,
HasOverridingMethodWithoutOverrideControl = false;
- if (!Record->isDependentType()) {
- // Check the destructor before any other member function. We need to
- // determine whether it's trivial in order to determine whether the claas
- // type is a literal type, which is a prerequisite for determining whether
- // other special member functions are valid and whether they're implicitly
- // 'constexpr'.
- if (CXXDestructorDecl *Dtor = Record->getDestructor())
- CompleteMemberFunction(Dtor);
-
- for (auto *M : Record->methods()) {
- // See if a method overloads virtual methods in a base
- // class without overriding any.
- if (!M->isStatic())
- DiagnoseHiddenVirtualMethods(M);
- if (M->hasAttr<OverrideAttr>())
- HasMethodWithOverrideControl = true;
- else if (M->size_overridden_methods() > 0)
- HasOverridingMethodWithoutOverrideControl = true;
+ for (auto *D : Record->decls()) {
+ if (auto *M = dyn_cast<CXXMethodDecl>(D)) {
+ // FIXME: We could do this check for dependent types with non-dependent
+ // bases.
+ if (!Record->isDependentType()) {
+ // See if a method overloads virtual methods in a base
+ // class without overriding any.
+ if (!M->isStatic())
+ DiagnoseHiddenVirtualMethods(M);
+ if (M->hasAttr<OverrideAttr>())
+ HasMethodWithOverrideControl = true;
+ else if (M->size_overridden_methods() > 0)
+ HasOverridingMethodWithoutOverrideControl = true;
+ }
if (!isa<CXXDestructorDecl>(M))
CompleteMemberFunction(M);
+ } else if (auto *F = dyn_cast<FriendDecl>(D)) {
+ CheckForDefaultedFunction(
+ dyn_cast_or_null<FunctionDecl>(F->getFriendDecl()));
}
}
if (HasMethodWithOverrideControl &&
HasOverridingMethodWithoutOverrideControl) {
// At least one method has the 'override' control declared.
- // Diagnose all other overridden methods which do not have 'override' specified on them.
+ // Diagnose all other overridden methods which do not have 'override'
+ // specified on them.
for (auto *M : Record->methods())
DiagnoseAbsenceOfOverrideControl(M);
}
+ // Check the defaulted secondary comparisons after any other member functions.
+ for (FunctionDecl *FD : DefaultedSecondaryComparisons)
+ CheckExplicitlyDefaultedFunction(S, FD);
+
// ms_struct is a request to use the same ABI rules as MSVC. Check
// whether this class uses any C++ features that are implemented
// completely differently in MSVC, and if so, emit a diagnostic.
@@ -6710,20 +6834,50 @@ static bool defaultedSpecialMemberIsConstexpr(
return true;
}
+namespace {
+/// RAII object to register a defaulted function as having its exception
+/// specification computed.
+struct ComputingExceptionSpec {
+ Sema &S;
+
+ ComputingExceptionSpec(Sema &S, FunctionDecl *FD, SourceLocation Loc)
+ : S(S) {
+ Sema::CodeSynthesisContext Ctx;
+ Ctx.Kind = Sema::CodeSynthesisContext::ExceptionSpecEvaluation;
+ Ctx.PointOfInstantiation = Loc;
+ Ctx.Entity = FD;
+ S.pushCodeSynthesisContext(Ctx);
+ }
+ ~ComputingExceptionSpec() {
+ S.popCodeSynthesisContext();
+ }
+};
+}
+
static Sema::ImplicitExceptionSpecification
ComputeDefaultedSpecialMemberExceptionSpec(
Sema &S, SourceLocation Loc, CXXMethodDecl *MD, Sema::CXXSpecialMember CSM,
Sema::InheritedConstructorInfo *ICI);
static Sema::ImplicitExceptionSpecification
-computeImplicitExceptionSpec(Sema &S, SourceLocation Loc, CXXMethodDecl *MD) {
- auto CSM = S.getSpecialMember(MD);
- if (CSM != Sema::CXXInvalid)
- return ComputeDefaultedSpecialMemberExceptionSpec(S, Loc, MD, CSM, nullptr);
+ComputeDefaultedComparisonExceptionSpec(Sema &S, SourceLocation Loc,
+ FunctionDecl *FD,
+ Sema::DefaultedComparisonKind DCK);
- auto *CD = cast<CXXConstructorDecl>(MD);
+static Sema::ImplicitExceptionSpecification
+computeImplicitExceptionSpec(Sema &S, SourceLocation Loc, FunctionDecl *FD) {
+ auto DFK = S.getDefaultedFunctionKind(FD);
+ if (DFK.isSpecialMember())
+ return ComputeDefaultedSpecialMemberExceptionSpec(
+ S, Loc, cast<CXXMethodDecl>(FD), DFK.asSpecialMember(), nullptr);
+ if (DFK.isComparison())
+ return ComputeDefaultedComparisonExceptionSpec(S, Loc, FD,
+ DFK.asComparison());
+
+ auto *CD = cast<CXXConstructorDecl>(FD);
assert(CD->getInheritedConstructor() &&
- "only special members have implicit exception specs");
+ "only defaulted functions and inherited constructors have implicit "
+ "exception specs");
Sema::InheritedConstructorInfo ICI(
S, Loc, CD->getInheritedConstructor().getShadowDecl());
return ComputeDefaultedSpecialMemberExceptionSpec(
@@ -6745,34 +6899,46 @@ static FunctionProtoType::ExtProtoInfo getImplicitMethodEPI(Sema &S,
return EPI;
}
-void Sema::EvaluateImplicitExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD) {
- const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
+void Sema::EvaluateImplicitExceptionSpec(SourceLocation Loc, FunctionDecl *FD) {
+ const FunctionProtoType *FPT = FD->getType()->castAs<FunctionProtoType>();
if (FPT->getExceptionSpecType() != EST_Unevaluated)
return;
// Evaluate the exception specification.
- auto IES = computeImplicitExceptionSpec(*this, Loc, MD);
+ auto IES = computeImplicitExceptionSpec(*this, Loc, FD);
auto ESI = IES.getExceptionSpec();
// Update the type of the special member to use it.
- UpdateExceptionSpec(MD, ESI);
+ UpdateExceptionSpec(FD, ESI);
+}
+
+void Sema::CheckExplicitlyDefaultedFunction(Scope *S, FunctionDecl *FD) {
+ assert(FD->isExplicitlyDefaulted() && "not explicitly-defaulted");
- // A user-provided destructor can be defined outside the class. When that
- // happens, be sure to update the exception specification on both
- // declarations.
- const FunctionProtoType *CanonicalFPT =
- MD->getCanonicalDecl()->getType()->castAs<FunctionProtoType>();
- if (CanonicalFPT->getExceptionSpecType() == EST_Unevaluated)
- UpdateExceptionSpec(MD->getCanonicalDecl(), ESI);
+ DefaultedFunctionKind DefKind = getDefaultedFunctionKind(FD);
+ if (!DefKind) {
+ assert(FD->getDeclContext()->isDependentContext());
+ return;
+ }
+
+ if (DefKind.isSpecialMember()
+ ? CheckExplicitlyDefaultedSpecialMember(cast<CXXMethodDecl>(FD),
+ DefKind.asSpecialMember())
+ : CheckExplicitlyDefaultedComparison(S, FD, DefKind.asComparison()))
+ FD->setInvalidDecl();
}
-void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
+bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD,
+ CXXSpecialMember CSM) {
CXXRecordDecl *RD = MD->getParent();
- CXXSpecialMember CSM = getSpecialMember(MD);
assert(MD->isExplicitlyDefaulted() && CSM != CXXInvalid &&
"not an explicitly-defaulted special member");
+ // Defer all checking for special members of a dependent type.
+ if (RD->isDependentType())
+ return false;
+
// Whether this was the first-declared instance of the constructor.
// This affects whether we implicitly add an exception spec and constexpr.
bool First = MD == MD->getCanonicalDecl();
@@ -6781,7 +6947,7 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
// C++11 [dcl.fct.def.default]p1:
// A function that is explicitly defaulted shall
- // -- be a special member function (checked elsewhere),
+ // -- be a special member function [...] (checked elsewhere),
// -- have the same type (except for ref-qualifiers, and except that a
// copy operation can take a non-const reference) as an implicit
// declaration, and
@@ -6960,8 +7126,1124 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
}
}
- if (HadError)
- MD->setInvalidDecl();
+ return HadError;
+}
+
+namespace {
+/// Helper class for building and checking a defaulted comparison.
+///
+/// Defaulted functions are built in two phases:
+///
+/// * First, the set of operations that the function will perform are
+/// identified, and some of them are checked. If any of the checked
+/// operations is invalid in certain ways, the comparison function is
+/// defined as deleted and no body is built.
+/// * Then, if the function is not defined as deleted, the body is built.
+///
+/// This is accomplished by performing two visitation steps over the eventual
+/// body of the function.
+template<typename Derived, typename ResultList, typename Result,
+ typename Subobject>
+class DefaultedComparisonVisitor {
+public:
+ using DefaultedComparisonKind = Sema::DefaultedComparisonKind;
+
+ DefaultedComparisonVisitor(Sema &S, CXXRecordDecl *RD, FunctionDecl *FD,
+ DefaultedComparisonKind DCK)
+ : S(S), RD(RD), FD(FD), DCK(DCK) {
+ if (auto *Info = FD->getDefaultedFunctionInfo()) {
+ // FIXME: Change CreateOverloadedBinOp to take an ArrayRef instead of an
+ // UnresolvedSet to avoid this copy.
+ Fns.assign(Info->getUnqualifiedLookups().begin(),
+ Info->getUnqualifiedLookups().end());
+ }
+ }
+
+ ResultList visit() {
+ // The type of an lvalue naming a parameter of this function.
+ QualType ParamLvalType =
+ FD->getParamDecl(0)->getType().getNonReferenceType();
+
+ ResultList Results;
+
+ switch (DCK) {
+ case DefaultedComparisonKind::None:
+ llvm_unreachable("not a defaulted comparison");
+
+ case DefaultedComparisonKind::Equal:
+ case DefaultedComparisonKind::ThreeWay:
+ getDerived().visitSubobjects(Results, RD, ParamLvalType.getQualifiers());
+ return Results;
+
+ case DefaultedComparisonKind::NotEqual:
+ case DefaultedComparisonKind::Relational:
+ Results.add(getDerived().visitExpandedSubobject(
+ ParamLvalType, getDerived().getCompleteObject()));
+ return Results;
+ }
+ llvm_unreachable("");
+ }
+
+protected:
+ Derived &getDerived() { return static_cast<Derived&>(*this); }
+
+ /// Visit the expanded list of subobjects of the given type, as specified in
+ /// C++2a [class.compare.default].
+ ///
+ /// \return \c true if the ResultList object said we're done, \c false if not.
+ bool visitSubobjects(ResultList &Results, CXXRecordDecl *Record,
+ Qualifiers Quals) {
+ // C++2a [class.compare.default]p4:
+ // The direct base class subobjects of C
+ for (CXXBaseSpecifier &Base : Record->bases())
+ if (Results.add(getDerived().visitSubobject(
+ S.Context.getQualifiedType(Base.getType(), Quals),
+ getDerived().getBase(&Base))))
+ return true;
+
+ // followed by the non-static data members of C
+ for (FieldDecl *Field : Record->fields()) {
+ // Recursively expand anonymous structs.
+ if (Field->isAnonymousStructOrUnion()) {
+ if (visitSubobjects(Results, Field->getType()->getAsCXXRecordDecl(),
+ Quals))
+ return true;
+ continue;
+ }
+
+ // Figure out the type of an lvalue denoting this field.
+ Qualifiers FieldQuals = Quals;
+ if (Field->isMutable())
+ FieldQuals.removeConst();
+ QualType FieldType =
+ S.Context.getQualifiedType(Field->getType(), FieldQuals);
+
+ if (Results.add(getDerived().visitSubobject(
+ FieldType, getDerived().getField(Field))))
+ return true;
+ }
+
+ // form a list of subobjects.
+ return false;
+ }
+
+ Result visitSubobject(QualType Type, Subobject Subobj) {
+ // In that list, any subobject of array type is recursively expanded
+ const ArrayType *AT = S.Context.getAsArrayType(Type);
+ if (auto *CAT = dyn_cast_or_null<ConstantArrayType>(AT))
+ return getDerived().visitSubobjectArray(CAT->getElementType(),
+ CAT->getSize(), Subobj);
+ return getDerived().visitExpandedSubobject(Type, Subobj);
+ }
+
+ Result visitSubobjectArray(QualType Type, const llvm::APInt &Size,
+ Subobject Subobj) {
+ return getDerived().visitSubobject(Type, Subobj);
+ }
+
+protected:
+ Sema &S;
+ CXXRecordDecl *RD;
+ FunctionDecl *FD;
+ DefaultedComparisonKind DCK;
+ UnresolvedSet<16> Fns;
+};
+
+/// Information about a defaulted comparison, as determined by
+/// DefaultedComparisonAnalyzer.
+struct DefaultedComparisonInfo {
+ bool Deleted = false;
+ bool Constexpr = true;
+ ComparisonCategoryType Category = ComparisonCategoryType::StrongOrdering;
+
+ static DefaultedComparisonInfo deleted() {
+ DefaultedComparisonInfo Deleted;
+ Deleted.Deleted = true;
+ return Deleted;
+ }
+
+ bool add(const DefaultedComparisonInfo &R) {
+ Deleted |= R.Deleted;
+ Constexpr &= R.Constexpr;
+ Category = commonComparisonType(Category, R.Category);
+ return Deleted;
+ }
+};
+
+/// An element in the expanded list of subobjects of a defaulted comparison, as
+/// specified in C++2a [class.compare.default]p4.
+struct DefaultedComparisonSubobject {
+ enum { CompleteObject, Member, Base } Kind;
+ NamedDecl *Decl;
+ SourceLocation Loc;
+};
+
+/// A visitor over the notional body of a defaulted comparison that determines
+/// whether that body would be deleted or constexpr.
+class DefaultedComparisonAnalyzer
+ : public DefaultedComparisonVisitor<DefaultedComparisonAnalyzer,
+ DefaultedComparisonInfo,
+ DefaultedComparisonInfo,
+ DefaultedComparisonSubobject> {
+public:
+ enum DiagnosticKind { NoDiagnostics, ExplainDeleted, ExplainConstexpr };
+
+private:
+ DiagnosticKind Diagnose;
+
+public:
+ using Base = DefaultedComparisonVisitor;
+ using Result = DefaultedComparisonInfo;
+ using Subobject = DefaultedComparisonSubobject;
+
+ friend Base;
+
+ DefaultedComparisonAnalyzer(Sema &S, CXXRecordDecl *RD, FunctionDecl *FD,
+ DefaultedComparisonKind DCK,
+ DiagnosticKind Diagnose = NoDiagnostics)
+ : Base(S, RD, FD, DCK), Diagnose(Diagnose) {}
+
+ Result visit() {
+ if ((DCK == DefaultedComparisonKind::Equal ||
+ DCK == DefaultedComparisonKind::ThreeWay) &&
+ RD->hasVariantMembers()) {
+ // C++2a [class.compare.default]p2 [P2002R0]:
+ // A defaulted comparison operator function for class C is defined as
+ // deleted if [...] C has variant members.
+ if (Diagnose == ExplainDeleted) {
+ S.Diag(FD->getLocation(), diag::note_defaulted_comparison_union)
+ << FD << RD->isUnion() << RD;
+ }
+ return Result::deleted();
+ }
+
+ return Base::visit();
+ }
+
+private:
+ Subobject getCompleteObject() {
+ return Subobject{Subobject::CompleteObject, nullptr, FD->getLocation()};
+ }
+
+ Subobject getBase(CXXBaseSpecifier *Base) {
+ return Subobject{Subobject::Base, Base->getType()->getAsCXXRecordDecl(),
+ Base->getBaseTypeLoc()};
+ }
+
+ Subobject getField(FieldDecl *Field) {
+ return Subobject{Subobject::Member, Field, Field->getLocation()};
+ }
+
+ Result visitExpandedSubobject(QualType Type, Subobject Subobj) {
+ // C++2a [class.compare.default]p2 [P2002R0]:
+ // A defaulted <=> or == operator function for class C is defined as
+ // deleted if any non-static data member of C is of reference type
+ if (Type->isReferenceType()) {
+ if (Diagnose == ExplainDeleted) {
+ S.Diag(Subobj.Loc, diag::note_defaulted_comparison_reference_member)
+ << FD << RD;
+ }
+ return Result::deleted();
+ }
+
+ // [...] Let xi be an lvalue denoting the ith element [...]
+ OpaqueValueExpr Xi(FD->getLocation(), Type, VK_LValue);
+ Expr *Args[] = {&Xi, &Xi};
+
+ // All operators start by trying to apply that same operator recursively.
+ OverloadedOperatorKind OO = FD->getOverloadedOperator();
+ assert(OO != OO_None && "not an overloaded operator!");
+ return visitBinaryOperator(OO, Args, Subobj);
+ }
+
+ Result
+ visitBinaryOperator(OverloadedOperatorKind OO, ArrayRef<Expr *> Args,
+ Subobject Subobj,
+ OverloadCandidateSet *SpaceshipCandidates = nullptr) {
+ // Note that there is no need to consider rewritten candidates here if
+ // we've already found there is no viable 'operator<=>' candidate (and are
+ // considering synthesizing a '<=>' from '==' and '<').
+ OverloadCandidateSet CandidateSet(
+ FD->getLocation(), OverloadCandidateSet::CSK_Operator,
+ OverloadCandidateSet::OperatorRewriteInfo(
+ OO, /*AllowRewrittenCandidates=*/!SpaceshipCandidates));
+
+ /// C++2a [class.compare.default]p1 [P2002R0]:
+ /// [...] the defaulted function itself is never a candidate for overload
+ /// resolution [...]
+ CandidateSet.exclude(FD);
+
+ S.LookupOverloadedBinOp(CandidateSet, OO, Fns, Args);
+
+ Result R;
+
+ OverloadCandidateSet::iterator Best;
+ switch (CandidateSet.BestViableFunction(S, FD->getLocation(), Best)) {
+ case OR_Success: {
+ // C++2a [class.compare.secondary]p2 [P2002R0]:
+ // The operator function [...] is defined as deleted if [...] the
+ // candidate selected by overload resolution is not a rewritten
+ // candidate.
+ if ((DCK == DefaultedComparisonKind::NotEqual ||
+ DCK == DefaultedComparisonKind::Relational) &&
+ !Best->RewriteKind) {
+ if (Diagnose == ExplainDeleted) {
+ S.Diag(Best->Function->getLocation(),
+ diag::note_defaulted_comparison_not_rewritten_callee)
+ << FD;
+ }
+ return Result::deleted();
+ }
+
+ // Throughout C++2a [class.compare]: if overload resolution does not
+ // result in a usable function, the candidate function is defined as
+ // deleted. This requires that we selected an accessible function.
+ //
+ // Note that this only considers the access of the function when named
+ // within the type of the subobject, and not the access path for any
+ // derived-to-base conversion.
+ CXXRecordDecl *ArgClass = Args[0]->getType()->getAsCXXRecordDecl();
+ if (ArgClass && Best->FoundDecl.getDecl() &&
+ Best->FoundDecl.getDecl()->isCXXClassMember()) {
+ QualType ObjectType = Subobj.Kind == Subobject::Member
+ ? Args[0]->getType()
+ : S.Context.getRecordType(RD);
+ if (!S.isMemberAccessibleForDeletion(
+ ArgClass, Best->FoundDecl, ObjectType, Subobj.Loc,
+ Diagnose == ExplainDeleted
+ ? S.PDiag(diag::note_defaulted_comparison_inaccessible)
+ << FD << Subobj.Kind << Subobj.Decl
+ : S.PDiag()))
+ return Result::deleted();
+ }
+
+ // C++2a [class.compare.default]p3 [P2002R0]:
+ // A defaulted comparison function is constexpr-compatible if [...]
+ // no overlod resolution performed [...] results in a non-constexpr
+ // function.
+ if (FunctionDecl *BestFD = Best->Function) {
+ assert(!BestFD->isDeleted() && "wrong overload resolution result");
+ // If it's not constexpr, explain why not.
+ if (Diagnose == ExplainConstexpr && !BestFD->isConstexpr()) {
+ if (Subobj.Kind != Subobject::CompleteObject)
+ S.Diag(Subobj.Loc, diag::note_defaulted_comparison_not_constexpr)
+ << Subobj.Kind << Subobj.Decl;
+ S.Diag(BestFD->getLocation(),
+ diag::note_defaulted_comparison_not_constexpr_here);
+ // Bail out after explaining; we don't want any more notes.
+ return Result::deleted();
+ }
+ R.Constexpr &= BestFD->isConstexpr();
+ }
+
+ if (OO == OO_Spaceship && FD->getReturnType()->isUndeducedAutoType()) {
+ if (auto *BestFD = Best->Function) {
+ if (auto *Info = S.Context.CompCategories.lookupInfoForType(
+ BestFD->getCallResultType())) {
+ R.Category = Info->Kind;
+ } else {
+ if (Diagnose == ExplainDeleted) {
+ S.Diag(Subobj.Loc, diag::note_defaulted_comparison_cannot_deduce)
+ << Subobj.Kind << Subobj.Decl
+ << BestFD->getCallResultType().withoutLocalFastQualifiers();
+ S.Diag(BestFD->getLocation(),
+ diag::note_defaulted_comparison_cannot_deduce_callee)
+ << Subobj.Kind << Subobj.Decl;
+ }
+ return Result::deleted();
+ }
+ } else {
+ Optional<ComparisonCategoryType> Cat =
+ getComparisonCategoryForBuiltinCmp(Args[0]->getType());
+ assert(Cat && "no category for builtin comparison?");
+ R.Category = *Cat;
+ }
+ }
+
+ // Note that we might be rewriting to a different operator. That call is
+ // not considered until we come to actually build the comparison function.
+ break;
+ }
+
+ case OR_Ambiguous:
+ if (Diagnose == ExplainDeleted) {
+ unsigned Kind = 0;
+ if (FD->getOverloadedOperator() == OO_Spaceship && OO != OO_Spaceship)
+ Kind = OO == OO_EqualEqual ? 1 : 2;
+ CandidateSet.NoteCandidates(
+ PartialDiagnosticAt(
+ Subobj.Loc, S.PDiag(diag::note_defaulted_comparison_ambiguous)
+ << FD << Kind << Subobj.Kind << Subobj.Decl),
+ S, OCD_AmbiguousCandidates, Args);
+ }
+ R = Result::deleted();
+ break;
+
+ case OR_Deleted:
+ if (Diagnose == ExplainDeleted) {
+ if ((DCK == DefaultedComparisonKind::NotEqual ||
+ DCK == DefaultedComparisonKind::Relational) &&
+ !Best->RewriteKind) {
+ S.Diag(Best->Function->getLocation(),
+ diag::note_defaulted_comparison_not_rewritten_callee)
+ << FD;
+ } else {
+ S.Diag(Subobj.Loc,
+ diag::note_defaulted_comparison_calls_deleted)
+ << FD << Subobj.Kind << Subobj.Decl;
+ S.NoteDeletedFunction(Best->Function);
+ }
+ }
+ R = Result::deleted();
+ break;
+
+ case OR_No_Viable_Function:
+ // If there's no usable candidate, we're done unless we can rewrite a
+ // '<=>' in terms of '==' and '<'.
+ if (OO == OO_Spaceship &&
+ S.Context.CompCategories.lookupInfoForType(FD->getReturnType())) {
+ // For any kind of comparison category return type, we need a usable
+ // '==' and a usable '<'.
+ if (!R.add(visitBinaryOperator(OO_EqualEqual, Args, Subobj,
+ &CandidateSet)))
+ R.add(visitBinaryOperator(OO_Less, Args, Subobj, &CandidateSet));
+ break;
+ }
+
+ if (Diagnose == ExplainDeleted) {
+ S.Diag(Subobj.Loc, diag::note_defaulted_comparison_no_viable_function)
+ << FD << Subobj.Kind << Subobj.Decl;
+
+ // For a three-way comparison, list both the candidates for the
+ // original operator and the candidates for the synthesized operator.
+ if (SpaceshipCandidates) {
+ SpaceshipCandidates->NoteCandidates(
+ S, Args,
+ SpaceshipCandidates->CompleteCandidates(S, OCD_AllCandidates,
+ Args, FD->getLocation()));
+ S.Diag(Subobj.Loc,
+ diag::note_defaulted_comparison_no_viable_function_synthesized)
+ << (OO == OO_EqualEqual ? 0 : 1);
+ }
+
+ CandidateSet.NoteCandidates(
+ S, Args,
+ CandidateSet.CompleteCandidates(S, OCD_AllCandidates, Args,
+ FD->getLocation()));
+ }
+ R = Result::deleted();
+ break;
+ }
+
+ return R;
+ }
+};
+
+/// A list of statements.
+struct StmtListResult {
+ bool IsInvalid = false;
+ llvm::SmallVector<Stmt*, 16> Stmts;
+
+ bool add(const StmtResult &S) {
+ IsInvalid |= S.isInvalid();
+ if (IsInvalid)
+ return true;
+ Stmts.push_back(S.get());
+ return false;
+ }
+};
+
+/// A visitor over the notional body of a defaulted comparison that synthesizes
+/// the actual body.
+class DefaultedComparisonSynthesizer
+ : public DefaultedComparisonVisitor<DefaultedComparisonSynthesizer,
+ StmtListResult, StmtResult,
+ std::pair<ExprResult, ExprResult>> {
+ SourceLocation Loc;
+ unsigned ArrayDepth = 0;
+
+public:
+ using Base = DefaultedComparisonVisitor;
+ using ExprPair = std::pair<ExprResult, ExprResult>;
+
+ friend Base;
+
+ DefaultedComparisonSynthesizer(Sema &S, CXXRecordDecl *RD, FunctionDecl *FD,
+ DefaultedComparisonKind DCK,
+ SourceLocation BodyLoc)
+ : Base(S, RD, FD, DCK), Loc(BodyLoc) {}
+
+ /// Build a suitable function body for this defaulted comparison operator.
+ StmtResult build() {
+ Sema::CompoundScopeRAII CompoundScope(S);
+
+ StmtListResult Stmts = visit();
+ if (Stmts.IsInvalid)
+ return StmtError();
+
+ ExprResult RetVal;
+ switch (DCK) {
+ case DefaultedComparisonKind::None:
+ llvm_unreachable("not a defaulted comparison");
+
+ case DefaultedComparisonKind::Equal: {
+ // C++2a [class.eq]p3:
+ // [...] compar[e] the corresponding elements [...] until the first
+ // index i where xi == yi yields [...] false. If no such index exists,
+ // V is true. Otherwise, V is false.
+ //
+ // Join the comparisons with '&&'s and return the result. Use a right
+ // fold (traversing the conditions right-to-left), because that
+ // short-circuits more naturally.
+ auto OldStmts = std::move(Stmts.Stmts);
+ Stmts.Stmts.clear();
+ ExprResult CmpSoFar;
+ // Finish a particular comparison chain.
+ auto FinishCmp = [&] {
+ if (Expr *Prior = CmpSoFar.get()) {
+ // Convert the last expression to 'return ...;'
+ if (RetVal.isUnset() && Stmts.Stmts.empty())
+ RetVal = CmpSoFar;
+ // Convert any prior comparison to 'if (!(...)) return false;'
+ else if (Stmts.add(buildIfNotCondReturnFalse(Prior)))
+ return true;
+ CmpSoFar = ExprResult();
+ }
+ return false;
+ };
+ for (Stmt *EAsStmt : llvm::reverse(OldStmts)) {
+ Expr *E = dyn_cast<Expr>(EAsStmt);
+ if (!E) {
+ // Found an array comparison.
+ if (FinishCmp() || Stmts.add(EAsStmt))
+ return StmtError();
+ continue;
+ }
+
+ if (CmpSoFar.isUnset()) {
+ CmpSoFar = E;
+ continue;
+ }
+ CmpSoFar = S.CreateBuiltinBinOp(Loc, BO_LAnd, E, CmpSoFar.get());
+ if (CmpSoFar.isInvalid())
+ return StmtError();
+ }
+ if (FinishCmp())
+ return StmtError();
+ std::reverse(Stmts.Stmts.begin(), Stmts.Stmts.end());
+ // If no such index exists, V is true.
+ if (RetVal.isUnset())
+ RetVal = S.ActOnCXXBoolLiteral(Loc, tok::kw_true);
+ break;
+ }
+
+ case DefaultedComparisonKind::ThreeWay: {
+ // Per C++2a [class.spaceship]p3, as a fallback add:
+ // return static_cast<R>(std::strong_ordering::equal);
+ QualType StrongOrdering = S.CheckComparisonCategoryType(
+ ComparisonCategoryType::StrongOrdering, Loc,
+ Sema::ComparisonCategoryUsage::DefaultedOperator);
+ if (StrongOrdering.isNull())
+ return StmtError();
+ VarDecl *EqualVD = S.Context.CompCategories.getInfoForType(StrongOrdering)
+ .getValueInfo(ComparisonCategoryResult::Equal)
+ ->VD;
+ RetVal = getDecl(EqualVD);
+ if (RetVal.isInvalid())
+ return StmtError();
+ RetVal = buildStaticCastToR(RetVal.get());
+ break;
+ }
+
+ case DefaultedComparisonKind::NotEqual:
+ case DefaultedComparisonKind::Relational:
+ RetVal = cast<Expr>(Stmts.Stmts.pop_back_val());
+ break;
+ }
+
+ // Build the final return statement.
+ if (RetVal.isInvalid())
+ return StmtError();
+ StmtResult ReturnStmt = S.BuildReturnStmt(Loc, RetVal.get());
+ if (ReturnStmt.isInvalid())
+ return StmtError();
+ Stmts.Stmts.push_back(ReturnStmt.get());
+
+ return S.ActOnCompoundStmt(Loc, Loc, Stmts.Stmts, /*IsStmtExpr=*/false);
+ }
+
+private:
+ ExprResult getDecl(ValueDecl *VD) {
+ return S.BuildDeclarationNameExpr(
+ CXXScopeSpec(), DeclarationNameInfo(VD->getDeclName(), Loc), VD);
+ }
+
+ ExprResult getParam(unsigned I) {
+ ParmVarDecl *PD = FD->getParamDecl(I);
+ return getDecl(PD);
+ }
+
+ ExprPair getCompleteObject() {
+ unsigned Param = 0;
+ ExprResult LHS;
+ if (isa<CXXMethodDecl>(FD)) {
+ // LHS is '*this'.
+ LHS = S.ActOnCXXThis(Loc);
+ if (!LHS.isInvalid())
+ LHS = S.CreateBuiltinUnaryOp(Loc, UO_Deref, LHS.get());
+ } else {
+ LHS = getParam(Param++);
+ }
+ ExprResult RHS = getParam(Param++);
+ assert(Param == FD->getNumParams());
+ return {LHS, RHS};
+ }
+
+ ExprPair getBase(CXXBaseSpecifier *Base) {
+ ExprPair Obj = getCompleteObject();
+ if (Obj.first.isInvalid() || Obj.second.isInvalid())
+ return {ExprError(), ExprError()};
+ CXXCastPath Path = {Base};
+ return {S.ImpCastExprToType(Obj.first.get(), Base->getType(),
+ CK_DerivedToBase, VK_LValue, &Path),
+ S.ImpCastExprToType(Obj.second.get(), Base->getType(),
+ CK_DerivedToBase, VK_LValue, &Path)};
+ }
+
+ ExprPair getField(FieldDecl *Field) {
+ ExprPair Obj = getCompleteObject();
+ if (Obj.first.isInvalid() || Obj.second.isInvalid())
+ return {ExprError(), ExprError()};
+
+ DeclAccessPair Found = DeclAccessPair::make(Field, Field->getAccess());
+ DeclarationNameInfo NameInfo(Field->getDeclName(), Loc);
+ return {S.BuildFieldReferenceExpr(Obj.first.get(), /*IsArrow=*/false, Loc,
+ CXXScopeSpec(), Field, Found, NameInfo),
+ S.BuildFieldReferenceExpr(Obj.second.get(), /*IsArrow=*/false, Loc,
+ CXXScopeSpec(), Field, Found, NameInfo)};
+ }
+
+ // FIXME: When expanding a subobject, register a note in the code synthesis
+ // stack to say which subobject we're comparing.
+
+ StmtResult buildIfNotCondReturnFalse(ExprResult Cond) {
+ if (Cond.isInvalid())
+ return StmtError();
+
+ ExprResult NotCond = S.CreateBuiltinUnaryOp(Loc, UO_LNot, Cond.get());
+ if (NotCond.isInvalid())
+ return StmtError();
+
+ ExprResult False = S.ActOnCXXBoolLiteral(Loc, tok::kw_false);
+ assert(!False.isInvalid() && "should never fail");
+ StmtResult ReturnFalse = S.BuildReturnStmt(Loc, False.get());
+ if (ReturnFalse.isInvalid())
+ return StmtError();
+
+ return S.ActOnIfStmt(Loc, false, nullptr,
+ S.ActOnCondition(nullptr, Loc, NotCond.get(),
+ Sema::ConditionKind::Boolean),
+ ReturnFalse.get(), SourceLocation(), nullptr);
+ }
+
+ StmtResult visitSubobjectArray(QualType Type, llvm::APInt Size,
+ ExprPair Subobj) {
+ QualType SizeType = S.Context.getSizeType();
+ Size = Size.zextOrTrunc(S.Context.getTypeSize(SizeType));
+
+ // Build 'size_t i$n = 0'.
+ IdentifierInfo *IterationVarName = nullptr;
+ {
+ SmallString<8> Str;
+ llvm::raw_svector_ostream OS(Str);
+ OS << "i" << ArrayDepth;
+ IterationVarName = &S.Context.Idents.get(OS.str());
+ }
+ VarDecl *IterationVar = VarDecl::Create(
+ S.Context, S.CurContext, Loc, Loc, IterationVarName, SizeType,
+ S.Context.getTrivialTypeSourceInfo(SizeType, Loc), SC_None);
+ llvm::APInt Zero(S.Context.getTypeSize(SizeType), 0);
+ IterationVar->setInit(
+ IntegerLiteral::Create(S.Context, Zero, SizeType, Loc));
+ Stmt *Init = new (S.Context) DeclStmt(DeclGroupRef(IterationVar), Loc, Loc);
+
+ auto IterRef = [&] {
+ ExprResult Ref = S.BuildDeclarationNameExpr(
+ CXXScopeSpec(), DeclarationNameInfo(IterationVarName, Loc),
+ IterationVar);
+ assert(!Ref.isInvalid() && "can't reference our own variable?");
+ return Ref.get();
+ };
+
+ // Build 'i$n != Size'.
+ ExprResult Cond = S.CreateBuiltinBinOp(
+ Loc, BO_NE, IterRef(),
+ IntegerLiteral::Create(S.Context, Size, SizeType, Loc));
+ assert(!Cond.isInvalid() && "should never fail");
+
+ // Build '++i$n'.
+ ExprResult Inc = S.CreateBuiltinUnaryOp(Loc, UO_PreInc, IterRef());
+ assert(!Inc.isInvalid() && "should never fail");
+
+ // Build 'a[i$n]' and 'b[i$n]'.
+ auto Index = [&](ExprResult E) {
+ if (E.isInvalid())
+ return ExprError();
+ return S.CreateBuiltinArraySubscriptExpr(E.get(), Loc, IterRef(), Loc);
+ };
+ Subobj.first = Index(Subobj.first);
+ Subobj.second = Index(Subobj.second);
+
+ // Compare the array elements.
+ ++ArrayDepth;
+ StmtResult Substmt = visitSubobject(Type, Subobj);
+ --ArrayDepth;
+
+ if (Substmt.isInvalid())
+ return StmtError();
+
+ // For the inner level of an 'operator==', build 'if (!cmp) return false;'.
+ // For outer levels or for an 'operator<=>' we already have a suitable
+ // statement that returns as necessary.
+ if (Expr *ElemCmp = dyn_cast<Expr>(Substmt.get())) {
+ assert(DCK == DefaultedComparisonKind::Equal &&
+ "should have non-expression statement");
+ Substmt = buildIfNotCondReturnFalse(ElemCmp);
+ if (Substmt.isInvalid())
+ return StmtError();
+ }
+
+ // Build 'for (...) ...'
+ return S.ActOnForStmt(Loc, Loc, Init,
+ S.ActOnCondition(nullptr, Loc, Cond.get(),
+ Sema::ConditionKind::Boolean),
+ S.MakeFullDiscardedValueExpr(Inc.get()), Loc,
+ Substmt.get());
+ }
+
+ StmtResult visitExpandedSubobject(QualType Type, ExprPair Obj) {
+ if (Obj.first.isInvalid() || Obj.second.isInvalid())
+ return StmtError();
+
+ OverloadedOperatorKind OO = FD->getOverloadedOperator();
+ ExprResult Op = S.CreateOverloadedBinOp(
+ Loc, BinaryOperator::getOverloadedOpcode(OO), Fns,
+ Obj.first.get(), Obj.second.get(), /*PerformADL=*/true,
+ /*AllowRewrittenCandidates=*/true, FD);
+ if (Op.isInvalid())
+ return StmtError();
+
+ switch (DCK) {
+ case DefaultedComparisonKind::None:
+ llvm_unreachable("not a defaulted comparison");
+
+ case DefaultedComparisonKind::Equal:
+ // Per C++2a [class.eq]p2, each comparison is individually contextually
+ // converted to bool.
+ Op = S.PerformContextuallyConvertToBool(Op.get());
+ if (Op.isInvalid())
+ return StmtError();
+ return Op.get();
+
+ case DefaultedComparisonKind::ThreeWay: {
+ // Per C++2a [class.spaceship]p3, form:
+ // if (R cmp = static_cast<R>(op); cmp != 0)
+ // return cmp;
+ QualType R = FD->getReturnType();
+ Op = buildStaticCastToR(Op.get());
+ if (Op.isInvalid())
+ return StmtError();
+
+ // R cmp = ...;
+ IdentifierInfo *Name = &S.Context.Idents.get("cmp");
+ VarDecl *VD =
+ VarDecl::Create(S.Context, S.CurContext, Loc, Loc, Name, R,
+ S.Context.getTrivialTypeSourceInfo(R, Loc), SC_None);
+ S.AddInitializerToDecl(VD, Op.get(), /*DirectInit=*/false);
+ Stmt *InitStmt = new (S.Context) DeclStmt(DeclGroupRef(VD), Loc, Loc);
+
+ // cmp != 0
+ ExprResult VDRef = getDecl(VD);
+ if (VDRef.isInvalid())
+ return StmtError();
+ llvm::APInt ZeroVal(S.Context.getIntWidth(S.Context.IntTy), 0);
+ Expr *Zero =
+ IntegerLiteral::Create(S.Context, ZeroVal, S.Context.IntTy, Loc);
+ ExprResult Comp = S.CreateOverloadedBinOp(Loc, BO_NE, Fns, VDRef.get(),
+ Zero, true, true, FD);
+ if (Comp.isInvalid())
+ return StmtError();
+ Sema::ConditionResult Cond = S.ActOnCondition(
+ nullptr, Loc, Comp.get(), Sema::ConditionKind::Boolean);
+ if (Cond.isInvalid())
+ return StmtError();
+
+ // return cmp;
+ VDRef = getDecl(VD);
+ if (VDRef.isInvalid())
+ return StmtError();
+ StmtResult ReturnStmt = S.BuildReturnStmt(Loc, VDRef.get());
+ if (ReturnStmt.isInvalid())
+ return StmtError();
+
+ // if (...)
+ return S.ActOnIfStmt(Loc, /*IsConstexpr=*/false, InitStmt, Cond,
+ ReturnStmt.get(), /*ElseLoc=*/SourceLocation(),
+ /*Else=*/nullptr);
+ }
+
+ case DefaultedComparisonKind::NotEqual:
+ case DefaultedComparisonKind::Relational:
+ // C++2a [class.compare.secondary]p2:
+ // Otherwise, the operator function yields x @ y.
+ return Op.get();
+ }
+ llvm_unreachable("");
+ }
+
+ /// Build "static_cast<R>(E)".
+ ExprResult buildStaticCastToR(Expr *E) {
+ QualType R = FD->getReturnType();
+ assert(!R->isUndeducedType() && "type should have been deduced already");
+
+ // Don't bother forming a no-op cast in the common case.
+ if (E->isRValue() && S.Context.hasSameType(E->getType(), R))
+ return E;
+ return S.BuildCXXNamedCast(Loc, tok::kw_static_cast,
+ S.Context.getTrivialTypeSourceInfo(R, Loc), E,
+ SourceRange(Loc, Loc), SourceRange(Loc, Loc));
+ }
+};
+}
+
+/// Perform the unqualified lookups that might be needed to form a defaulted
+/// comparison function for the given operator.
+static void lookupOperatorsForDefaultedComparison(Sema &Self, Scope *S,
+ UnresolvedSetImpl &Operators,
+ OverloadedOperatorKind Op) {
+ auto Lookup = [&](OverloadedOperatorKind OO) {
+ Self.LookupOverloadedOperatorName(OO, S, QualType(), QualType(), Operators);
+ };
+
+ // Every defaulted operator looks up itself.
+ Lookup(Op);
+ // ... and the rewritten form of itself, if any.
+ if (OverloadedOperatorKind ExtraOp = getRewrittenOverloadedOperator(Op))
+ Lookup(ExtraOp);
+
+ // For 'operator<=>', we also form a 'cmp != 0' expression, and might
+ // synthesize a three-way comparison from '<' and '=='. In a dependent
+ // context, we also need to look up '==' in case we implicitly declare a
+ // defaulted 'operator=='.
+ if (Op == OO_Spaceship) {
+ Lookup(OO_ExclaimEqual);
+ Lookup(OO_Less);
+ Lookup(OO_EqualEqual);
+ }
+}
+
+bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD,
+ DefaultedComparisonKind DCK) {
+ assert(DCK != DefaultedComparisonKind::None && "not a defaulted comparison");
+
+ CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(FD->getLexicalDeclContext());
+ assert(RD && "defaulted comparison is not defaulted in a class");
+
+ // Perform any unqualified lookups we're going to need to default this
+ // function.
+ if (S) {
+ UnresolvedSet<32> Operators;
+ lookupOperatorsForDefaultedComparison(*this, S, Operators,
+ FD->getOverloadedOperator());
+ FD->setDefaultedFunctionInfo(FunctionDecl::DefaultedFunctionInfo::Create(
+ Context, Operators.pairs()));
+ }
+
+ // C++2a [class.compare.default]p1:
+ // A defaulted comparison operator function for some class C shall be a
+ // non-template function declared in the member-specification of C that is
+ // -- a non-static const member of C having one parameter of type
+ // const C&, or
+ // -- a friend of C having two parameters of type const C& or two
+ // parameters of type C.
+ QualType ExpectedParmType1 = Context.getRecordType(RD);
+ QualType ExpectedParmType2 =
+ Context.getLValueReferenceType(ExpectedParmType1.withConst());
+ if (isa<CXXMethodDecl>(FD))
+ ExpectedParmType1 = ExpectedParmType2;
+ for (const ParmVarDecl *Param : FD->parameters()) {
+ if (!Param->getType()->isDependentType() &&
+ !Context.hasSameType(Param->getType(), ExpectedParmType1) &&
+ !Context.hasSameType(Param->getType(), ExpectedParmType2)) {
+ // Don't diagnose an implicit 'operator=='; we will have diagnosed the
+ // corresponding defaulted 'operator<=>' already.
+ if (!FD->isImplicit()) {
+ Diag(FD->getLocation(), diag::err_defaulted_comparison_param)
+ << (int)DCK << Param->getType() << ExpectedParmType1
+ << !isa<CXXMethodDecl>(FD)
+ << ExpectedParmType2 << Param->getSourceRange();
+ }
+ return true;
+ }
+ }
+ if (FD->getNumParams() == 2 &&
+ !Context.hasSameType(FD->getParamDecl(0)->getType(),
+ FD->getParamDecl(1)->getType())) {
+ if (!FD->isImplicit()) {
+ Diag(FD->getLocation(), diag::err_defaulted_comparison_param_mismatch)
+ << (int)DCK
+ << FD->getParamDecl(0)->getType()
+ << FD->getParamDecl(0)->getSourceRange()
+ << FD->getParamDecl(1)->getType()
+ << FD->getParamDecl(1)->getSourceRange();
+ }
+ return true;
+ }
+
+ // ... non-static const member ...
+ if (auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
+ assert(!MD->isStatic() && "comparison function cannot be a static member");
+ if (!MD->isConst()) {
+ SourceLocation InsertLoc;
+ if (FunctionTypeLoc Loc = MD->getFunctionTypeLoc())
+ InsertLoc = getLocForEndOfToken(Loc.getRParenLoc());
+ // Don't diagnose an implicit 'operator=='; we will have diagnosed the
+ // corresponding defaulted 'operator<=>' already.
+ if (!MD->isImplicit()) {
+ Diag(MD->getLocation(), diag::err_defaulted_comparison_non_const)
+ << (int)DCK << FixItHint::CreateInsertion(InsertLoc, " const");
+ }
+
+ // Add the 'const' to the type to recover.
+ const auto *FPT = MD->getType()->castAs<FunctionProtoType>();
+ FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
+ EPI.TypeQuals.addConst();
+ MD->setType(Context.getFunctionType(FPT->getReturnType(),
+ FPT->getParamTypes(), EPI));
+ }
+ } else {
+ // A non-member function declared in a class must be a friend.
+ assert(FD->getFriendObjectKind() && "expected a friend declaration");
+ }
+
+ // C++2a [class.eq]p1, [class.rel]p1:
+ // A [defaulted comparison other than <=>] shall have a declared return
+ // type bool.
+ if (DCK != DefaultedComparisonKind::ThreeWay &&
+ !FD->getDeclaredReturnType()->isDependentType() &&
+ !Context.hasSameType(FD->getDeclaredReturnType(), Context.BoolTy)) {
+ Diag(FD->getLocation(), diag::err_defaulted_comparison_return_type_not_bool)
+ << (int)DCK << FD->getDeclaredReturnType() << Context.BoolTy
+ << FD->getReturnTypeSourceRange();
+ return true;
+ }
+ // C++2a [class.spaceship]p2 [P2002R0]:
+ // Let R be the declared return type [...]. If R is auto, [...]. Otherwise,
+ // R shall not contain a placeholder type.
+ if (DCK == DefaultedComparisonKind::ThreeWay &&
+ FD->getDeclaredReturnType()->getContainedDeducedType() &&
+ !Context.hasSameType(FD->getDeclaredReturnType(),
+ Context.getAutoDeductType())) {
+ Diag(FD->getLocation(),
+ diag::err_defaulted_comparison_deduced_return_type_not_auto)
+ << (int)DCK << FD->getDeclaredReturnType() << Context.AutoDeductTy
+ << FD->getReturnTypeSourceRange();
+ return true;
+ }
+
+ // For a defaulted function in a dependent class, defer all remaining checks
+ // until instantiation.
+ if (RD->isDependentType())
+ return false;
+
+ // Determine whether the function should be defined as deleted.
+ DefaultedComparisonInfo Info =
+ DefaultedComparisonAnalyzer(*this, RD, FD, DCK).visit();
+
+ bool First = FD == FD->getCanonicalDecl();
+
+ // If we want to delete the function, then do so; there's nothing else to
+ // check in that case.
+ if (Info.Deleted) {
+ if (!First) {
+ // C++11 [dcl.fct.def.default]p4:
+ // [For a] user-provided explicitly-defaulted function [...] if such a
+ // function is implicitly defined as deleted, the program is ill-formed.
+ //
+ // This is really just a consequence of the general rule that you can
+ // only delete a function on its first declaration.
+ Diag(FD->getLocation(), diag::err_non_first_default_compare_deletes)
+ << FD->isImplicit() << (int)DCK;
+ DefaultedComparisonAnalyzer(*this, RD, FD, DCK,
+ DefaultedComparisonAnalyzer::ExplainDeleted)
+ .visit();
+ return true;
+ }
+
+ SetDeclDeleted(FD, FD->getLocation());
+ if (!inTemplateInstantiation() && !FD->isImplicit()) {
+ Diag(FD->getLocation(), diag::warn_defaulted_comparison_deleted)
+ << (int)DCK;
+ DefaultedComparisonAnalyzer(*this, RD, FD, DCK,
+ DefaultedComparisonAnalyzer::ExplainDeleted)
+ .visit();
+ }
+ return false;
+ }
+
+ // C++2a [class.spaceship]p2:
+ // The return type is deduced as the common comparison type of R0, R1, ...
+ if (DCK == DefaultedComparisonKind::ThreeWay &&
+ FD->getDeclaredReturnType()->isUndeducedAutoType()) {
+ SourceLocation RetLoc = FD->getReturnTypeSourceRange().getBegin();
+ if (RetLoc.isInvalid())
+ RetLoc = FD->getBeginLoc();
+ // FIXME: Should we really care whether we have the complete type and the
+ // 'enumerator' constants here? A forward declaration seems sufficient.
+ QualType Cat = CheckComparisonCategoryType(
+ Info.Category, RetLoc, ComparisonCategoryUsage::DefaultedOperator);
+ if (Cat.isNull())
+ return true;
+ Context.adjustDeducedFunctionResultType(
+ FD, SubstAutoType(FD->getDeclaredReturnType(), Cat));
+ }
+
+ // C++2a [dcl.fct.def.default]p3 [P2002R0]:
+ // An explicitly-defaulted function that is not defined as deleted may be
+ // declared constexpr or consteval only if it is constexpr-compatible.
+ // C++2a [class.compare.default]p3 [P2002R0]:
+ // A defaulted comparison function is constexpr-compatible if it satisfies
+ // the requirements for a constexpr function [...]
+ // The only relevant requirements are that the parameter and return types are
+ // literal types. The remaining conditions are checked by the analyzer.
+ if (FD->isConstexpr()) {
+ if (CheckConstexprReturnType(*this, FD, CheckConstexprKind::Diagnose) &&
+ CheckConstexprParameterTypes(*this, FD, CheckConstexprKind::Diagnose) &&
+ !Info.Constexpr) {
+ Diag(FD->getBeginLoc(),
+ diag::err_incorrect_defaulted_comparison_constexpr)
+ << FD->isImplicit() << (int)DCK << FD->isConsteval();
+ DefaultedComparisonAnalyzer(*this, RD, FD, DCK,
+ DefaultedComparisonAnalyzer::ExplainConstexpr)
+ .visit();
+ }
+ }
+
+ // C++2a [dcl.fct.def.default]p3 [P2002R0]:
+ // If a constexpr-compatible function is explicitly defaulted on its first
+ // declaration, it is implicitly considered to be constexpr.
+ // FIXME: Only applying this to the first declaration seems problematic, as
+ // simple reorderings can affect the meaning of the program.
+ if (First && !FD->isConstexpr() && Info.Constexpr)
+ FD->setConstexprKind(CSK_constexpr);
+
+ // C++2a [except.spec]p3:
+ // If a declaration of a function does not have a noexcept-specifier
+ // [and] is defaulted on its first declaration, [...] the exception
+ // specification is as specified below
+ if (FD->getExceptionSpecType() == EST_None) {
+ auto *FPT = FD->getType()->castAs<FunctionProtoType>();
+ FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
+ EPI.ExceptionSpec.Type = EST_Unevaluated;
+ EPI.ExceptionSpec.SourceDecl = FD;
+ FD->setType(Context.getFunctionType(FPT->getReturnType(),
+ FPT->getParamTypes(), EPI));
+ }
+
+ return false;
+}
+
+void Sema::DeclareImplicitEqualityComparison(CXXRecordDecl *RD,
+ FunctionDecl *Spaceship) {
+ Sema::CodeSynthesisContext Ctx;
+ Ctx.Kind = Sema::CodeSynthesisContext::DeclaringImplicitEqualityComparison;
+ Ctx.PointOfInstantiation = Spaceship->getEndLoc();
+ Ctx.Entity = Spaceship;
+ pushCodeSynthesisContext(Ctx);
+
+ if (FunctionDecl *EqualEqual = SubstSpaceshipAsEqualEqual(RD, Spaceship))
+ EqualEqual->setImplicit();
+
+ popCodeSynthesisContext();
+}
+
+void Sema::DefineDefaultedComparison(SourceLocation UseLoc, FunctionDecl *FD,
+ DefaultedComparisonKind DCK) {
+ assert(FD->isDefaulted() && !FD->isDeleted() &&
+ !FD->doesThisDeclarationHaveABody());
+ if (FD->willHaveBody() || FD->isInvalidDecl())
+ return;
+
+ SynthesizedFunctionScope Scope(*this, FD);
+
+ // Add a context note for diagnostics produced after this point.
+ Scope.addContextNote(UseLoc);
+
+ {
+ // Build and set up the function body.
+ CXXRecordDecl *RD = cast<CXXRecordDecl>(FD->getLexicalParent());
+ SourceLocation BodyLoc =
+ FD->getEndLoc().isValid() ? FD->getEndLoc() : FD->getLocation();
+ StmtResult Body =
+ DefaultedComparisonSynthesizer(*this, RD, FD, DCK, BodyLoc).build();
+ if (Body.isInvalid()) {
+ FD->setInvalidDecl();
+ return;
+ }
+ FD->setBody(Body.get());
+ FD->markUsed(Context);
+ }
+
+ // The exception specification is needed because we are defining the
+ // function. Note that this will reuse the body we just built.
+ ResolveExceptionSpec(UseLoc, FD->getType()->castAs<FunctionProtoType>());
+
+ if (ASTMutationListener *L = getASTMutationListener())
+ L->CompletedImplicitDefinition(FD);
+}
+
+static Sema::ImplicitExceptionSpecification
+ComputeDefaultedComparisonExceptionSpec(Sema &S, SourceLocation Loc,
+ FunctionDecl *FD,
+ Sema::DefaultedComparisonKind DCK) {
+ ComputingExceptionSpec CES(S, FD, Loc);
+ Sema::ImplicitExceptionSpecification ExceptSpec(S);
+
+ if (FD->isInvalidDecl())
+ return ExceptSpec;
+
+ // The common case is that we just defined the comparison function. In that
+ // case, just look at whether the body can throw.
+ if (FD->hasBody()) {
+ ExceptSpec.CalledStmt(FD->getBody());
+ } else {
+ // Otherwise, build a body so we can check it. This should ideally only
+ // happen when we're not actually marking the function referenced. (This is
+ // only really important for efficiency: we don't want to build and throw
+ // away bodies for comparison functions more than we strictly need to.)
+
+ // Pretend to synthesize the function body in an unevaluated context.
+ // Note that we can't actually just go ahead and define the function here:
+ // we are not permitted to mark its callees as referenced.
+ Sema::SynthesizedFunctionScope Scope(S, FD);
+ EnterExpressionEvaluationContext Context(
+ S, Sema::ExpressionEvaluationContext::Unevaluated);
+
+ CXXRecordDecl *RD = cast<CXXRecordDecl>(FD->getLexicalParent());
+ SourceLocation BodyLoc =
+ FD->getEndLoc().isValid() ? FD->getEndLoc() : FD->getLocation();
+ StmtResult Body =
+ DefaultedComparisonSynthesizer(S, RD, FD, DCK, BodyLoc).build();
+ if (!Body.isInvalid())
+ ExceptSpec.CalledStmt(Body.get());
+
+ // FIXME: Can we hold onto this body and just transform it to potentially
+ // evaluated when we're asked to define the function rather than rebuilding
+ // it? Either that, or we should only build the bits of the body that we
+ // need (the expressions, not the statements).
+ }
+
+ return ExceptSpec;
}
void Sema::CheckDelayedMemberExceptionSpecs() {
@@ -7157,7 +8439,8 @@ bool SpecialMemberDeletionInfo::isAccessible(Subobject Subobj,
objectTy = S.Context.getTypeDeclType(target->getParent());
}
- return S.isSpecialMemberAccessibleForDeletion(target, access, objectTy);
+ return S.isMemberAccessibleForDeletion(
+ target->getParent(), DeclAccessPair::make(target, access), objectTy);
}
/// Check whether we should delete a special member due to the implicit
@@ -7568,6 +8851,22 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM,
return false;
}
+void Sema::DiagnoseDeletedDefaultedFunction(FunctionDecl *FD) {
+ DefaultedFunctionKind DFK = getDefaultedFunctionKind(FD);
+ assert(DFK && "not a defaultable function");
+ assert(FD->isDefaulted() && FD->isDeleted() && "not defaulted and deleted");
+
+ if (DFK.isSpecialMember()) {
+ ShouldDeleteSpecialMember(cast<CXXMethodDecl>(FD), DFK.asSpecialMember(),
+ nullptr, /*Diagnose=*/true);
+ } else {
+ DefaultedComparisonAnalyzer(
+ *this, cast<CXXRecordDecl>(FD->getLexicalDeclContext()), FD,
+ DFK.asComparison(), DefaultedComparisonAnalyzer::ExplainDeleted)
+ .visit();
+ }
+}
+
/// Perform lookup for a special member of the specified kind, and determine
/// whether it is trivial. If the triviality can be determined without the
/// lookup, skip it. This is intended for use when determining whether a
@@ -8187,7 +9486,45 @@ void Sema::ActOnFinishCXXMemberSpecification(
reinterpret_cast<Decl**>(FieldCollector->getCurFields()),
FieldCollector->getCurNumFields()), LBrac, RBrac, AttrList);
- CheckCompletedCXXClass(cast<CXXRecordDecl>(TagDecl));
+ CheckCompletedCXXClass(S, cast<CXXRecordDecl>(TagDecl));
+}
+
+/// Find the equality comparison functions that should be implicitly declared
+/// in a given class definition, per C++2a [class.compare.default]p3.
+static void findImplicitlyDeclaredEqualityComparisons(
+ ASTContext &Ctx, CXXRecordDecl *RD,
+ llvm::SmallVectorImpl<FunctionDecl *> &Spaceships) {
+ DeclarationName EqEq = Ctx.DeclarationNames.getCXXOperatorName(OO_EqualEqual);
+ if (!RD->lookup(EqEq).empty())
+ // Member operator== explicitly declared: no implicit operator==s.
+ return;
+
+ // Traverse friends looking for an '==' or a '<=>'.
+ for (FriendDecl *Friend : RD->friends()) {
+ FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Friend->getFriendDecl());
+ if (!FD) continue;
+
+ if (FD->getOverloadedOperator() == OO_EqualEqual) {
+ // Friend operator== explicitly declared: no implicit operator==s.
+ Spaceships.clear();
+ return;
+ }
+
+ if (FD->getOverloadedOperator() == OO_Spaceship &&
+ FD->isExplicitlyDefaulted())
+ Spaceships.push_back(FD);
+ }
+
+ // Look for members named 'operator<=>'.
+ DeclarationName Cmp = Ctx.DeclarationNames.getCXXOperatorName(OO_Spaceship);
+ for (NamedDecl *ND : RD->lookup(Cmp)) {
+ // Note that we could find a non-function here (either a function template
+ // or a using-declaration). Neither case results in an implicit
+ // 'operator=='.
+ if (auto *FD = dyn_cast<FunctionDecl>(ND))
+ if (FD->isExplicitlyDefaulted())
+ Spaceships.push_back(FD);
+ }
}
/// AddImplicitlyDeclaredMembersToClass - Adds any implicitly-declared
@@ -8267,6 +9604,20 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
ClassDecl->needsOverloadResolutionForDestructor())
DeclareImplicitDestructor(ClassDecl);
}
+
+ // C++2a [class.compare.default]p3:
+ // If the member-specification does not explicitly declare any member or
+ // friend named operator==, an == operator function is declared implicitly
+ // for each defaulted three-way comparison operator function defined in the
+ // member-specification
+ // FIXME: Consider doing this lazily.
+ if (getLangOpts().CPlusPlus2a) {
+ llvm::SmallVector<FunctionDecl*, 4> DefaultedSpaceships;
+ findImplicitlyDeclaredEqualityComparisons(Context, ClassDecl,
+ DefaultedSpaceships);
+ for (auto *FD : DefaultedSpaceships)
+ DeclareImplicitEqualityComparison(ClassDecl, FD);
+ }
}
unsigned Sema::ActOnReenterTemplateScope(Scope *S, Decl *D) {
@@ -8478,7 +9829,7 @@ QualType Sema::CheckConstructorDeclarator(Declarator &D, QualType R,
// Rebuild the function type "R" without any type qualifiers (in
// case any of the errors above fired) and with "void" as the
// return type, since constructors don't have return types.
- const FunctionProtoType *Proto = R->getAs<FunctionProtoType>();
+ const FunctionProtoType *Proto = R->castAs<FunctionProtoType>();
if (Proto->getReturnType() == Context.VoidTy && !D.isInvalidType())
return R;
@@ -8676,7 +10027,7 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R,
if (!D.isInvalidType())
return R;
- const FunctionProtoType *Proto = R->getAs<FunctionProtoType>();
+ const FunctionProtoType *Proto = R->castAs<FunctionProtoType>();
FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo();
EPI.Variadic = false;
EPI.TypeQuals = Qualifiers();
@@ -8750,7 +10101,7 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
D.setInvalidType();
}
- const FunctionProtoType *Proto = R->getAs<FunctionProtoType>();
+ const auto *Proto = R->castAs<FunctionProtoType>();
// Make sure we don't have any parameters.
if (Proto->getNumParams() > 0) {
@@ -9334,22 +10685,37 @@ struct InvalidSTLDiagnoser {
} // namespace
QualType Sema::CheckComparisonCategoryType(ComparisonCategoryType Kind,
- SourceLocation Loc) {
+ SourceLocation Loc,
+ ComparisonCategoryUsage Usage) {
assert(getLangOpts().CPlusPlus &&
"Looking for comparison category type outside of C++.");
+ // Use an elaborated type for diagnostics which has a name containing the
+ // prepended 'std' namespace but not any inline namespace names.
+ auto TyForDiags = [&](ComparisonCategoryInfo *Info) {
+ auto *NNS =
+ NestedNameSpecifier::Create(Context, nullptr, getStdNamespace());
+ return Context.getElaboratedType(ETK_None, NNS, Info->getType());
+ };
+
// Check if we've already successfully checked the comparison category type
// before. If so, skip checking it again.
ComparisonCategoryInfo *Info = Context.CompCategories.lookupInfo(Kind);
- if (Info && FullyCheckedComparisonCategories[static_cast<unsigned>(Kind)])
+ if (Info && FullyCheckedComparisonCategories[static_cast<unsigned>(Kind)]) {
+ // The only thing we need to check is that the type has a reachable
+ // definition in the current context.
+ if (RequireCompleteType(Loc, TyForDiags(Info), diag::err_incomplete_type))
+ return QualType();
+
return Info->getType();
+ }
// If lookup failed
if (!Info) {
std::string NameForDiags = "std::";
NameForDiags += ComparisonCategories::getCategoryString(Kind);
Diag(Loc, diag::err_implied_comparison_category_type_not_found)
- << NameForDiags;
+ << NameForDiags << (int)Usage;
return QualType();
}
@@ -9361,18 +10727,10 @@ QualType Sema::CheckComparisonCategoryType(ComparisonCategoryType Kind,
if (Info->Record->hasDefinition())
Info->Record = Info->Record->getDefinition();
- // Use an elaborated type for diagnostics which has a name containing the
- // prepended 'std' namespace but not any inline namespace names.
- QualType TyForDiags = [&]() {
- auto *NNS =
- NestedNameSpecifier::Create(Context, nullptr, getStdNamespace());
- return Context.getElaboratedType(ETK_None, NNS, Info->getType());
- }();
-
- if (RequireCompleteType(Loc, TyForDiags, diag::err_incomplete_type))
+ if (RequireCompleteType(Loc, TyForDiags(Info), diag::err_incomplete_type))
return QualType();
- InvalidSTLDiagnoser UnsupportedSTLError{*this, Loc, TyForDiags};
+ InvalidSTLDiagnoser UnsupportedSTLError{*this, Loc, TyForDiags(Info)};
if (!Info->Record->isTriviallyCopyable())
return UnsupportedSTLError(USS_NonTrivial);
@@ -11070,25 +12428,6 @@ void SpecialMemberExceptionSpecInfo::visitSubobjectCall(
ExceptSpec.CalledDecl(getSubobjectLoc(Subobj), MD);
}
-namespace {
-/// RAII object to register a special member as being currently declared.
-struct ComputingExceptionSpec {
- Sema &S;
-
- ComputingExceptionSpec(Sema &S, CXXMethodDecl *MD, SourceLocation Loc)
- : S(S) {
- Sema::CodeSynthesisContext Ctx;
- Ctx.Kind = Sema::CodeSynthesisContext::ExceptionSpecEvaluation;
- Ctx.PointOfInstantiation = Loc;
- Ctx.Entity = MD;
- S.pushCodeSynthesisContext(Ctx);
- }
- ~ComputingExceptionSpec() {
- S.popCodeSynthesisContext();
- }
-};
-}
-
bool Sema::tryResolveExplicitSpecifier(ExplicitSpecifier &ExplicitSpec) {
llvm::APSInt Result;
ExprResult Converted = CheckConvertedConstantExpression(
@@ -11222,10 +12561,9 @@ void Sema::setupImplicitSpecialMemberType(CXXMethodDecl *SpecialMem,
// Build an exception specification pointing back at this constructor.
FunctionProtoType::ExtProtoInfo EPI = getImplicitMethodEPI(*this, SpecialMem);
- if (getLangOpts().OpenCLCPlusPlus) {
- // OpenCL: Implicitly defaulted special member are of the generic address
- // space.
- EPI.TypeQuals.addAddressSpace(LangAS::opencl_generic);
+ LangAS AS = getDefaultCXXMethodAddrSpace();
+ if (AS != LangAS::Default) {
+ EPI.TypeQuals.addAddressSpace(AS);
}
auto QT = Context.getFunctionType(ResultTy, Args, EPI);
@@ -11384,7 +12722,8 @@ Sema::findInheritingConstructor(SourceLocation Loc,
BaseCtor->getExplicitSpecifier(), /*isInline=*/true,
/*isImplicitlyDeclared=*/true,
Constexpr ? BaseCtor->getConstexprKind() : CSK_unspecified,
- InheritedConstructor(Shadow, BaseCtor));
+ InheritedConstructor(Shadow, BaseCtor),
+ BaseCtor->getTrailingRequiresClause());
if (Shadow->isInvalidDecl())
DerivedCtor->setInvalidDecl();
@@ -11635,7 +12974,7 @@ void Sema::ActOnFinishCXXMemberDecls() {
}
}
-void Sema::ActOnFinishCXXNonNestedClass(Decl *D) {
+void Sema::ActOnFinishCXXNonNestedClass() {
referenceDLLExportedClassMethods();
if (!DelayedDllExportMemberFunctions.empty()) {
@@ -11676,8 +13015,7 @@ void Sema::AdjustDestructorExceptionSpec(CXXDestructorDecl *Destructor) {
// A declaration of a destructor that does not have an exception-
// specification is implicitly considered to have the same exception-
// specification as an implicit declaration.
- const FunctionProtoType *DtorType = Destructor->getType()->
- getAs<FunctionProtoType>();
+ const auto *DtorType = Destructor->getType()->castAs<FunctionProtoType>();
if (DtorType->hasExceptionSpec())
return;
@@ -12135,8 +13473,9 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
return nullptr;
QualType ArgType = Context.getTypeDeclType(ClassDecl);
- if (Context.getLangOpts().OpenCLCPlusPlus)
- ArgType = Context.getAddrSpaceQualType(ArgType, LangAS::opencl_generic);
+ LangAS AS = getDefaultCXXMethodAddrSpace();
+ if (AS != LangAS::Default)
+ ArgType = Context.getAddrSpaceQualType(ArgType, AS);
QualType RetType = Context.getLValueReferenceType(ArgType);
bool Const = ClassDecl->implicitCopyAssignmentHasConstParam();
if (Const)
@@ -12237,11 +13576,12 @@ static void diagnoseDeprecatedCopyOperation(Sema &S, CXXMethodDecl *CopyOp) {
assert(UserDeclaredOperation);
}
- if (UserDeclaredOperation) {
+ if (UserDeclaredOperation && UserDeclaredOperation->isUserProvided()) {
S.Diag(UserDeclaredOperation->getLocation(),
- diag::warn_deprecated_copy_operation)
- << RD << /*copy assignment*/!isa<CXXConstructorDecl>(CopyOp)
- << /*destructor*/isa<CXXDestructorDecl>(UserDeclaredOperation);
+ isa<CXXDestructorDecl>(UserDeclaredOperation)
+ ? diag::warn_deprecated_copy_dtor_operation
+ : diag::warn_deprecated_copy_operation)
+ << RD << /*copy assignment*/ !isa<CXXConstructorDecl>(CopyOp);
}
}
@@ -12460,8 +13800,9 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) {
// constructor rules.
QualType ArgType = Context.getTypeDeclType(ClassDecl);
- if (Context.getLangOpts().OpenCLCPlusPlus)
- ArgType = Context.getAddrSpaceQualType(ArgType, LangAS::opencl_generic);
+ LangAS AS = getDefaultCXXMethodAddrSpace();
+ if (AS != LangAS::Default)
+ ArgType = Context.getAddrSpaceQualType(ArgType, AS);
QualType RetType = Context.getLValueReferenceType(ArgType);
ArgType = Context.getRValueReferenceType(ArgType);
@@ -12654,8 +13995,8 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
// The parameter for the "other" object, which we are move from.
ParmVarDecl *Other = MoveAssignOperator->getParamDecl(0);
- QualType OtherRefType = Other->getType()->
- getAs<RValueReferenceType>()->getPointeeType();
+ QualType OtherRefType =
+ Other->getType()->castAs<RValueReferenceType>()->getPointeeType();
// Our location for everything implicitly-generated.
SourceLocation Loc = MoveAssignOperator->getEndLoc().isValid()
@@ -12838,8 +14179,9 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
if (Const)
ArgType = ArgType.withConst();
- if (Context.getLangOpts().OpenCLCPlusPlus)
- ArgType = Context.getAddrSpaceQualType(ArgType, LangAS::opencl_generic);
+ LangAS AS = getDefaultCXXMethodAddrSpace();
+ if (AS != LangAS::Default)
+ ArgType = Context.getAddrSpaceQualType(ArgType, AS);
ArgType = Context.getLValueReferenceType(ArgType);
@@ -12970,8 +14312,9 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor(
QualType ClassType = Context.getTypeDeclType(ClassDecl);
QualType ArgType = ClassType;
- if (Context.getLangOpts().OpenCLCPlusPlus)
- ArgType = Context.getAddrSpaceQualType(ClassType, LangAS::opencl_generic);
+ LangAS AS = getDefaultCXXMethodAddrSpace();
+ if (AS != LangAS::Default)
+ ArgType = Context.getAddrSpaceQualType(ClassType, AS);
ArgType = Context.getRValueReferenceType(ArgType);
bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, ClassDecl,
@@ -13447,9 +14790,7 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor,
unsigned NumArgs = ArgsPtr.size();
Expr **Args = ArgsPtr.data();
- const FunctionProtoType *Proto
- = Constructor->getType()->getAs<FunctionProtoType>();
- assert(Proto && "Constructor without a prototype?");
+ const auto *Proto = Constructor->getType()->castAs<FunctionProtoType>();
unsigned NumParams = Proto->getNumParams();
// If too few arguments are available, we'll fill in the rest with defaults.
@@ -13512,7 +14853,7 @@ CheckOperatorNewDeleteTypes(Sema &SemaRef, const FunctionDecl *FnDecl,
unsigned DependentParamTypeDiag,
unsigned InvalidParamTypeDiag) {
QualType ResultType =
- FnDecl->getType()->getAs<FunctionType>()->getReturnType();
+ FnDecl->getType()->castAs<FunctionType>()->getReturnType();
// Check that the result type is not dependent.
if (ResultType->isDependentType())
@@ -13741,7 +15082,7 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
// Overloaded operators other than operator() cannot be variadic.
if (Op != OO_Call &&
- FnDecl->getType()->getAs<FunctionProtoType>()->isVariadic()) {
+ FnDecl->getType()->castAs<FunctionProtoType>()->isVariadic()) {
return Diag(FnDecl->getLocation(), diag::err_operator_overload_variadic)
<< FnDecl->getDeclName();
}
@@ -14010,10 +15351,6 @@ Decl *Sema::ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc,
Language = LinkageSpecDecl::lang_c;
else if (Lang == "C++")
Language = LinkageSpecDecl::lang_cxx;
- else if (Lang == "C++11")
- Language = LinkageSpecDecl::lang_cxx_11;
- else if (Lang == "C++14")
- Language = LinkageSpecDecl::lang_cxx_14;
else {
Diag(LangStr->getExprLoc(), diag::err_language_linkage_spec_unknown)
<< LangStr->getSourceRange();
@@ -14291,8 +15628,16 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc,
std::string InnerCondDescription;
std::tie(InnerCond, InnerCondDescription) =
findFailedBooleanCondition(Converted.get());
- if (InnerCond && !isa<CXXBoolLiteralExpr>(InnerCond)
- && !isa<IntegerLiteral>(InnerCond)) {
+ if (InnerCond && isa<ConceptSpecializationExpr>(InnerCond)) {
+ // Drill down into concept specialization expressions to see why they
+ // weren't satisfied.
+ Diag(StaticAssertLoc, diag::err_static_assert_failed)
+ << !AssertMessage << Msg.str() << AssertExpr->getSourceRange();
+ ConstraintSatisfaction Satisfaction;
+ if (!CheckConstraintSatisfaction(InnerCond, Satisfaction))
+ DiagnoseUnsatisfiedConstraint(Satisfaction);
+ } else if (InnerCond && !isa<CXXBoolLiteralExpr>(InnerCond)
+ && !isa<IntegerLiteral>(InnerCond)) {
Diag(StaticAssertLoc, diag::err_static_assert_requirement_failed)
<< InnerCondDescription << !AssertMessage
<< Msg.str() << InnerCond->getSourceRange();
@@ -14974,6 +16319,16 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) {
if (Fn->isDeleted())
return;
+ // C++11 [basic.start.main]p3:
+ // A program that defines main as deleted [...] is ill-formed.
+ if (Fn->isMain())
+ Diag(DelLoc, diag::err_deleted_main);
+
+ // C++11 [dcl.fct.def.delete]p4:
+ // A deleted function is implicitly inline.
+ Fn->setImplicitlyInline();
+ Fn->setDeletedAsWritten();
+
// See if we're deleting a function which is already known to override a
// non-deleted virtual function.
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Fn)) {
@@ -14990,67 +16345,93 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) {
// If this function was implicitly deleted because it was defaulted,
// explain why it was deleted.
if (IssuedDiagnostic && MD->isDefaulted())
- ShouldDeleteSpecialMember(MD, getSpecialMember(MD), nullptr,
- /*Diagnose*/true);
+ DiagnoseDeletedDefaultedFunction(MD);
}
-
- // C++11 [basic.start.main]p3:
- // A program that defines main as deleted [...] is ill-formed.
- if (Fn->isMain())
- Diag(DelLoc, diag::err_deleted_main);
-
- // C++11 [dcl.fct.def.delete]p4:
- // A deleted function is implicitly inline.
- Fn->setImplicitlyInline();
- Fn->setDeletedAsWritten();
}
void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
- CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(Dcl);
+ if (!Dcl || Dcl->isInvalidDecl())
+ return;
- if (MD) {
- if (MD->getParent()->isDependentType()) {
- MD->setDefaulted();
- MD->setExplicitlyDefaulted();
- return;
+ auto *FD = dyn_cast<FunctionDecl>(Dcl);
+ if (!FD) {
+ if (auto *FTD = dyn_cast<FunctionTemplateDecl>(Dcl)) {
+ if (getDefaultedFunctionKind(FTD->getTemplatedDecl()).isComparison()) {
+ Diag(DefaultLoc, diag::err_defaulted_comparison_template);
+ return;
+ }
}
- CXXSpecialMember Member = getSpecialMember(MD);
- if (Member == CXXInvalid) {
- if (!MD->isInvalidDecl())
- Diag(DefaultLoc, diag::err_default_special_members);
- return;
- }
+ Diag(DefaultLoc, diag::err_default_special_members)
+ << getLangOpts().CPlusPlus2a;
+ return;
+ }
- MD->setDefaulted();
- MD->setExplicitlyDefaulted();
+ // Reject if this can't possibly be a defaultable function.
+ DefaultedFunctionKind DefKind = getDefaultedFunctionKind(FD);
+ if (!DefKind &&
+ // A dependent function that doesn't locally look defaultable can
+ // still instantiate to a defaultable function if it's a constructor
+ // or assignment operator.
+ (!FD->isDependentContext() ||
+ (!isa<CXXConstructorDecl>(FD) &&
+ FD->getDeclName().getCXXOverloadedOperator() != OO_Equal))) {
+ Diag(DefaultLoc, diag::err_default_special_members)
+ << getLangOpts().CPlusPlus2a;
+ return;
+ }
- // Unset that we will have a body for this function. We might not,
- // if it turns out to be trivial, and we don't need this marking now
- // that we've marked it as defaulted.
- MD->setWillHaveBody(false);
+ if (DefKind.isComparison() &&
+ !isa<CXXRecordDecl>(FD->getLexicalDeclContext())) {
+ Diag(FD->getLocation(), diag::err_defaulted_comparison_out_of_class)
+ << (int)DefKind.asComparison();
+ return;
+ }
- // If this definition appears within the record, do the checking when
- // the record is complete.
- const FunctionDecl *Primary = MD;
- if (const FunctionDecl *Pattern = MD->getTemplateInstantiationPattern())
- // Ask the template instantiation pattern that actually had the
- // '= default' on it.
- Primary = Pattern;
+ // Issue compatibility warning. We already warned if the operator is
+ // 'operator<=>' when parsing the '<=>' token.
+ if (DefKind.isComparison() &&
+ DefKind.asComparison() != DefaultedComparisonKind::ThreeWay) {
+ Diag(DefaultLoc, getLangOpts().CPlusPlus2a
+ ? diag::warn_cxx17_compat_defaulted_comparison
+ : diag::ext_defaulted_comparison);
+ }
- // If the method was defaulted on its first declaration, we will have
- // already performed the checking in CheckCompletedCXXClass. Such a
- // declaration doesn't trigger an implicit definition.
- if (Primary->getCanonicalDecl()->isDefaulted())
- return;
+ FD->setDefaulted();
+ FD->setExplicitlyDefaulted();
- CheckExplicitlyDefaultedSpecialMember(MD);
+ // Defer checking functions that are defaulted in a dependent context.
+ if (FD->isDependentContext())
+ return;
- if (!MD->isInvalidDecl())
- DefineImplicitSpecialMember(*this, MD, DefaultLoc);
- } else {
- Diag(DefaultLoc, diag::err_default_special_members);
- }
+ // Unset that we will have a body for this function. We might not,
+ // if it turns out to be trivial, and we don't need this marking now
+ // that we've marked it as defaulted.
+ FD->setWillHaveBody(false);
+
+ // If this definition appears within the record, do the checking when
+ // the record is complete. This is always the case for a defaulted
+ // comparison.
+ if (DefKind.isComparison())
+ return;
+ auto *MD = cast<CXXMethodDecl>(FD);
+
+ const FunctionDecl *Primary = FD;
+ if (const FunctionDecl *Pattern = FD->getTemplateInstantiationPattern())
+ // Ask the template instantiation pattern that actually had the
+ // '= default' on it.
+ Primary = Pattern;
+
+ // If the method was defaulted on its first declaration, we will have
+ // already performed the checking in CheckCompletedCXXClass. Such a
+ // declaration doesn't trigger an implicit definition.
+ if (Primary->getCanonicalDecl()->isDefaulted())
+ return;
+
+ if (CheckExplicitlyDefaultedSpecialMember(MD, DefKind.asSpecialMember()))
+ MD->setInvalidDecl();
+ else
+ DefineImplicitSpecialMember(*this, MD, DefaultLoc);
}
static void SearchForReturnInStmt(Sema &Self, Stmt *S) {
@@ -15074,8 +16455,8 @@ void Sema::DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock) {
bool Sema::CheckOverridingFunctionAttributes(const CXXMethodDecl *New,
const CXXMethodDecl *Old) {
- const auto *NewFT = New->getType()->getAs<FunctionProtoType>();
- const auto *OldFT = Old->getType()->getAs<FunctionProtoType>();
+ const auto *NewFT = New->getType()->castAs<FunctionProtoType>();
+ const auto *OldFT = Old->getType()->castAs<FunctionProtoType>();
if (OldFT->hasExtParameterInfos()) {
for (unsigned I = 0, E = OldFT->getNumParams(); I != E; ++I)
@@ -15122,8 +16503,8 @@ bool Sema::CheckOverridingFunctionAttributes(const CXXMethodDecl *New,
bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
const CXXMethodDecl *Old) {
- QualType NewTy = New->getType()->getAs<FunctionType>()->getReturnType();
- QualType OldTy = Old->getType()->getAs<FunctionType>()->getReturnType();
+ QualType NewTy = New->getType()->castAs<FunctionType>()->getReturnType();
+ QualType OldTy = Old->getType()->castAs<FunctionType>()->getReturnType();
if (Context.hasSameType(NewTy, OldTy) ||
NewTy->isDependentType() || OldTy->isDependentType())
@@ -15729,6 +17110,11 @@ bool Sema::checkThisInStaticMemberFunctionType(CXXMethodDecl *Method) {
if (checkThisInStaticMemberFunctionExceptionSpec(Method))
return true;
+ // Check the trailing requires clause
+ if (Expr *E = Method->getTrailingRequiresClause())
+ if (!Finder.TraverseStmt(E))
+ return true;
+
return checkThisInStaticMemberFunctionAttributes(Method);
}
diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp
index db594bbd21dd..5fdf6aeed5b4 100644
--- a/clang/lib/Sema/SemaDeclObjC.cpp
+++ b/clang/lib/Sema/SemaDeclObjC.cpp
@@ -2828,6 +2828,9 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap,
"Expected to find the method through lookup as well");
// ImpMethodDecl may be null as in a @dynamic property.
if (ImpMethodDecl) {
+ // Skip property accessor function stubs.
+ if (ImpMethodDecl->isSynthesizedAccessorStub())
+ continue;
if (!WarnCategoryMethodImpl)
WarnConflictingTypedMethods(ImpMethodDecl, I,
isa<ObjCProtocolDecl>(CDecl));
@@ -2854,6 +2857,9 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap,
"Expected to find the method through lookup as well");
// ImpMethodDecl may be null as in a @dynamic property.
if (ImpMethodDecl) {
+ // Skip property accessor function stubs.
+ if (ImpMethodDecl->isSynthesizedAccessorStub())
+ continue;
if (!WarnCategoryMethodImpl)
WarnConflictingTypedMethods(ImpMethodDecl, I,
isa<ObjCProtocolDecl>(CDecl));
@@ -3233,6 +3239,9 @@ bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *left,
if (left->isHidden() || right->isHidden())
return false;
+ if (left->isDirectMethod() != right->isDirectMethod())
+ return false;
+
if (getLangOpts().ObjCAutoRefCount &&
(left->hasAttr<NSReturnsRetainedAttr>()
!= right->hasAttr<NSReturnsRetainedAttr>() ||
@@ -3424,6 +3433,9 @@ static bool isAcceptableMethodMismatch(ObjCMethodDecl *chosen,
if (!chosen->isInstanceMethod())
return false;
+ if (chosen->isDirectMethod() != other->isDirectMethod())
+ return false;
+
Selector sel = chosen->getSelector();
if (!sel.isUnarySelector() || sel.getNameForSlot(0) != "length")
return false;
@@ -3903,6 +3915,25 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods,
|| isa<ObjCProtocolDecl>(ClassDecl);
bool checkIdenticalMethods = isa<ObjCImplementationDecl>(ClassDecl);
+ // Make synthesized accessor stub functions visible.
+ // ActOnPropertyImplDecl() creates them as not visible in case
+ // they are overridden by an explicit method that is encountered
+ // later.
+ if (auto *OID = dyn_cast<ObjCImplementationDecl>(CurContext)) {
+ for (auto PropImpl : OID->property_impls()) {
+ if (auto *Getter = PropImpl->getGetterMethodDecl())
+ if (Getter->isSynthesizedAccessorStub()) {
+ OID->makeDeclVisibleInContext(Getter);
+ OID->addDecl(Getter);
+ }
+ if (auto *Setter = PropImpl->getSetterMethodDecl())
+ if (Setter->isSynthesizedAccessorStub()) {
+ OID->makeDeclVisibleInContext(Setter);
+ OID->addDecl(Setter);
+ }
+ }
+ }
+
// FIXME: Remove these and use the ObjCContainerDecl/DeclContext.
llvm::DenseMap<Selector, const ObjCMethodDecl*> InsMap;
llvm::DenseMap<Selector, const ObjCMethodDecl*> ClsMap;
@@ -4001,8 +4032,8 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods,
continue;
for (const auto *Ext : IDecl->visible_extensions()) {
- if (ObjCMethodDecl *GetterMethod
- = Ext->getInstanceMethod(Property->getGetterName()))
+ if (ObjCMethodDecl *GetterMethod =
+ Ext->getInstanceMethod(Property->getGetterName()))
GetterMethod->setPropertyAccessor(true);
if (!Property->isReadOnly())
if (ObjCMethodDecl *SetterMethod
@@ -4314,6 +4345,18 @@ private:
};
} // end anonymous namespace
+void Sema::CheckObjCMethodDirectOverrides(ObjCMethodDecl *method,
+ ObjCMethodDecl *overridden) {
+ if (const auto *attr = overridden->getAttr<ObjCDirectAttr>()) {
+ Diag(method->getLocation(), diag::err_objc_override_direct_method);
+ Diag(attr->getLocation(), diag::note_previous_declaration);
+ } else if (const auto *attr = method->getAttr<ObjCDirectAttr>()) {
+ Diag(attr->getLocation(), diag::err_objc_direct_on_override)
+ << isa<ObjCProtocolDecl>(overridden->getDeclContext());
+ Diag(overridden->getLocation(), diag::note_previous_declaration);
+ }
+}
+
void Sema::CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod,
ObjCInterfaceDecl *CurrentClass,
ResultTypeCompatibilityKind RTC) {
@@ -4332,8 +4375,8 @@ void Sema::CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod,
if (isa<ObjCProtocolDecl>(overridden->getDeclContext()) ||
CurrentClass != overridden->getClassInterface() ||
overridden->isOverriding()) {
+ CheckObjCMethodDirectOverrides(ObjCMethod, overridden);
hasOverriddenMethodsInBaseOrProtocol = true;
-
} else if (isa<ObjCImplDecl>(ObjCMethod->getDeclContext())) {
// OverrideSearch will return as "overridden" the same method in the
// interface. For hasOverriddenMethodsInBaseOrProtocol, we need to
@@ -4357,6 +4400,7 @@ void Sema::CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod,
for (ObjCMethodDecl *SuperOverridden : overrides) {
if (isa<ObjCProtocolDecl>(SuperOverridden->getDeclContext()) ||
CurrentClass != SuperOverridden->getClassInterface()) {
+ CheckObjCMethodDirectOverrides(ObjCMethod, SuperOverridden);
hasOverriddenMethodsInBaseOrProtocol = true;
overridden->setOverriding(true);
break;
@@ -4551,6 +4595,7 @@ Decl *Sema::ActOnMethodDeclaration(
Diag(MethodLoc, diag::err_missing_method_context);
return nullptr;
}
+
Decl *ClassDecl = cast<ObjCContainerDecl>(CurContext);
QualType resultDeclType;
@@ -4574,7 +4619,7 @@ Decl *Sema::ActOnMethodDeclaration(
ObjCMethodDecl *ObjCMethod = ObjCMethodDecl::Create(
Context, MethodLoc, EndLoc, Sel, resultDeclType, ReturnTInfo, CurContext,
MethodType == tok::minus, isVariadic,
- /*isPropertyAccessor=*/false,
+ /*isPropertyAccessor=*/false, /*isSynthesizedAccessorStub=*/false,
/*isImplicitlyDeclared=*/false, /*isDefined=*/false,
MethodDeclKind == tok::objc_optional ? ObjCMethodDecl::Optional
: ObjCMethodDecl::Required,
@@ -4666,6 +4711,41 @@ Decl *Sema::ActOnMethodDeclaration(
ImpDecl->addClassMethod(ObjCMethod);
}
+ // If this method overrides a previous @synthesize declaration,
+ // register it with the property. Linear search through all
+ // properties here, because the autosynthesized stub hasn't been
+ // made visible yet, so it can be overriden by a later
+ // user-specified implementation.
+ for (ObjCPropertyImplDecl *PropertyImpl : ImpDecl->property_impls()) {
+ if (auto *Setter = PropertyImpl->getSetterMethodDecl())
+ if (Setter->getSelector() == Sel &&
+ Setter->isInstanceMethod() == ObjCMethod->isInstanceMethod()) {
+ assert(Setter->isSynthesizedAccessorStub() && "autosynth stub expected");
+ PropertyImpl->setSetterMethodDecl(ObjCMethod);
+ }
+ if (auto *Getter = PropertyImpl->getGetterMethodDecl())
+ if (Getter->getSelector() == Sel &&
+ Getter->isInstanceMethod() == ObjCMethod->isInstanceMethod()) {
+ assert(Getter->isSynthesizedAccessorStub() && "autosynth stub expected");
+ PropertyImpl->setGetterMethodDecl(ObjCMethod);
+ break;
+ }
+ }
+
+ // A method is either tagged direct explicitly, or inherits it from its
+ // canonical declaration.
+ //
+ // We have to do the merge upfront and not in mergeInterfaceMethodToImpl()
+ // because IDecl->lookupMethod() returns more possible matches than just
+ // the canonical declaration.
+ if (!ObjCMethod->isDirectMethod()) {
+ const ObjCMethodDecl *CanonicalMD = ObjCMethod->getCanonicalDecl();
+ if (const auto *attr = CanonicalMD->getAttr<ObjCDirectAttr>()) {
+ ObjCMethod->addAttr(
+ ObjCDirectAttr::CreateImplicit(Context, attr->getLocation()));
+ }
+ }
+
// Merge information from the @interface declaration into the
// @implementation.
if (ObjCInterfaceDecl *IDecl = ImpDecl->getClassInterface()) {
@@ -4673,12 +4753,64 @@ Decl *Sema::ActOnMethodDeclaration(
ObjCMethod->isInstanceMethod())) {
mergeInterfaceMethodToImpl(*this, ObjCMethod, IMD);
+ // The Idecl->lookupMethod() above will find declarations for ObjCMethod
+ // in one of these places:
+ //
+ // (1) the canonical declaration in an @interface container paired
+ // with the ImplDecl,
+ // (2) non canonical declarations in @interface not paired with the
+ // ImplDecl for the same Class,
+ // (3) any superclass container.
+ //
+ // Direct methods only allow for canonical declarations in the matching
+ // container (case 1).
+ //
+ // Direct methods overriding a superclass declaration (case 3) is
+ // handled during overrides checks in CheckObjCMethodOverrides().
+ //
+ // We deal with same-class container mismatches (Case 2) here.
+ if (IDecl == IMD->getClassInterface()) {
+ auto diagContainerMismatch = [&] {
+ int decl = 0, impl = 0;
+
+ if (auto *Cat = dyn_cast<ObjCCategoryDecl>(IMD->getDeclContext()))
+ decl = Cat->IsClassExtension() ? 1 : 2;
+
+ if (isa<ObjCCategoryImplDecl>(ImpDecl))
+ impl = 1 + (decl != 0);
+
+ Diag(ObjCMethod->getLocation(),
+ diag::err_objc_direct_impl_decl_mismatch)
+ << decl << impl;
+ Diag(IMD->getLocation(), diag::note_previous_declaration);
+ };
+
+ if (const auto *attr = ObjCMethod->getAttr<ObjCDirectAttr>()) {
+ if (ObjCMethod->getCanonicalDecl() != IMD) {
+ diagContainerMismatch();
+ } else if (!IMD->isDirectMethod()) {
+ Diag(attr->getLocation(), diag::err_objc_direct_missing_on_decl);
+ Diag(IMD->getLocation(), diag::note_previous_declaration);
+ }
+ } else if (const auto *attr = IMD->getAttr<ObjCDirectAttr>()) {
+ if (ObjCMethod->getCanonicalDecl() != IMD) {
+ diagContainerMismatch();
+ } else {
+ ObjCMethod->addAttr(
+ ObjCDirectAttr::CreateImplicit(Context, attr->getLocation()));
+ }
+ }
+ }
+
// Warn about defining -dealloc in a category.
if (isa<ObjCCategoryImplDecl>(ImpDecl) && IMD->isOverriding() &&
ObjCMethod->getSelector().getMethodFamily() == OMF_dealloc) {
Diag(ObjCMethod->getLocation(), diag::warn_dealloc_in_category)
<< ObjCMethod->getDeclName();
}
+ } else if (ImpDecl->hasAttr<ObjCDirectMembersAttr>()) {
+ ObjCMethod->addAttr(
+ ObjCDirectAttr::CreateImplicit(Context, ObjCMethod->getLocation()));
}
// Warn if a method declared in a protocol to which a category or
@@ -4698,6 +4830,42 @@ Decl *Sema::ActOnMethodDeclaration(
}
}
} else {
+ if (!isa<ObjCProtocolDecl>(ClassDecl)) {
+ if (!ObjCMethod->isDirectMethod() &&
+ ClassDecl->hasAttr<ObjCDirectMembersAttr>()) {
+ ObjCMethod->addAttr(
+ ObjCDirectAttr::CreateImplicit(Context, ObjCMethod->getLocation()));
+ }
+
+ // There can be a single declaration in any @interface container
+ // for a given direct method, look for clashes as we add them.
+ //
+ // For valid code, we should always know the primary interface
+ // declaration by now, however for invalid code we'll keep parsing
+ // but we won't find the primary interface and IDecl will be nil.
+ ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(ClassDecl);
+ if (!IDecl)
+ IDecl = cast<ObjCCategoryDecl>(ClassDecl)->getClassInterface();
+
+ if (IDecl)
+ if (auto *IMD = IDecl->lookupMethod(ObjCMethod->getSelector(),
+ ObjCMethod->isInstanceMethod(),
+ /*shallowCategoryLookup=*/false,
+ /*followSuper=*/false)) {
+ if (isa<ObjCProtocolDecl>(IMD->getDeclContext())) {
+ // Do not emit a diagnostic for the Protocol case:
+ // diag::err_objc_direct_on_protocol has already been emitted
+ // during parsing for these with a nicer diagnostic.
+ } else if (ObjCMethod->isDirectMethod() || IMD->isDirectMethod()) {
+ Diag(ObjCMethod->getLocation(),
+ diag::err_objc_direct_duplicate_decl)
+ << ObjCMethod->isDirectMethod() << IMD->isDirectMethod()
+ << ObjCMethod->getDeclName();
+ Diag(IMD->getLocation(), diag::note_previous_declaration);
+ }
+ }
+ }
+
cast<DeclContext>(ClassDecl)->addDecl(ObjCMethod);
}
@@ -4783,6 +4951,9 @@ Decl *Sema::ActOnMethodDeclaration(
}
}
+ // Insert the invisible arguments, self and _cmd!
+ ObjCMethod->createImplicitParams(Context, ObjCMethod->getClassInterface());
+
ActOnDocumentableDecl(ObjCMethod);
return ObjCMethod;
@@ -5063,6 +5234,9 @@ void Sema::DiagnoseUnusedBackingIvarInAccessor(Scope *S,
if (!IV)
continue;
+ if (CurMethod->isSynthesizedAccessorStub())
+ continue;
+
UnusedBackingIvarChecker Checker(*this, CurMethod, IV);
Checker.TraverseStmt(CurMethod->getBody());
if (Checker.AccessedIvar)
diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
index c1abf099e9f2..5aedbe7644e4 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -15,6 +15,7 @@
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/AST/StmtObjC.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceManager.h"
@@ -80,8 +81,16 @@ ExprResult Sema::ActOnNoexceptSpec(SourceLocation NoexceptLoc,
ExceptionSpecificationType &EST) {
// FIXME: This is bogus, a noexcept expression is not a condition.
ExprResult Converted = CheckBooleanCondition(NoexceptLoc, NoexceptExpr);
- if (Converted.isInvalid())
- return Converted;
+ if (Converted.isInvalid()) {
+ EST = EST_NoexceptFalse;
+
+ // Fill in an expression of 'false' as a fixup.
+ auto *BoolExpr = new (Context)
+ CXXBoolLiteralExpr(false, Context.BoolTy, NoexceptExpr->getBeginLoc());
+ llvm::APSInt Value{1};
+ Value = 0;
+ return ConstantExpr::Create(Context, BoolExpr, APValue{Value});
+ }
if (Converted.get()->isValueDependent()) {
EST = EST_DependentNoexcept;
@@ -204,7 +213,7 @@ Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) {
// Compute or instantiate the exception specification now.
if (SourceFPT->getExceptionSpecType() == EST_Unevaluated)
- EvaluateImplicitExceptionSpec(Loc, cast<CXXMethodDecl>(SourceDecl));
+ EvaluateImplicitExceptionSpec(Loc, SourceDecl);
else
InstantiateExceptionSpec(Loc, SourceDecl);
@@ -970,17 +979,22 @@ bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
New->getLocation());
}
-static CanThrowResult canSubExprsThrow(Sema &S, const Expr *E) {
+static CanThrowResult canSubStmtsThrow(Sema &Self, const Stmt *S) {
CanThrowResult R = CT_Cannot;
- for (const Stmt *SubStmt : E->children()) {
- R = mergeCanThrow(R, S.canThrow(cast<Expr>(SubStmt)));
+ for (const Stmt *SubStmt : S->children()) {
+ if (!SubStmt)
+ continue;
+ R = mergeCanThrow(R, Self.canThrow(SubStmt));
if (R == CT_Can)
break;
}
return R;
}
-static CanThrowResult canCalleeThrow(Sema &S, const Expr *E, const Decl *D) {
+/// Determine whether the callee of a particular function call can throw.
+/// E and D are both optional, but at least one of E and Loc must be specified.
+static CanThrowResult canCalleeThrow(Sema &S, const Expr *E, const Decl *D,
+ SourceLocation Loc = SourceLocation()) {
// As an extension, we assume that __attribute__((nothrow)) functions don't
// throw.
if (D && isa<FunctionDecl>(D) && D->hasAttr<NoThrowAttr>())
@@ -989,7 +1003,7 @@ static CanThrowResult canCalleeThrow(Sema &S, const Expr *E, const Decl *D) {
QualType T;
// In C++1z, just look at the function type of the callee.
- if (S.getLangOpts().CPlusPlus17 && isa<CallExpr>(E)) {
+ if (S.getLangOpts().CPlusPlus17 && E && isa<CallExpr>(E)) {
E = cast<CallExpr>(E)->getCallee();
T = E->getType();
if (T->isSpecificPlaceholderType(BuiltinType::BoundMember)) {
@@ -1026,13 +1040,41 @@ static CanThrowResult canCalleeThrow(Sema &S, const Expr *E, const Decl *D) {
if (!FT)
return CT_Can;
- FT = S.ResolveExceptionSpec(E->getBeginLoc(), FT);
+ FT = S.ResolveExceptionSpec(Loc.isInvalid() ? E->getBeginLoc() : Loc, FT);
if (!FT)
return CT_Can;
return FT->canThrow();
}
+static CanThrowResult canVarDeclThrow(Sema &Self, const VarDecl *VD) {
+ CanThrowResult CT = CT_Cannot;
+
+ // Initialization might throw.
+ if (!VD->isUsableInConstantExpressions(Self.Context))
+ if (const Expr *Init = VD->getInit())
+ CT = mergeCanThrow(CT, Self.canThrow(Init));
+
+ // Destructor might throw.
+ if (VD->needsDestruction(Self.Context) == QualType::DK_cxx_destructor) {
+ if (auto *RD =
+ VD->getType()->getBaseElementTypeUnsafe()->getAsCXXRecordDecl()) {
+ if (auto *Dtor = RD->getDestructor()) {
+ CT = mergeCanThrow(
+ CT, canCalleeThrow(Self, nullptr, Dtor, VD->getLocation()));
+ }
+ }
+ }
+
+ // If this is a decomposition declaration, bindings might throw.
+ if (auto *DD = dyn_cast<DecompositionDecl>(VD))
+ for (auto *B : DD->bindings())
+ if (auto *HD = B->getHoldingVar())
+ CT = mergeCanThrow(CT, canVarDeclThrow(Self, HD));
+
+ return CT;
+}
+
static CanThrowResult canDynamicCastThrow(const CXXDynamicCastExpr *DC) {
if (DC->isTypeDependent())
return CT_Dependent;
@@ -1067,13 +1109,13 @@ static CanThrowResult canTypeidThrow(Sema &S, const CXXTypeidExpr *DC) {
return CT_Can;
}
-CanThrowResult Sema::canThrow(const Expr *E) {
+CanThrowResult Sema::canThrow(const Stmt *S) {
// C++ [expr.unary.noexcept]p3:
// [Can throw] if in a potentially-evaluated context the expression would
// contain:
- switch (E->getStmtClass()) {
+ switch (S->getStmtClass()) {
case Expr::ConstantExprClass:
- return canThrow(cast<ConstantExpr>(E)->getSubExpr());
+ return canThrow(cast<ConstantExpr>(S)->getSubExpr());
case Expr::CXXThrowExprClass:
// - a potentially evaluated throw-expression
@@ -1082,16 +1124,20 @@ CanThrowResult Sema::canThrow(const Expr *E) {
case Expr::CXXDynamicCastExprClass: {
// - a potentially evaluated dynamic_cast expression dynamic_cast<T>(v),
// where T is a reference type, that requires a run-time check
- CanThrowResult CT = canDynamicCastThrow(cast<CXXDynamicCastExpr>(E));
+ auto *CE = cast<CXXDynamicCastExpr>(S);
+ // FIXME: Properly determine whether a variably-modified type can throw.
+ if (CE->getType()->isVariablyModifiedType())
+ return CT_Can;
+ CanThrowResult CT = canDynamicCastThrow(CE);
if (CT == CT_Can)
return CT;
- return mergeCanThrow(CT, canSubExprsThrow(*this, E));
+ return mergeCanThrow(CT, canSubStmtsThrow(*this, CE));
}
case Expr::CXXTypeidExprClass:
// - a potentially evaluated typeid expression applied to a glvalue
// expression whose type is a polymorphic class type
- return canTypeidThrow(*this, cast<CXXTypeidExpr>(E));
+ return canTypeidThrow(*this, cast<CXXTypeidExpr>(S));
// - a potentially evaluated call to a function, member function, function
// pointer, or member function pointer that does not have a non-throwing
@@ -1100,34 +1146,38 @@ CanThrowResult Sema::canThrow(const Expr *E) {
case Expr::CXXMemberCallExprClass:
case Expr::CXXOperatorCallExprClass:
case Expr::UserDefinedLiteralClass: {
- const CallExpr *CE = cast<CallExpr>(E);
+ const CallExpr *CE = cast<CallExpr>(S);
CanThrowResult CT;
- if (E->isTypeDependent())
+ if (CE->isTypeDependent())
CT = CT_Dependent;
else if (isa<CXXPseudoDestructorExpr>(CE->getCallee()->IgnoreParens()))
CT = CT_Cannot;
else
- CT = canCalleeThrow(*this, E, CE->getCalleeDecl());
+ CT = canCalleeThrow(*this, CE, CE->getCalleeDecl());
if (CT == CT_Can)
return CT;
- return mergeCanThrow(CT, canSubExprsThrow(*this, E));
+ return mergeCanThrow(CT, canSubStmtsThrow(*this, CE));
}
case Expr::CXXConstructExprClass:
case Expr::CXXTemporaryObjectExprClass: {
- CanThrowResult CT = canCalleeThrow(*this, E,
- cast<CXXConstructExpr>(E)->getConstructor());
+ auto *CE = cast<CXXConstructExpr>(S);
+ // FIXME: Properly determine whether a variably-modified type can throw.
+ if (CE->getType()->isVariablyModifiedType())
+ return CT_Can;
+ CanThrowResult CT = canCalleeThrow(*this, CE, CE->getConstructor());
if (CT == CT_Can)
return CT;
- return mergeCanThrow(CT, canSubExprsThrow(*this, E));
+ return mergeCanThrow(CT, canSubStmtsThrow(*this, CE));
}
- case Expr::CXXInheritedCtorInitExprClass:
- return canCalleeThrow(*this, E,
- cast<CXXInheritedCtorInitExpr>(E)->getConstructor());
+ case Expr::CXXInheritedCtorInitExprClass: {
+ auto *ICIE = cast<CXXInheritedCtorInitExpr>(S);
+ return canCalleeThrow(*this, ICIE, ICIE->getConstructor());
+ }
case Expr::LambdaExprClass: {
- const LambdaExpr *Lambda = cast<LambdaExpr>(E);
+ const LambdaExpr *Lambda = cast<LambdaExpr>(S);
CanThrowResult CT = CT_Cannot;
for (LambdaExpr::const_capture_init_iterator
Cap = Lambda->capture_init_begin(),
@@ -1138,43 +1188,56 @@ CanThrowResult Sema::canThrow(const Expr *E) {
}
case Expr::CXXNewExprClass: {
+ auto *NE = cast<CXXNewExpr>(S);
CanThrowResult CT;
- if (E->isTypeDependent())
+ if (NE->isTypeDependent())
CT = CT_Dependent;
else
- CT = canCalleeThrow(*this, E, cast<CXXNewExpr>(E)->getOperatorNew());
+ CT = canCalleeThrow(*this, NE, NE->getOperatorNew());
if (CT == CT_Can)
return CT;
- return mergeCanThrow(CT, canSubExprsThrow(*this, E));
+ return mergeCanThrow(CT, canSubStmtsThrow(*this, NE));
}
case Expr::CXXDeleteExprClass: {
+ auto *DE = cast<CXXDeleteExpr>(S);
CanThrowResult CT;
- QualType DTy = cast<CXXDeleteExpr>(E)->getDestroyedType();
+ QualType DTy = DE->getDestroyedType();
if (DTy.isNull() || DTy->isDependentType()) {
CT = CT_Dependent;
} else {
- CT = canCalleeThrow(*this, E,
- cast<CXXDeleteExpr>(E)->getOperatorDelete());
+ CT = canCalleeThrow(*this, DE, DE->getOperatorDelete());
if (const RecordType *RT = DTy->getAs<RecordType>()) {
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
const CXXDestructorDecl *DD = RD->getDestructor();
if (DD)
- CT = mergeCanThrow(CT, canCalleeThrow(*this, E, DD));
+ CT = mergeCanThrow(CT, canCalleeThrow(*this, DE, DD));
}
if (CT == CT_Can)
return CT;
}
- return mergeCanThrow(CT, canSubExprsThrow(*this, E));
+ return mergeCanThrow(CT, canSubStmtsThrow(*this, DE));
}
case Expr::CXXBindTemporaryExprClass: {
+ auto *BTE = cast<CXXBindTemporaryExpr>(S);
// The bound temporary has to be destroyed again, which might throw.
- CanThrowResult CT = canCalleeThrow(*this, E,
- cast<CXXBindTemporaryExpr>(E)->getTemporary()->getDestructor());
+ CanThrowResult CT =
+ canCalleeThrow(*this, BTE, BTE->getTemporary()->getDestructor());
if (CT == CT_Can)
return CT;
- return mergeCanThrow(CT, canSubExprsThrow(*this, E));
+ return mergeCanThrow(CT, canSubStmtsThrow(*this, BTE));
+ }
+
+ case Expr::PseudoObjectExprClass: {
+ auto *POE = cast<PseudoObjectExpr>(S);
+ CanThrowResult CT = CT_Cannot;
+ for (const Expr *E : POE->semantics()) {
+ CT = mergeCanThrow(CT, canThrow(E));
+ if (CT == CT_Can)
+ break;
+ }
+ return CT;
}
// ObjC message sends are like function calls, but never have exception
@@ -1196,12 +1259,8 @@ CanThrowResult Sema::canThrow(const Expr *E) {
// Some are simple:
case Expr::CoawaitExprClass:
case Expr::ConditionalOperatorClass:
- case Expr::CompoundLiteralExprClass:
case Expr::CoyieldExprClass:
- case Expr::CXXConstCastExprClass:
- case Expr::CXXReinterpretCastExprClass:
case Expr::CXXRewrittenBinaryOperatorClass:
- case Expr::BuiltinBitCastExprClass:
case Expr::CXXStdInitializerListExprClass:
case Expr::DesignatedInitExprClass:
case Expr::DesignatedInitUpdateExprClass:
@@ -1215,9 +1274,19 @@ CanThrowResult Sema::canThrow(const Expr *E) {
case Expr::ParenExprClass:
case Expr::ParenListExprClass:
case Expr::ShuffleVectorExprClass:
+ case Expr::StmtExprClass:
case Expr::ConvertVectorExprClass:
case Expr::VAArgExprClass:
- return canSubExprsThrow(*this, E);
+ return canSubStmtsThrow(*this, S);
+
+ case Expr::CompoundLiteralExprClass:
+ case Expr::CXXConstCastExprClass:
+ case Expr::CXXReinterpretCastExprClass:
+ case Expr::BuiltinBitCastExprClass:
+ // FIXME: Properly determine whether a variably-modified type can throw.
+ if (cast<Expr>(S)->getType()->isVariablyModifiedType())
+ return CT_Can;
+ return canSubStmtsThrow(*this, S);
// Some might be dependent for other reasons.
case Expr::ArraySubscriptExprClass:
@@ -1231,29 +1300,32 @@ CanThrowResult Sema::canThrow(const Expr *E) {
case Expr::ImplicitCastExprClass:
case Expr::MaterializeTemporaryExprClass:
case Expr::UnaryOperatorClass: {
- CanThrowResult CT = E->isTypeDependent() ? CT_Dependent : CT_Cannot;
- return mergeCanThrow(CT, canSubExprsThrow(*this, E));
+ // FIXME: Properly determine whether a variably-modified type can throw.
+ if (auto *CE = dyn_cast<CastExpr>(S))
+ if (CE->getType()->isVariablyModifiedType())
+ return CT_Can;
+ CanThrowResult CT =
+ cast<Expr>(S)->isTypeDependent() ? CT_Dependent : CT_Cannot;
+ return mergeCanThrow(CT, canSubStmtsThrow(*this, S));
}
- // FIXME: We should handle StmtExpr, but that opens a MASSIVE can of worms.
- case Expr::StmtExprClass:
- return CT_Can;
-
case Expr::CXXDefaultArgExprClass:
- return canThrow(cast<CXXDefaultArgExpr>(E)->getExpr());
+ return canThrow(cast<CXXDefaultArgExpr>(S)->getExpr());
case Expr::CXXDefaultInitExprClass:
- return canThrow(cast<CXXDefaultInitExpr>(E)->getExpr());
+ return canThrow(cast<CXXDefaultInitExpr>(S)->getExpr());
- case Expr::ChooseExprClass:
- if (E->isTypeDependent() || E->isValueDependent())
+ case Expr::ChooseExprClass: {
+ auto *CE = cast<ChooseExpr>(S);
+ if (CE->isTypeDependent() || CE->isValueDependent())
return CT_Dependent;
- return canThrow(cast<ChooseExpr>(E)->getChosenSubExpr());
+ return canThrow(CE->getChosenSubExpr());
+ }
case Expr::GenericSelectionExprClass:
- if (cast<GenericSelectionExpr>(E)->isResultDependent())
+ if (cast<GenericSelectionExpr>(S)->isResultDependent())
return CT_Dependent;
- return canThrow(cast<GenericSelectionExpr>(E)->getResultExpr());
+ return canThrow(cast<GenericSelectionExpr>(S)->getResultExpr());
// Some expressions are always dependent.
case Expr::CXXDependentScopeMemberExprClass:
@@ -1274,7 +1346,6 @@ CanThrowResult Sema::canThrow(const Expr *E) {
case Expr::ObjCAvailabilityCheckExprClass:
case Expr::OffsetOfExprClass:
case Expr::PackExpansionExprClass:
- case Expr::PseudoObjectExprClass:
case Expr::SubstNonTypeTemplateParmExprClass:
case Expr::SubstNonTypeTemplateParmPackExprClass:
case Expr::FunctionParmPackExprClass:
@@ -1282,7 +1353,7 @@ CanThrowResult Sema::canThrow(const Expr *E) {
case Expr::UnresolvedLookupExprClass:
case Expr::UnresolvedMemberExprClass:
case Expr::TypoExprClass:
- // FIXME: Can any of the above throw? If so, when?
+ // FIXME: Many of the above can throw.
return CT_Cannot;
case Expr::AddrLabelExprClass:
@@ -1322,14 +1393,170 @@ CanThrowResult Sema::canThrow(const Expr *E) {
case Expr::MSPropertySubscriptExprClass:
llvm_unreachable("Invalid class for expression");
-#define STMT(CLASS, PARENT) case Expr::CLASS##Class:
-#define STMT_RANGE(Base, First, Last)
-#define LAST_STMT_RANGE(BASE, FIRST, LAST)
-#define EXPR(CLASS, PARENT)
-#define ABSTRACT_STMT(STMT)
-#include "clang/AST/StmtNodes.inc"
- case Expr::NoStmtClass:
- llvm_unreachable("Invalid class for expression");
+ // Most statements can throw if any substatement can throw.
+ case Stmt::AttributedStmtClass:
+ case Stmt::BreakStmtClass:
+ case Stmt::CapturedStmtClass:
+ case Stmt::CaseStmtClass:
+ case Stmt::CompoundStmtClass:
+ case Stmt::ContinueStmtClass:
+ case Stmt::CoreturnStmtClass:
+ case Stmt::CoroutineBodyStmtClass:
+ case Stmt::CXXCatchStmtClass:
+ case Stmt::CXXForRangeStmtClass:
+ case Stmt::DefaultStmtClass:
+ case Stmt::DoStmtClass:
+ case Stmt::ForStmtClass:
+ case Stmt::GCCAsmStmtClass:
+ case Stmt::GotoStmtClass:
+ case Stmt::IndirectGotoStmtClass:
+ case Stmt::LabelStmtClass:
+ case Stmt::MSAsmStmtClass:
+ case Stmt::MSDependentExistsStmtClass:
+ case Stmt::NullStmtClass:
+ case Stmt::ObjCAtCatchStmtClass:
+ case Stmt::ObjCAtFinallyStmtClass:
+ case Stmt::ObjCAtSynchronizedStmtClass:
+ case Stmt::ObjCAutoreleasePoolStmtClass:
+ case Stmt::ObjCForCollectionStmtClass:
+ case Stmt::OMPAtomicDirectiveClass:
+ case Stmt::OMPBarrierDirectiveClass:
+ case Stmt::OMPCancelDirectiveClass:
+ case Stmt::OMPCancellationPointDirectiveClass:
+ case Stmt::OMPCriticalDirectiveClass:
+ case Stmt::OMPDistributeDirectiveClass:
+ case Stmt::OMPDistributeParallelForDirectiveClass:
+ case Stmt::OMPDistributeParallelForSimdDirectiveClass:
+ case Stmt::OMPDistributeSimdDirectiveClass:
+ case Stmt::OMPFlushDirectiveClass:
+ case Stmt::OMPForDirectiveClass:
+ case Stmt::OMPForSimdDirectiveClass:
+ case Stmt::OMPMasterDirectiveClass:
+ case Stmt::OMPMasterTaskLoopDirectiveClass:
+ case Stmt::OMPMasterTaskLoopSimdDirectiveClass:
+ case Stmt::OMPOrderedDirectiveClass:
+ case Stmt::OMPParallelDirectiveClass:
+ case Stmt::OMPParallelForDirectiveClass:
+ case Stmt::OMPParallelForSimdDirectiveClass:
+ case Stmt::OMPParallelMasterDirectiveClass:
+ case Stmt::OMPParallelMasterTaskLoopDirectiveClass:
+ case Stmt::OMPParallelMasterTaskLoopSimdDirectiveClass:
+ case Stmt::OMPParallelSectionsDirectiveClass:
+ case Stmt::OMPSectionDirectiveClass:
+ case Stmt::OMPSectionsDirectiveClass:
+ case Stmt::OMPSimdDirectiveClass:
+ case Stmt::OMPSingleDirectiveClass:
+ case Stmt::OMPTargetDataDirectiveClass:
+ case Stmt::OMPTargetDirectiveClass:
+ case Stmt::OMPTargetEnterDataDirectiveClass:
+ case Stmt::OMPTargetExitDataDirectiveClass:
+ case Stmt::OMPTargetParallelDirectiveClass:
+ case Stmt::OMPTargetParallelForDirectiveClass:
+ case Stmt::OMPTargetParallelForSimdDirectiveClass:
+ case Stmt::OMPTargetSimdDirectiveClass:
+ case Stmt::OMPTargetTeamsDirectiveClass:
+ case Stmt::OMPTargetTeamsDistributeDirectiveClass:
+ case Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass:
+ case Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass:
+ case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass:
+ case Stmt::OMPTargetUpdateDirectiveClass:
+ case Stmt::OMPTaskDirectiveClass:
+ case Stmt::OMPTaskgroupDirectiveClass:
+ case Stmt::OMPTaskLoopDirectiveClass:
+ case Stmt::OMPTaskLoopSimdDirectiveClass:
+ case Stmt::OMPTaskwaitDirectiveClass:
+ case Stmt::OMPTaskyieldDirectiveClass:
+ case Stmt::OMPTeamsDirectiveClass:
+ case Stmt::OMPTeamsDistributeDirectiveClass:
+ case Stmt::OMPTeamsDistributeParallelForDirectiveClass:
+ case Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass:
+ case Stmt::OMPTeamsDistributeSimdDirectiveClass:
+ case Stmt::ReturnStmtClass:
+ case Stmt::SEHExceptStmtClass:
+ case Stmt::SEHFinallyStmtClass:
+ case Stmt::SEHLeaveStmtClass:
+ case Stmt::SEHTryStmtClass:
+ case Stmt::SwitchStmtClass:
+ case Stmt::WhileStmtClass:
+ return canSubStmtsThrow(*this, S);
+
+ case Stmt::DeclStmtClass: {
+ CanThrowResult CT = CT_Cannot;
+ for (const Decl *D : cast<DeclStmt>(S)->decls()) {
+ if (auto *VD = dyn_cast<VarDecl>(D))
+ CT = mergeCanThrow(CT, canVarDeclThrow(*this, VD));
+
+ // FIXME: Properly determine whether a variably-modified type can throw.
+ if (auto *TND = dyn_cast<TypedefNameDecl>(D))
+ if (TND->getUnderlyingType()->isVariablyModifiedType())
+ return CT_Can;
+ if (auto *VD = dyn_cast<ValueDecl>(D))
+ if (VD->getType()->isVariablyModifiedType())
+ return CT_Can;
+ }
+ return CT;
+ }
+
+ case Stmt::IfStmtClass: {
+ auto *IS = cast<IfStmt>(S);
+ CanThrowResult CT = CT_Cannot;
+ if (const Stmt *Init = IS->getInit())
+ CT = mergeCanThrow(CT, canThrow(Init));
+ if (const Stmt *CondDS = IS->getConditionVariableDeclStmt())
+ CT = mergeCanThrow(CT, canThrow(CondDS));
+ CT = mergeCanThrow(CT, canThrow(IS->getCond()));
+
+ // For 'if constexpr', consider only the non-discarded case.
+ // FIXME: We should add a DiscardedStmt marker to the AST.
+ if (Optional<const Stmt *> Case = IS->getNondiscardedCase(Context))
+ return *Case ? mergeCanThrow(CT, canThrow(*Case)) : CT;
+
+ CanThrowResult Then = canThrow(IS->getThen());
+ CanThrowResult Else = IS->getElse() ? canThrow(IS->getElse()) : CT_Cannot;
+ if (Then == Else)
+ return mergeCanThrow(CT, Then);
+
+ // For a dependent 'if constexpr', the result is dependent if it depends on
+ // the value of the condition.
+ return mergeCanThrow(CT, IS->isConstexpr() ? CT_Dependent
+ : mergeCanThrow(Then, Else));
+ }
+
+ case Stmt::CXXTryStmtClass: {
+ auto *TS = cast<CXXTryStmt>(S);
+ // try /*...*/ catch (...) { H } can throw only if H can throw.
+ // Any other try-catch can throw if any substatement can throw.
+ const CXXCatchStmt *FinalHandler = TS->getHandler(TS->getNumHandlers() - 1);
+ if (!FinalHandler->getExceptionDecl())
+ return canThrow(FinalHandler->getHandlerBlock());
+ return canSubStmtsThrow(*this, S);
+ }
+
+ case Stmt::ObjCAtThrowStmtClass:
+ return CT_Can;
+
+ case Stmt::ObjCAtTryStmtClass: {
+ auto *TS = cast<ObjCAtTryStmt>(S);
+
+ // @catch(...) need not be last in Objective-C. Walk backwards until we
+ // see one or hit the @try.
+ CanThrowResult CT = CT_Cannot;
+ if (const Stmt *Finally = TS->getFinallyStmt())
+ CT = mergeCanThrow(CT, canThrow(Finally));
+ for (unsigned I = TS->getNumCatchStmts(); I != 0; --I) {
+ const ObjCAtCatchStmt *Catch = TS->getCatchStmt(I - 1);
+ CT = mergeCanThrow(CT, canThrow(Catch));
+ // If we reach a @catch(...), no earlier exceptions can escape.
+ if (Catch->hasEllipsis())
+ return CT;
+ }
+
+ // Didn't find an @catch(...). Exceptions from the @try body can escape.
+ return mergeCanThrow(CT, canThrow(TS->getTryBody()));
+ }
+
+ case Stmt::NoStmtClass:
+ llvm_unreachable("Invalid class for statement");
}
llvm_unreachable("Bogus StmtClass");
}
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index e41cd5b6653a..5f4071924d3f 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -25,6 +25,7 @@
#include "clang/AST/ExprOpenMP.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/TypeLoc.h"
+#include "clang/Basic/Builtins.h"
#include "clang/Basic/FixedPoint.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/SourceManager.h"
@@ -97,21 +98,16 @@ static void DiagnoseUnusedOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc) {
/// Emit a note explaining that this function is deleted.
void Sema::NoteDeletedFunction(FunctionDecl *Decl) {
- assert(Decl->isDeleted());
+ assert(Decl && Decl->isDeleted());
- CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Decl);
-
- if (Method && Method->isDeleted() && Method->isDefaulted()) {
+ if (Decl->isDefaulted()) {
// If the method was explicitly defaulted, point at that declaration.
- if (!Method->isImplicit())
+ if (!Decl->isImplicit())
Diag(Decl->getLocation(), diag::note_implicitly_deleted);
// Try to diagnose why this special member function was implicitly
// deleted. This might fail, if that reason no longer applies.
- CXXSpecialMember CSM = getSpecialMember(Method);
- if (CSM != CXXInvalid)
- ShouldDeleteSpecialMember(Method, CSM, nullptr, /*Diagnose=*/true);
-
+ DiagnoseDeletedDefaultedFunction(Decl);
return;
}
@@ -330,6 +326,30 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
diagnoseUseOfInternalDeclInInlineFunction(*this, D, Loc);
+ // [expr.prim.id]p4
+ // A program that refers explicitly or implicitly to a function with a
+ // trailing requires-clause whose constraint-expression is not satisfied,
+ // other than to declare it, is ill-formed. [...]
+ //
+ // See if this is a function with constraints that need to be satisfied.
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ if (Expr *RC = FD->getTrailingRequiresClause()) {
+ ConstraintSatisfaction Satisfaction;
+ bool Failed = CheckConstraintSatisfaction(RC, Satisfaction);
+ if (Failed)
+ // A diagnostic will have already been generated (non-constant
+ // constraint expression, for example)
+ return true;
+ if (!Satisfaction.IsSatisfied) {
+ Diag(Loc,
+ diag::err_reference_to_function_with_unsatisfied_constraints)
+ << D;
+ DiagnoseUnsatisfiedConstraint(Satisfaction);
+ return true;
+ }
+ }
+ }
+
return false;
}
@@ -481,16 +501,22 @@ static void CheckForNullPointerDereference(Sema &S, Expr *E) {
// optimizer will delete, so warn about it. People sometimes try to use this
// to get a deterministic trap and are surprised by clang's behavior. This
// only handles the pattern "*null", which is a very syntactic check.
- if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E->IgnoreParenCasts()))
- if (UO->getOpcode() == UO_Deref &&
- UO->getSubExpr()->IgnoreParenCasts()->
- isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull) &&
+ const auto *UO = dyn_cast<UnaryOperator>(E->IgnoreParenCasts());
+ if (UO && UO->getOpcode() == UO_Deref &&
+ UO->getSubExpr()->getType()->isPointerType()) {
+ const LangAS AS =
+ UO->getSubExpr()->getType()->getPointeeType().getAddressSpace();
+ if ((!isTargetAddressSpace(AS) ||
+ (isTargetAddressSpace(AS) && toTargetAddressSpace(AS) == 0)) &&
+ UO->getSubExpr()->IgnoreParenCasts()->isNullPointerConstant(
+ S.Context, Expr::NPC_ValueDependentIsNotNull) &&
!UO->getType().isVolatileQualified()) {
- S.DiagRuntimeBehavior(UO->getOperatorLoc(), UO,
- S.PDiag(diag::warn_indirection_through_null)
- << UO->getSubExpr()->getSourceRange());
- S.DiagRuntimeBehavior(UO->getOperatorLoc(), UO,
- S.PDiag(diag::note_indirection_through_null));
+ S.DiagRuntimeBehavior(UO->getOperatorLoc(), UO,
+ S.PDiag(diag::warn_indirection_through_null)
+ << UO->getSubExpr()->getSourceRange());
+ S.DiagRuntimeBehavior(UO->getOperatorLoc(), UO,
+ S.PDiag(diag::note_indirection_through_null));
+ }
}
}
@@ -1331,13 +1357,72 @@ static QualType handleFixedPointConversion(Sema &S, QualType LHSTy,
return ResultTy;
}
+/// Check that the usual arithmetic conversions can be performed on this pair of
+/// expressions that might be of enumeration type.
+static void checkEnumArithmeticConversions(Sema &S, Expr *LHS, Expr *RHS,
+ SourceLocation Loc,
+ Sema::ArithConvKind ACK) {
+ // C++2a [expr.arith.conv]p1:
+ // If one operand is of enumeration type and the other operand is of a
+ // different enumeration type or a floating-point type, this behavior is
+ // deprecated ([depr.arith.conv.enum]).
+ //
+ // Warn on this in all language modes. Produce a deprecation warning in C++20.
+ // Eventually we will presumably reject these cases (in C++23 onwards?).
+ QualType L = LHS->getType(), R = RHS->getType();
+ bool LEnum = L->isUnscopedEnumerationType(),
+ REnum = R->isUnscopedEnumerationType();
+ bool IsCompAssign = ACK == Sema::ACK_CompAssign;
+ if ((!IsCompAssign && LEnum && R->isFloatingType()) ||
+ (REnum && L->isFloatingType())) {
+ S.Diag(Loc, S.getLangOpts().CPlusPlus2a
+ ? diag::warn_arith_conv_enum_float_cxx2a
+ : diag::warn_arith_conv_enum_float)
+ << LHS->getSourceRange() << RHS->getSourceRange()
+ << (int)ACK << LEnum << L << R;
+ } else if (!IsCompAssign && LEnum && REnum &&
+ !S.Context.hasSameUnqualifiedType(L, R)) {
+ unsigned DiagID;
+ if (!L->castAs<EnumType>()->getDecl()->hasNameForLinkage() ||
+ !R->castAs<EnumType>()->getDecl()->hasNameForLinkage()) {
+ // If either enumeration type is unnamed, it's less likely that the
+ // user cares about this, but this situation is still deprecated in
+ // C++2a. Use a different warning group.
+ DiagID = S.getLangOpts().CPlusPlus2a
+ ? diag::warn_arith_conv_mixed_anon_enum_types_cxx2a
+ : diag::warn_arith_conv_mixed_anon_enum_types;
+ } else if (ACK == Sema::ACK_Conditional) {
+ // Conditional expressions are separated out because they have
+ // historically had a different warning flag.
+ DiagID = S.getLangOpts().CPlusPlus2a
+ ? diag::warn_conditional_mixed_enum_types_cxx2a
+ : diag::warn_conditional_mixed_enum_types;
+ } else if (ACK == Sema::ACK_Comparison) {
+ // Comparison expressions are separated out because they have
+ // historically had a different warning flag.
+ DiagID = S.getLangOpts().CPlusPlus2a
+ ? diag::warn_comparison_mixed_enum_types_cxx2a
+ : diag::warn_comparison_mixed_enum_types;
+ } else {
+ DiagID = S.getLangOpts().CPlusPlus2a
+ ? diag::warn_arith_conv_mixed_enum_types_cxx2a
+ : diag::warn_arith_conv_mixed_enum_types;
+ }
+ S.Diag(Loc, DiagID) << LHS->getSourceRange() << RHS->getSourceRange()
+ << (int)ACK << L << R;
+ }
+}
+
/// UsualArithmeticConversions - Performs various conversions that are common to
/// binary operators (C99 6.3.1.8). If both operands aren't arithmetic, this
/// routine returns the first non-arithmetic type found. The client is
/// responsible for emitting appropriate error diagnostics.
QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS,
- bool IsCompAssign) {
- if (!IsCompAssign) {
+ SourceLocation Loc,
+ ArithConvKind ACK) {
+ checkEnumArithmeticConversions(*this, LHS.get(), RHS.get(), Loc, ACK);
+
+ if (ACK != ACK_CompAssign) {
LHS = UsualUnaryConversions(LHS.get());
if (LHS.isInvalid())
return QualType();
@@ -1374,7 +1459,7 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS,
QualType LHSBitfieldPromoteTy = Context.isPromotableBitField(LHS.get());
if (!LHSBitfieldPromoteTy.isNull())
LHSType = LHSBitfieldPromoteTy;
- if (LHSType != LHSUnpromotedType && !IsCompAssign)
+ if (LHSType != LHSUnpromotedType && ACK != ACK_CompAssign)
LHS = ImpCastExprToType(LHS.get(), LHSType, CK_IntegralCast);
// If both types are identical, no conversion is needed.
@@ -1391,24 +1476,24 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS,
// Handle complex types first (C99 6.3.1.8p1).
if (LHSType->isComplexType() || RHSType->isComplexType())
return handleComplexFloatConversion(*this, LHS, RHS, LHSType, RHSType,
- IsCompAssign);
+ ACK == ACK_CompAssign);
// Now handle "real" floating types (i.e. float, double, long double).
if (LHSType->isRealFloatingType() || RHSType->isRealFloatingType())
return handleFloatConversion(*this, LHS, RHS, LHSType, RHSType,
- IsCompAssign);
+ ACK == ACK_CompAssign);
// Handle GCC complex int extension.
if (LHSType->isComplexIntegerType() || RHSType->isComplexIntegerType())
return handleComplexIntConversion(*this, LHS, RHS, LHSType, RHSType,
- IsCompAssign);
+ ACK == ACK_CompAssign);
if (LHSType->isFixedPointType() || RHSType->isFixedPointType())
return handleFixedPointConversion(*this, LHSType, RHSType);
// Finally, we have two differing integer types.
return handleIntegerConversion<doIntegralCast, doIntegralCast>
- (*this, LHS, RHS, LHSType, RHSType, IsCompAssign);
+ (*this, LHS, RHS, LHSType, RHSType, ACK == ACK_CompAssign);
}
//===----------------------------------------------------------------------===//
@@ -1825,6 +1910,25 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
VK, FoundD, TemplateArgs, getNonOdrUseReasonInCurrentContext(D));
MarkDeclRefReferenced(E);
+ // C++ [except.spec]p17:
+ // An exception-specification is considered to be needed when:
+ // - in an expression, the function is the unique lookup result or
+ // the selected member of a set of overloaded functions.
+ //
+ // We delay doing this until after we've built the function reference and
+ // marked it as used so that:
+ // a) if the function is defaulted, we get errors from defining it before /
+ // instead of errors from computing its exception specification, and
+ // b) if the function is a defaulted comparison, we can use the body we
+ // build when defining it as input to the exception specification
+ // computation rather than computing a new body.
+ if (auto *FPT = Ty->getAs<FunctionProtoType>()) {
+ if (isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) {
+ if (auto *NewFPT = ResolveExceptionSpec(NameInfo.getLoc(), FPT))
+ E->setType(Context.getQualifiedType(NewFPT, Ty.getQualifiers()));
+ }
+ }
+
if (getLangOpts().ObjCWeak && isa<VarDecl>(D) &&
Ty.getObjCLifetime() == Qualifiers::OCL_Weak && !isUnevaluatedContext() &&
!Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, E->getBeginLoc()))
@@ -2704,6 +2808,20 @@ Sema::PerformObjectMemberConversion(Expr *From,
FromRecordType = FromType;
DestType = DestRecordType;
}
+
+ LangAS FromAS = FromRecordType.getAddressSpace();
+ LangAS DestAS = DestRecordType.getAddressSpace();
+ if (FromAS != DestAS) {
+ QualType FromRecordTypeWithoutAS =
+ Context.removeAddrSpaceQualType(FromRecordType);
+ QualType FromTypeWithDestAS =
+ Context.getAddrSpaceQualType(FromRecordTypeWithoutAS, DestAS);
+ if (PointerConversions)
+ FromTypeWithDestAS = Context.getPointerType(FromTypeWithDestAS);
+ From = ImpCastExprToType(From, FromTypeWithDestAS,
+ CK_AddressSpaceConversion, From->getValueKind())
+ .get();
+ }
} else {
// No conversion necessary.
return From;
@@ -2993,14 +3111,6 @@ ExprResult Sema::BuildDeclarationNameExpr(
QualType type = VD->getType();
if (type.isNull())
return ExprError();
- if (auto *FPT = type->getAs<FunctionProtoType>()) {
- // C++ [except.spec]p17:
- // An exception-specification is considered to be needed when:
- // - in an expression, the function is the unique lookup result or
- // the selected member of a set of overloaded functions.
- ResolveExceptionSpec(Loc, FPT);
- type = VD->getType();
- }
ExprValueKind valueKind = VK_RValue;
switch (D->getKind()) {
@@ -5231,6 +5341,9 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, FunctionDecl *FDecl,
for (Expr *A : Args.slice(ArgIx)) {
ExprResult Arg = DefaultVariadicArgumentPromotion(A, CallType, FDecl);
Invalid |= Arg.isInvalid();
+ // Copy blocks to the heap.
+ if (A->getType()->isBlockPointerType())
+ maybeExtendBlockObject(Arg);
AllArgs.push_back(Arg.get());
}
}
@@ -5424,15 +5537,15 @@ static FunctionDecl *rewriteBuiltinFunctionDecl(Sema *Sema, ASTContext &Context,
Expr *Arg = ArgRes.get();
QualType ArgType = Arg->getType();
if (!ParamType->isPointerType() ||
- ParamType.getQualifiers().hasAddressSpace() ||
+ ParamType.hasAddressSpace() ||
!ArgType->isPointerType() ||
- !ArgType->getPointeeType().getQualifiers().hasAddressSpace()) {
+ !ArgType->getPointeeType().hasAddressSpace()) {
OverloadParams.push_back(ParamType);
continue;
}
QualType PointeeType = ParamType->getPointeeType();
- if (PointeeType.getQualifiers().hasAddressSpace())
+ if (PointeeType.hasAddressSpace())
continue;
NeedsNewDecl = true;
@@ -7363,7 +7476,8 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
/*AllowBothBool*/true,
/*AllowBoolConversions*/false);
- QualType ResTy = UsualArithmeticConversions(LHS, RHS);
+ QualType ResTy =
+ UsualArithmeticConversions(LHS, RHS, QuestionLoc, ACK_Conditional);
if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
@@ -7639,7 +7753,7 @@ static bool IsArithmeticBinaryExpr(Expr *E, BinaryOperatorKind *Opcode,
E = E->IgnoreConversionOperator();
E = E->IgnoreImpCasts();
if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E)) {
- E = MTE->GetTemporaryExpr();
+ E = MTE->getSubExpr();
E = E->IgnoreImpCasts();
}
@@ -8695,7 +8809,7 @@ namespace {
struct OriginalOperand {
explicit OriginalOperand(Expr *Op) : Orig(Op), Conversion(nullptr) {
if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(Op))
- Op = MTE->GetTemporaryExpr();
+ Op = MTE->getSubExpr();
if (auto *BTE = dyn_cast<CXXBindTemporaryExpr>(Op))
Op = BTE->getSubExpr();
if (auto *ICE = dyn_cast<ImplicitCastExpr>(Op)) {
@@ -8957,6 +9071,12 @@ static bool tryGCCVectorConvertAndSplat(Sema &S, ExprResult *Scalar,
return true;
ScalarCast = CK_IntegralCast;
+ } else if (VectorEltTy->isIntegralType(S.Context) &&
+ ScalarTy->isRealFloatingType()) {
+ if (S.Context.getTypeSize(VectorEltTy) == S.Context.getTypeSize(ScalarTy))
+ ScalarCast = CK_FloatingToIntegral;
+ else
+ return true;
} else if (VectorEltTy->isRealFloatingType()) {
if (ScalarTy->isRealFloatingType()) {
@@ -9276,7 +9396,8 @@ QualType Sema::CheckMultiplyDivideOperands(ExprResult &LHS, ExprResult &RHS,
/*AllowBothBool*/getLangOpts().AltiVec,
/*AllowBoolConversions*/false);
- QualType compType = UsualArithmeticConversions(LHS, RHS, IsCompAssign);
+ QualType compType = UsualArithmeticConversions(
+ LHS, RHS, Loc, IsCompAssign ? ACK_CompAssign : ACK_Arithmetic);
if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
@@ -9304,7 +9425,8 @@ QualType Sema::CheckRemainderOperands(
return InvalidOperands(Loc, LHS, RHS);
}
- QualType compType = UsualArithmeticConversions(LHS, RHS, IsCompAssign);
+ QualType compType = UsualArithmeticConversions(
+ LHS, RHS, Loc, IsCompAssign ? ACK_CompAssign : ACK_Arithmetic);
if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
@@ -9593,7 +9715,8 @@ QualType Sema::CheckAdditionOperands(ExprResult &LHS, ExprResult &RHS,
return compType;
}
- QualType compType = UsualArithmeticConversions(LHS, RHS, CompLHSTy);
+ QualType compType = UsualArithmeticConversions(
+ LHS, RHS, Loc, CompLHSTy ? ACK_CompAssign : ACK_Arithmetic);
if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
@@ -9687,7 +9810,8 @@ QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS,
return compType;
}
- QualType compType = UsualArithmeticConversions(LHS, RHS, CompLHSTy);
+ QualType compType = UsualArithmeticConversions(
+ LHS, RHS, Loc, CompLHSTy ? ACK_CompAssign : ACK_Arithmetic);
if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
@@ -10018,35 +10142,6 @@ QualType Sema::CheckShiftOperands(ExprResult &LHS, ExprResult &RHS,
return LHSType;
}
-/// If two different enums are compared, raise a warning.
-static void checkEnumComparison(Sema &S, SourceLocation Loc, Expr *LHS,
- Expr *RHS) {
- QualType LHSStrippedType = LHS->IgnoreParenImpCasts()->getType();
- QualType RHSStrippedType = RHS->IgnoreParenImpCasts()->getType();
-
- const EnumType *LHSEnumType = LHSStrippedType->getAs<EnumType>();
- if (!LHSEnumType)
- return;
- const EnumType *RHSEnumType = RHSStrippedType->getAs<EnumType>();
- if (!RHSEnumType)
- return;
-
- // Ignore anonymous enums.
- if (!LHSEnumType->getDecl()->getIdentifier() &&
- !LHSEnumType->getDecl()->getTypedefNameForAnonDecl())
- return;
- if (!RHSEnumType->getDecl()->getIdentifier() &&
- !RHSEnumType->getDecl()->getTypedefNameForAnonDecl())
- return;
-
- if (S.Context.hasSameUnqualifiedType(LHSStrippedType, RHSStrippedType))
- return;
-
- S.Diag(Loc, diag::warn_comparison_of_mixed_enum_types)
- << LHSStrippedType << RHSStrippedType
- << LHS->getSourceRange() << RHS->getSourceRange();
-}
-
/// Diagnose bad pointer comparisons.
static void diagnoseDistinctPointerComparison(Sema &S, SourceLocation Loc,
ExprResult &LHS, ExprResult &RHS,
@@ -10085,8 +10180,6 @@ static bool convertPointersToCompositeType(Sema &S, SourceLocation Loc,
return true;
}
- LHS = S.ImpCastExprToType(LHS.get(), T, CK_BitCast);
- RHS = S.ImpCastExprToType(RHS.get(), T, CK_BitCast);
return false;
}
@@ -10317,7 +10410,6 @@ static void diagnoseTautologicalComparison(Sema &S, SourceLocation Loc,
QualType RHSType = RHS->getType();
if (LHSType->hasFloatingRepresentation() ||
(LHSType->isBlockPointerType() && !BinaryOperator::isEqualityOp(Opc)) ||
- LHS->getBeginLoc().isMacroID() || RHS->getBeginLoc().isMacroID() ||
S.inTemplateInstantiation())
return;
@@ -10345,45 +10437,64 @@ static void diagnoseTautologicalComparison(Sema &S, SourceLocation Loc,
AlwaysEqual, // std::strong_ordering::equal from operator<=>
};
- if (Expr::isSameComparisonOperand(LHS, RHS)) {
- unsigned Result;
- switch (Opc) {
- case BO_EQ: case BO_LE: case BO_GE:
- Result = AlwaysTrue;
- break;
- case BO_NE: case BO_LT: case BO_GT:
- Result = AlwaysFalse;
- break;
- case BO_Cmp:
- Result = AlwaysEqual;
- break;
- default:
- Result = AlwaysConstant;
- break;
- }
- S.DiagRuntimeBehavior(Loc, nullptr,
- S.PDiag(diag::warn_comparison_always)
- << 0 /*self-comparison*/
- << Result);
- } else if (checkForArray(LHSStripped) && checkForArray(RHSStripped)) {
- // What is it always going to evaluate to?
- unsigned Result;
- switch(Opc) {
- case BO_EQ: // e.g. array1 == array2
- Result = AlwaysFalse;
- break;
- case BO_NE: // e.g. array1 != array2
- Result = AlwaysTrue;
- break;
- default: // e.g. array1 <= array2
- // The best we can say is 'a constant'
- Result = AlwaysConstant;
- break;
+ // C++2a [depr.array.comp]:
+ // Equality and relational comparisons ([expr.eq], [expr.rel]) between two
+ // operands of array type are deprecated.
+ if (S.getLangOpts().CPlusPlus2a && LHSStripped->getType()->isArrayType() &&
+ RHSStripped->getType()->isArrayType()) {
+ S.Diag(Loc, diag::warn_depr_array_comparison)
+ << LHS->getSourceRange() << RHS->getSourceRange()
+ << LHSStripped->getType() << RHSStripped->getType();
+ // Carry on to produce the tautological comparison warning, if this
+ // expression is potentially-evaluated, we can resolve the array to a
+ // non-weak declaration, and so on.
+ }
+
+ if (!LHS->getBeginLoc().isMacroID() && !RHS->getBeginLoc().isMacroID()) {
+ if (Expr::isSameComparisonOperand(LHS, RHS)) {
+ unsigned Result;
+ switch (Opc) {
+ case BO_EQ:
+ case BO_LE:
+ case BO_GE:
+ Result = AlwaysTrue;
+ break;
+ case BO_NE:
+ case BO_LT:
+ case BO_GT:
+ Result = AlwaysFalse;
+ break;
+ case BO_Cmp:
+ Result = AlwaysEqual;
+ break;
+ default:
+ Result = AlwaysConstant;
+ break;
+ }
+ S.DiagRuntimeBehavior(Loc, nullptr,
+ S.PDiag(diag::warn_comparison_always)
+ << 0 /*self-comparison*/
+ << Result);
+ } else if (checkForArray(LHSStripped) && checkForArray(RHSStripped)) {
+ // What is it always going to evaluate to?
+ unsigned Result;
+ switch (Opc) {
+ case BO_EQ: // e.g. array1 == array2
+ Result = AlwaysFalse;
+ break;
+ case BO_NE: // e.g. array1 != array2
+ Result = AlwaysTrue;
+ break;
+ default: // e.g. array1 <= array2
+ // The best we can say is 'a constant'
+ Result = AlwaysConstant;
+ break;
+ }
+ S.DiagRuntimeBehavior(Loc, nullptr,
+ S.PDiag(diag::warn_comparison_always)
+ << 1 /*array comparison*/
+ << Result);
}
- S.DiagRuntimeBehavior(Loc, nullptr,
- S.PDiag(diag::warn_comparison_always)
- << 1 /*array comparison*/
- << Result);
}
if (isa<CastExpr>(LHSStripped))
@@ -10392,7 +10503,7 @@ static void diagnoseTautologicalComparison(Sema &S, SourceLocation Loc,
RHSStripped = RHSStripped->IgnoreParenCasts();
// Warn about comparisons against a string constant (unless the other
- // operand is null); the user probably wants strcmp.
+ // operand is null); the user probably wants string comparison function.
Expr *LiteralString = nullptr;
Expr *LiteralStringStripped = nullptr;
if ((isa<StringLiteral>(LHSStripped) || isa<ObjCEncodeExpr>(LHSStripped)) &&
@@ -10500,8 +10611,6 @@ static QualType checkArithmeticOrEnumeralThreeWayCompare(Sema &S,
ExprResult &LHS,
ExprResult &RHS,
SourceLocation Loc) {
- using CCT = ComparisonCategoryType;
-
QualType LHSType = LHS.get()->getType();
QualType RHSType = RHS.get()->getType();
// Dig out the original argument type and expression before implicit casts
@@ -10519,6 +10628,7 @@ static QualType checkArithmeticOrEnumeralThreeWayCompare(Sema &S,
return QualType();
}
+ // FIXME: Consider combining this with checkEnumArithmeticConversions.
int NumEnumArgs = (int)LHSStrippedType->isEnumeralType() +
RHSStrippedType->isEnumeralType();
if (NumEnumArgs == 1) {
@@ -10554,12 +10664,17 @@ static QualType checkArithmeticOrEnumeralThreeWayCompare(Sema &S,
// C++2a [expr.spaceship]p4: If both operands have arithmetic types, the
// usual arithmetic conversions are applied to the operands.
- QualType Type = S.UsualArithmeticConversions(LHS, RHS);
+ QualType Type =
+ S.UsualArithmeticConversions(LHS, RHS, Loc, Sema::ACK_Comparison);
if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
if (Type.isNull())
return S.InvalidOperands(Loc, LHS, RHS);
- assert(Type->isArithmeticType() || Type->isEnumeralType());
+
+ Optional<ComparisonCategoryType> CCT =
+ getComparisonCategoryForBuiltinCmp(Type);
+ if (!CCT)
+ return S.InvalidOperands(Loc, LHS, RHS);
bool HasNarrowing = checkThreeWayNarrowingConversion(
S, Type, LHS.get(), LHSType, LHS.get()->getBeginLoc());
@@ -10570,20 +10685,8 @@ static QualType checkArithmeticOrEnumeralThreeWayCompare(Sema &S,
assert(!Type.isNull() && "composite type for <=> has not been set");
- auto TypeKind = [&]() {
- if (const ComplexType *CT = Type->getAs<ComplexType>()) {
- if (CT->getElementType()->hasFloatingRepresentation())
- return CCT::WeakEquality;
- return CCT::StrongEquality;
- }
- if (Type->isIntegralOrEnumerationType())
- return CCT::StrongOrdering;
- if (Type->hasFloatingRepresentation())
- return CCT::PartialOrdering;
- llvm_unreachable("other types are unimplemented");
- }();
-
- return S.CheckComparisonCategoryType(TypeKind, Loc);
+ return S.CheckComparisonCategoryType(
+ *CCT, Loc, Sema::ComparisonCategoryUsage::OperatorInExpression);
}
static QualType checkArithmeticOrEnumeralCompare(Sema &S, ExprResult &LHS,
@@ -10594,15 +10697,14 @@ static QualType checkArithmeticOrEnumeralCompare(Sema &S, ExprResult &LHS,
return checkArithmeticOrEnumeralThreeWayCompare(S, LHS, RHS, Loc);
// C99 6.5.8p3 / C99 6.5.9p4
- QualType Type = S.UsualArithmeticConversions(LHS, RHS);
+ QualType Type =
+ S.UsualArithmeticConversions(LHS, RHS, Loc, Sema::ACK_Comparison);
if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
if (Type.isNull())
return S.InvalidOperands(Loc, LHS, RHS);
assert(Type->isArithmeticType() || Type->isEnumeralType());
- checkEnumComparison(S, Loc, LHS.get(), RHS.get());
-
if (Type->isAnyComplexType() && BinaryOperator::isRelationalOp(Opc))
return S.InvalidOperands(Loc, LHS, RHS);
@@ -10646,6 +10748,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
BinaryOperatorKind Opc) {
bool IsRelational = BinaryOperator::isRelationalOp(Opc);
bool IsThreeWay = Opc == BO_Cmp;
+ bool IsOrdered = IsRelational || IsThreeWay;
auto IsAnyPointerType = [](ExprResult E) {
QualType Ty = E.get()->getType();
return Ty->isPointerType() || Ty->isMemberPointerType();
@@ -10708,36 +10811,26 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
QualType CompositeTy = LHS.get()->getType();
assert(!CompositeTy->isReferenceType());
- auto buildResultTy = [&](ComparisonCategoryType Kind) {
- return CheckComparisonCategoryType(Kind, Loc);
- };
-
- // C++2a [expr.spaceship]p7: If the composite pointer type is a function
- // pointer type, a pointer-to-member type, or std::nullptr_t, the
- // result is of type std::strong_equality
- if (CompositeTy->isFunctionPointerType() ||
- CompositeTy->isMemberPointerType() || CompositeTy->isNullPtrType())
- // FIXME: consider making the function pointer case produce
- // strong_ordering not strong_equality, per P0946R0-Jax18 discussion
- // and direction polls
- return buildResultTy(ComparisonCategoryType::StrongEquality);
-
- // C++2a [expr.spaceship]p8: If the composite pointer type is an object
- // pointer type, p <=> q is of type std::strong_ordering.
- if (CompositeTy->isPointerType()) {
+ Optional<ComparisonCategoryType> CCT =
+ getComparisonCategoryForBuiltinCmp(CompositeTy);
+ if (!CCT)
+ return InvalidOperands(Loc, LHS, RHS);
+
+ if (CompositeTy->isPointerType() && LHSIsNull != RHSIsNull) {
// P0946R0: Comparisons between a null pointer constant and an object
- // pointer result in std::strong_equality
- if (LHSIsNull != RHSIsNull)
- return buildResultTy(ComparisonCategoryType::StrongEquality);
- return buildResultTy(ComparisonCategoryType::StrongOrdering);
+ // pointer result in std::strong_equality, which is ill-formed under
+ // P1959R0.
+ Diag(Loc, diag::err_typecheck_three_way_comparison_of_pointer_and_zero)
+ << (LHSIsNull ? LHS.get()->getSourceRange()
+ : RHS.get()->getSourceRange());
+ return QualType();
}
- // C++2a [expr.spaceship]p9: Otherwise, the program is ill-formed.
- // TODO: Extend support for operator<=> to ObjC types.
- return InvalidOperands(Loc, LHS, RHS);
- };
+ return CheckComparisonCategoryType(
+ *CCT, Loc, ComparisonCategoryUsage::OperatorInExpression);
+ };
- if (!IsRelational && LHSIsNull != RHSIsNull) {
+ if (!IsOrdered && LHSIsNull != RHSIsNull) {
bool IsEquality = Opc == BO_EQ;
if (RHSIsNull)
DiagnoseAlwaysNonNullPointer(LHS.get(), RHSNullKind, IsEquality,
@@ -10756,7 +10849,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
// but we allow it as an extension.
// FIXME: If we really want to allow this, should it be part of composite
// pointer type computation so it works in conditionals too?
- if (!IsRelational &&
+ if (!IsOrdered &&
((LHSType->isFunctionPointerType() && RHSType->isVoidPointerType()) ||
(RHSType->isFunctionPointerType() && LHSType->isVoidPointerType()))) {
// This is a gcc extension compatibility comparison.
@@ -10781,8 +10874,11 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
// C++ [expr.rel]p2:
// If both operands are pointers, [...] bring them to their composite
// pointer type.
+ // For <=>, the only valid non-pointer types are arrays and functions, and
+ // we already decayed those, so this is really the same as the relational
+ // comparison rule.
if ((int)LHSType->isPointerType() + (int)RHSType->isPointerType() >=
- (IsRelational ? 2 : 1) &&
+ (IsOrdered ? 2 : 1) &&
(!LangOpts.ObjCAutoRefCount || !(LHSType->isObjCObjectPointerType() ||
RHSType->isObjCObjectPointerType()))) {
if (convertPointersToCompositeType(*this, Loc, LHS, RHS))
@@ -10845,7 +10941,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
// C++ [expr.eq]p4:
// Two operands of type std::nullptr_t or one operand of type
// std::nullptr_t and the other a null pointer constant compare equal.
- if (!IsRelational && LHSIsNull && RHSIsNull) {
+ if (!IsOrdered && LHSIsNull && RHSIsNull) {
if (LHSType->isNullPtrType()) {
RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer);
return computeResultTy();
@@ -10858,12 +10954,12 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
// Comparison of Objective-C pointers and block pointers against nullptr_t.
// These aren't covered by the composite pointer type rules.
- if (!IsRelational && RHSType->isNullPtrType() &&
+ if (!IsOrdered && RHSType->isNullPtrType() &&
(LHSType->isObjCObjectPointerType() || LHSType->isBlockPointerType())) {
RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer);
return computeResultTy();
}
- if (!IsRelational && LHSType->isNullPtrType() &&
+ if (!IsOrdered && LHSType->isNullPtrType() &&
(RHSType->isObjCObjectPointerType() || RHSType->isBlockPointerType())) {
LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer);
return computeResultTy();
@@ -10897,7 +10993,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
// C++ [expr.eq]p2:
// If at least one operand is a pointer to member, [...] bring them to
// their composite pointer type.
- if (!IsRelational &&
+ if (!IsOrdered &&
(LHSType->isMemberPointerType() || RHSType->isMemberPointerType())) {
if (convertPointersToCompositeType(*this, Loc, LHS, RHS))
return QualType();
@@ -10907,7 +11003,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
}
// Handle block pointer types.
- if (!IsRelational && LHSType->isBlockPointerType() &&
+ if (!IsOrdered && LHSType->isBlockPointerType() &&
RHSType->isBlockPointerType()) {
QualType lpointee = LHSType->castAs<BlockPointerType>()->getPointeeType();
QualType rpointee = RHSType->castAs<BlockPointerType>()->getPointeeType();
@@ -10923,7 +11019,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
}
// Allow block pointers to be compared with null pointer constants.
- if (!IsRelational
+ if (!IsOrdered
&& ((LHSType->isBlockPointerType() && RHSType->isPointerType())
|| (LHSType->isPointerType() && RHSType->isBlockPointerType()))) {
if (!LHSIsNull && !RHSIsNull) {
@@ -10959,6 +11055,9 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
diagnoseDistinctPointerComparison(*this, Loc, LHS, RHS,
/*isError*/false);
}
+ // FIXME: If LPtrToVoid, we should presumably convert the LHS rather than
+ // the RHS, but we have test coverage for this behavior.
+ // FIXME: Consider using convertPointersToCompositeType in C++.
if (LHSIsNull && !RHSIsNull) {
Expr *E = LHS.get();
if (getLangOpts().ObjCAutoRefCount)
@@ -10993,12 +11092,12 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
return computeResultTy();
}
- if (!IsRelational && LHSType->isBlockPointerType() &&
+ if (!IsOrdered && LHSType->isBlockPointerType() &&
RHSType->isBlockCompatibleObjCPointerType(Context)) {
LHS = ImpCastExprToType(LHS.get(), RHSType,
CK_BlockPointerToObjCPointerCast);
return computeResultTy();
- } else if (!IsRelational &&
+ } else if (!IsOrdered &&
LHSType->isBlockCompatibleObjCPointerType(Context) &&
RHSType->isBlockPointerType()) {
RHS = ImpCastExprToType(RHS.get(), LHSType,
@@ -11015,7 +11114,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
// since users tend to want to compare addresses.
} else if ((LHSIsNull && LHSType->isIntegerType()) ||
(RHSIsNull && RHSType->isIntegerType())) {
- if (IsRelational) {
+ if (IsOrdered) {
isError = getLangOpts().CPlusPlus;
DiagID =
isError ? diag::err_typecheck_ordered_comparison_of_pointer_and_zero
@@ -11024,7 +11123,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
} else if (getLangOpts().CPlusPlus) {
DiagID = diag::err_typecheck_comparison_of_pointer_integer;
isError = true;
- } else if (IsRelational)
+ } else if (IsOrdered)
DiagID = diag::ext_typecheck_ordered_comparison_of_pointer_integer;
else
DiagID = diag::ext_typecheck_comparison_of_pointer_integer;
@@ -11047,12 +11146,12 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
}
// Handle block pointers.
- if (!IsRelational && RHSIsNull
+ if (!IsOrdered && RHSIsNull
&& LHSType->isBlockPointerType() && RHSType->isIntegerType()) {
RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer);
return computeResultTy();
}
- if (!IsRelational && LHSIsNull
+ if (!IsOrdered && LHSIsNull
&& LHSType->isIntegerType() && RHSType->isBlockPointerType()) {
LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer);
return computeResultTy();
@@ -11129,6 +11228,11 @@ QualType Sema::GetSignedVectorType(QualType V) {
QualType Sema::CheckVectorCompareOperands(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 = CheckVectorOperands(LHS, RHS, Loc, /*isCompAssign*/false,
@@ -11318,9 +11422,13 @@ inline QualType Sema::CheckBitwiseOperands(ExprResult &LHS, ExprResult &RHS,
if (Opc == BO_And)
diagnoseLogicalNotOnLHSofCheck(*this, LHS, RHS, Loc, Opc);
+ if (LHS.get()->getType()->hasFloatingRepresentation() ||
+ RHS.get()->getType()->hasFloatingRepresentation())
+ return InvalidOperands(Loc, LHS, RHS);
+
ExprResult LHSResult = LHS, RHSResult = RHS;
- QualType compType = UsualArithmeticConversions(LHSResult, RHSResult,
- IsCompAssign);
+ QualType compType = UsualArithmeticConversions(
+ LHSResult, RHSResult, Loc, IsCompAssign ? ACK_CompAssign : ACK_BitwiseOp);
if (LHSResult.isInvalid() || RHSResult.isInvalid())
return QualType();
LHS = LHSResult.get();
@@ -13011,6 +13119,14 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
if (ResultTy.isNull() || LHS.isInvalid() || RHS.isInvalid())
return ExprError();
+ if (ResultTy->isRealFloatingType() &&
+ (getLangOpts().getFPRoundingMode() != LangOptions::FPR_ToNearest ||
+ getLangOpts().getFPExceptionMode() != LangOptions::FPE_Ignore))
+ // Mark the current function as usng floating point constrained intrinsics
+ if (FunctionDecl *F = dyn_cast<FunctionDecl>(CurContext)) {
+ F->setUsesFPIntrin(true);
+ }
+
// Some of the binary operations require promoting operands of half vector to
// float vectors and truncating the result back to half vector. For now, we do
// this only when HalfArgsAndReturn is set (that is, when the target is arm or
@@ -15268,8 +15384,7 @@ static bool funcHasParameterSizeMangling(Sema &S, FunctionDecl *FD) {
// These manglings don't do anything on non-Windows or non-x86 platforms, so
// we don't need parameter type sizes.
const llvm::Triple &TT = S.Context.getTargetInfo().getTriple();
- if (!TT.isOSWindows() || (TT.getArch() != llvm::Triple::x86 &&
- TT.getArch() != llvm::Triple::x86_64))
+ if (!TT.isOSWindows() || !TT.isX86())
return false;
// If this is C++ and this isn't an extern "C" function, parameters do not
@@ -15385,9 +15500,8 @@ static OdrUseContext isOdrUseContext(Sema &SemaRef) {
}
static bool isImplicitlyDefinableConstexprFunction(FunctionDecl *Func) {
- CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Func);
return Func->isConstexpr() &&
- (Func->isImplicitlyInstantiable() || (MD && !MD->isUserProvided()));
+ (Func->isImplicitlyInstantiable() || !Func->isUserProvided());
}
/// Mark a function referenced, and check whether it is odr-used
@@ -15467,19 +15581,6 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
Func->getMemberSpecializationInfo()))
checkSpecializationVisibility(Loc, Func);
- // C++14 [except.spec]p17:
- // An exception-specification is considered to be needed when:
- // - the function is odr-used or, if it appears in an unevaluated operand,
- // would be odr-used if the expression were potentially-evaluated;
- //
- // Note, we do this even if MightBeOdrUse is false. That indicates that the
- // function is a pure virtual function we're calling, and in that case the
- // function was selected by overload resolution and we need to resolve its
- // exception specification for a different reason.
- const FunctionProtoType *FPT = Func->getType()->getAs<FunctionProtoType>();
- if (FPT && isUnresolvedExceptionSpec(FPT->getExceptionSpecType()))
- ResolveExceptionSpec(Loc, FPT);
-
if (getLangOpts().CUDA)
CheckCUDACall(Loc, Func);
@@ -15535,6 +15636,12 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
MarkVTableUsed(Loc, MethodDecl->getParent());
}
+ if (Func->isDefaulted() && !Func->isDeleted()) {
+ DefaultedComparisonKind DCK = getDefaultedComparisonKind(Func);
+ if (DCK != DefaultedComparisonKind::None)
+ DefineDefaultedComparison(Loc, Func, DCK);
+ }
+
// Implicit instantiation of function templates and member functions of
// class templates.
if (Func->isImplicitlyInstantiable()) {
@@ -15582,6 +15689,19 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
});
}
+ // C++14 [except.spec]p17:
+ // An exception-specification is considered to be needed when:
+ // - the function is odr-used or, if it appears in an unevaluated operand,
+ // would be odr-used if the expression were potentially-evaluated;
+ //
+ // Note, we do this even if MightBeOdrUse is false. That indicates that the
+ // function is a pure virtual function we're calling, and in that case the
+ // function was selected by overload resolution and we need to resolve its
+ // exception specification for a different reason.
+ const FunctionProtoType *FPT = Func->getType()->getAs<FunctionProtoType>();
+ if (FPT && isUnresolvedExceptionSpec(FPT->getExceptionSpecType()))
+ ResolveExceptionSpec(Loc, FPT);
+
// If this is the first "real" use, act on that.
if (OdrUse == OdrUseContext::Used && !Func->isUsed(/*CheckUsedAttr=*/false)) {
// Keep track of used but undefined functions.
@@ -17880,7 +18000,7 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
// No guarantees that ResolveAndFixSingleFunctionTemplateSpecialization
// leaves Result unchanged on failure.
Result = E;
- if (resolveAndFixAddressOfOnlyViableOverloadCandidate(Result))
+ if (resolveAndFixAddressOfSingleOverloadCandidate(Result))
return Result;
// If that failed, try to recover with a call.
@@ -18017,3 +18137,8 @@ ExprResult Sema::ActOnObjCAvailabilityCheckExpr(
return new (Context)
ObjCAvailabilityCheckExpr(Version, AtLoc, RParen, Context.BoolTy);
}
+
+bool Sema::IsDependentFunctionNameExpr(Expr *E) {
+ assert(E->isTypeDependent());
+ return isa<UnresolvedLookupExpr>(E);
+}
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 9aae9289b514..a73e6906fceb 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -921,7 +921,7 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc,
// cannot be a simple walk of the class's decls. Instead, we must perform
// lookup and overload resolution.
CXXConstructorDecl *CD = LookupCopyingConstructor(Subobject, 0);
- if (!CD)
+ if (!CD || CD->isDeleted())
continue;
// Mark the constructor referenced as it is used by this throw expression.
@@ -2323,7 +2323,7 @@ static bool resolveAllocationOverload(
PartialDiagnosticAt(R.getNameLoc(),
S.PDiag(diag::err_ovl_ambiguous_call)
<< R.getLookupName() << Range),
- S, OCD_ViableCandidates, Args);
+ S, OCD_AmbiguousCandidates, Args);
}
return true;
@@ -3513,7 +3513,7 @@ static bool resolveBuiltinNewDeleteOverload(Sema &S, CallExpr *TheCall,
PartialDiagnosticAt(R.getNameLoc(),
S.PDiag(diag::err_ovl_ambiguous_call)
<< R.getLookupName() << Range),
- S, OCD_ViableCandidates, Args);
+ S, OCD_AmbiguousCandidates, Args);
return true;
case OR_Deleted: {
@@ -4095,9 +4095,26 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
<< From->getSourceRange();
}
+ // Defer address space conversion to the third conversion.
+ QualType FromPteeType = From->getType()->getPointeeType();
+ QualType ToPteeType = ToType->getPointeeType();
+ QualType NewToType = ToType;
+ if (!FromPteeType.isNull() && !ToPteeType.isNull() &&
+ FromPteeType.getAddressSpace() != ToPteeType.getAddressSpace()) {
+ NewToType = Context.removeAddrSpaceQualType(ToPteeType);
+ NewToType = Context.getAddrSpaceQualType(NewToType,
+ FromPteeType.getAddressSpace());
+ if (ToType->isObjCObjectPointerType())
+ NewToType = Context.getObjCObjectPointerType(NewToType);
+ else if (ToType->isBlockPointerType())
+ NewToType = Context.getBlockPointerType(NewToType);
+ else
+ NewToType = Context.getPointerType(NewToType);
+ }
+
CastKind Kind;
CXXCastPath BasePath;
- if (CheckPointerConversion(From, ToType, Kind, BasePath, CStyle))
+ if (CheckPointerConversion(From, NewToType, Kind, BasePath, CStyle))
return ExprError();
// Make sure we extend blocks if necessary.
@@ -4108,8 +4125,8 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
From = E.get();
}
if (getLangOpts().allowsNonTrivialObjCLifetimeQualifiers())
- CheckObjCConversion(SourceRange(), ToType, From, CCK);
- From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath, CCK)
+ CheckObjCConversion(SourceRange(), NewToType, From, CCK);
+ From = ImpCastExprToType(From, NewToType, Kind, VK_RValue, &BasePath, CCK)
.get();
break;
}
@@ -5730,38 +5747,157 @@ static bool ConvertForConditional(Sema &Self, ExprResult &E, QualType T) {
return false;
}
+// Check the condition operand of ?: to see if it is valid for the GCC
+// extension.
+static bool isValidVectorForConditionalCondition(ASTContext &Ctx,
+ QualType CondTy) {
+ if (!CondTy->isVectorType() || CondTy->isExtVectorType())
+ return false;
+ const QualType EltTy =
+ cast<VectorType>(CondTy.getCanonicalType())->getElementType();
+
+ assert(!EltTy->isBooleanType() && !EltTy->isEnumeralType() &&
+ "Vectors cant be boolean or enum types");
+ return EltTy->isIntegralType(Ctx);
+}
+
+QualType Sema::CheckGNUVectorConditionalTypes(ExprResult &Cond, ExprResult &LHS,
+ ExprResult &RHS,
+ SourceLocation QuestionLoc) {
+ LHS = DefaultFunctionArrayLvalueConversion(LHS.get());
+ RHS = DefaultFunctionArrayLvalueConversion(RHS.get());
+
+ QualType CondType = Cond.get()->getType();
+ const auto *CondVT = CondType->getAs<VectorType>();
+ QualType CondElementTy = CondVT->getElementType();
+ unsigned CondElementCount = CondVT->getNumElements();
+ QualType LHSType = LHS.get()->getType();
+ const auto *LHSVT = LHSType->getAs<VectorType>();
+ QualType RHSType = RHS.get()->getType();
+ const auto *RHSVT = RHSType->getAs<VectorType>();
+
+ QualType ResultType;
+
+ // FIXME: In the future we should define what the Extvector conditional
+ // operator looks like.
+ if (LHSVT && isa<ExtVectorType>(LHSVT)) {
+ Diag(QuestionLoc, diag::err_conditional_vector_operand_type)
+ << /*isExtVector*/ true << LHSType;
+ return {};
+ }
+
+ if (RHSVT && isa<ExtVectorType>(RHSVT)) {
+ Diag(QuestionLoc, diag::err_conditional_vector_operand_type)
+ << /*isExtVector*/ true << RHSType;
+ return {};
+ }
+
+ if (LHSVT && RHSVT) {
+ // If both are vector types, they must be the same type.
+ if (!Context.hasSameType(LHSType, RHSType)) {
+ Diag(QuestionLoc, diag::err_conditional_vector_mismatched_vectors)
+ << LHSType << RHSType;
+ return {};
+ }
+ ResultType = LHSType;
+ } else if (LHSVT || RHSVT) {
+ ResultType = CheckVectorOperands(
+ LHS, RHS, QuestionLoc, /*isCompAssign*/ false, /*AllowBothBool*/ true,
+ /*AllowBoolConversions*/ false);
+ if (ResultType.isNull())
+ return {};
+ } else {
+ // Both are scalar.
+ 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)
+ << /*isExtVector*/ false << ResultElementTy;
+ return {};
+ }
+ ResultType = Context.getVectorType(
+ ResultElementTy, CondType->getAs<VectorType>()->getNumElements(),
+ VectorType::GenericVector);
+
+ LHS = ImpCastExprToType(LHS.get(), ResultType, CK_VectorSplat);
+ RHS = ImpCastExprToType(RHS.get(), ResultType, CK_VectorSplat);
+ }
+
+ assert(!ResultType.isNull() && ResultType->isVectorType() &&
+ "Result should have been a vector type");
+ QualType ResultElementTy = ResultType->getAs<VectorType>()->getElementType();
+ unsigned ResultElementCount =
+ ResultType->getAs<VectorType>()->getNumElements();
+
+ if (ResultElementCount != CondElementCount) {
+ Diag(QuestionLoc, diag::err_conditional_vector_size) << CondType
+ << ResultType;
+ return {};
+ }
+
+ if (Context.getTypeSize(ResultElementTy) !=
+ Context.getTypeSize(CondElementTy)) {
+ Diag(QuestionLoc, diag::err_conditional_vector_element_size) << CondType
+ << ResultType;
+ return {};
+ }
+
+ 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
/// extension. In this case, LHS == Cond. (But they're not aliases.)
+///
+/// This function also implements GCC's vector extension for conditionals.
+/// GCC's vector extension permits the use of a?b:c where the type of
+/// a is that of a integer vector with the same number of elements and
+/// size as the vectors of b and c. If one of either b or c is a scalar
+/// it is implicitly converted to match the type of the vector.
+/// Otherwise the expression is ill-formed. If both b and c are scalars,
+/// then b and c are checked and converted to the type of a if possible.
+/// Unlike the OpenCL ?: operator, the expression is evaluated as
+/// (a[0] != 0 ? b[0] : c[0], .. , a[n] != 0 ? b[n] : c[n]).
QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
ExprResult &RHS, ExprValueKind &VK,
ExprObjectKind &OK,
SourceLocation QuestionLoc) {
- // FIXME: Handle C99's complex types, vector types, block pointers and Obj-C++
- // interface pointers.
+ // FIXME: Handle C99's complex types, block pointers and Obj-C++ interface
+ // pointers.
+
+ // Assume r-value.
+ VK = VK_RValue;
+ OK = OK_Ordinary;
+ bool IsVectorConditional =
+ isValidVectorForConditionalCondition(Context, Cond.get()->getType());
// C++11 [expr.cond]p1
// The first expression is contextually converted to bool.
- //
- // FIXME; GCC's vector extension permits the use of a?b:c where the type of
- // a is that of a integer vector with the same number of elements and
- // size as the vectors of b and c. If one of either b or c is a scalar
- // it is implicitly converted to match the type of the vector.
- // Otherwise the expression is ill-formed. If both b and c are scalars,
- // then b and c are checked and converted to the type of a if possible.
- // Unlike the OpenCL ?: operator, the expression is evaluated as
- // (a[0] != 0 ? b[0] : c[0], .. , a[n] != 0 ? b[n] : c[n]).
if (!Cond.get()->isTypeDependent()) {
- ExprResult CondRes = CheckCXXBooleanCondition(Cond.get());
+ ExprResult CondRes = IsVectorConditional
+ ? DefaultFunctionArrayLvalueConversion(Cond.get())
+ : CheckCXXBooleanCondition(Cond.get());
if (CondRes.isInvalid())
return QualType();
Cond = CondRes;
+ } else {
+ // To implement C++, the first expression typically doesn't alter the result
+ // type of the conditional, however the GCC compatible vector extension
+ // changes the result type to be that of the conditional. Since we cannot
+ // know if this is a vector extension here, delay the conversion of the
+ // LHS/RHS below until later.
+ return Context.DependentTy;
}
- // Assume r-value.
- VK = VK_RValue;
- OK = OK_Ordinary;
// Either of the arguments dependent?
if (LHS.get()->isTypeDependent() || RHS.get()->isTypeDependent())
@@ -5780,6 +5916,17 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
// and value category of the other.
bool LThrow = isa<CXXThrowExpr>(LHS.get()->IgnoreParenImpCasts());
bool RThrow = isa<CXXThrowExpr>(RHS.get()->IgnoreParenImpCasts());
+
+ // Void expressions aren't legal in the vector-conditional expressions.
+ if (IsVectorConditional) {
+ SourceRange DiagLoc =
+ LVoid ? LHS.get()->getSourceRange() : RHS.get()->getSourceRange();
+ bool IsThrow = LVoid ? LThrow : RThrow;
+ Diag(DiagLoc.getBegin(), diag::err_conditional_vector_has_void)
+ << DiagLoc << IsThrow;
+ return QualType();
+ }
+
if (LThrow != RThrow) {
Expr *NonThrow = LThrow ? RHS.get() : LHS.get();
VK = NonThrow->getValueKind();
@@ -5802,6 +5949,8 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
}
// Neither is void.
+ if (IsVectorConditional)
+ return CheckGNUVectorConditionalTypes(Cond, LHS, RHS, QuestionLoc);
// C++11 [expr.cond]p3
// Otherwise, if the second and third operand have different types, and
@@ -5845,29 +5994,33 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
// FIXME:
// Resolving a defect in P0012R1: we extend this to cover all cases where
// one of the operands is reference-compatible with the other, in order
- // to support conditionals between functions differing in noexcept.
+ // to support conditionals between functions differing in noexcept. This
+ // will similarly cover difference in array bounds after P0388R4.
+ // FIXME: If LTy and RTy have a composite pointer type, should we convert to
+ // that instead?
ExprValueKind LVK = LHS.get()->getValueKind();
ExprValueKind RVK = RHS.get()->getValueKind();
if (!Context.hasSameType(LTy, RTy) &&
LVK == RVK && LVK != VK_RValue) {
// DerivedToBase was already handled by the class-specific case above.
// FIXME: Should we allow ObjC conversions here?
- bool DerivedToBase, ObjCConversion, ObjCLifetimeConversion,
- FunctionConversion;
- if (CompareReferenceRelationship(QuestionLoc, LTy, RTy, DerivedToBase,
- ObjCConversion, ObjCLifetimeConversion,
- FunctionConversion) == Ref_Compatible &&
- !DerivedToBase && !ObjCConversion && !ObjCLifetimeConversion &&
+ const ReferenceConversions AllowedConversions =
+ ReferenceConversions::Qualification |
+ ReferenceConversions::NestedQualification |
+ ReferenceConversions::Function;
+
+ ReferenceConversions RefConv;
+ if (CompareReferenceRelationship(QuestionLoc, LTy, RTy, &RefConv) ==
+ Ref_Compatible &&
+ !(RefConv & ~AllowedConversions) &&
// [...] subject to the constraint that the reference must bind
// directly [...]
!RHS.get()->refersToBitField() && !RHS.get()->refersToVectorElement()) {
RHS = ImpCastExprToType(RHS.get(), LTy, CK_NoOp, RVK);
RTy = RHS.get()->getType();
- } else if (CompareReferenceRelationship(
- QuestionLoc, RTy, LTy, DerivedToBase, ObjCConversion,
- ObjCLifetimeConversion,
- FunctionConversion) == Ref_Compatible &&
- !DerivedToBase && !ObjCConversion && !ObjCLifetimeConversion &&
+ } else if (CompareReferenceRelationship(QuestionLoc, RTy, LTy, &RefConv) ==
+ Ref_Compatible &&
+ !(RefConv & ~AllowedConversions) &&
!LHS.get()->refersToBitField() &&
!LHS.get()->refersToVectorElement()) {
LHS = ImpCastExprToType(LHS.get(), RTy, CK_NoOp, LVK);
@@ -5976,7 +6129,8 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
// the usual arithmetic conversions are performed to bring them to a
// common type, and the result is of that type.
if (LTy->isArithmeticType() && RTy->isArithmeticType()) {
- QualType ResTy = UsualArithmeticConversions(LHS, RHS);
+ QualType ResTy =
+ UsualArithmeticConversions(LHS, RHS, QuestionLoc, ACK_Conditional);
if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
if (ResTy.isNull()) {
@@ -6098,10 +6252,10 @@ mergeExceptionSpecs(Sema &S, FunctionProtoType::ExceptionSpecInfo ESI1,
/// Find a merged pointer type and convert the two expressions to it.
///
-/// This finds the composite pointer type (or member pointer type) for @p E1
-/// and @p E2 according to C++1z 5p14. It converts both expressions to this
-/// type and returns it.
-/// It does not emit diagnostics.
+/// This finds the composite pointer type for \p E1 and \p E2 according to
+/// C++2a [expr.type]p3. It converts both expressions to this type and returns
+/// it. It does not emit diagnostics (FIXME: that's not true if \p ConvertArgs
+/// is \c true).
///
/// \param Loc The location of the operator requiring these two expressions to
/// be converted to the composite pointer type.
@@ -6154,60 +6308,117 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc,
assert(!T1->isNullPtrType() && !T2->isNullPtrType() &&
"nullptr_t should be a null pointer constant");
- // - if T1 or T2 is "pointer to cv1 void" and the other type is
- // "pointer to cv2 T", "pointer to cv12 void", where cv12 is
- // the union of cv1 and cv2;
- // - if T1 or T2 is "pointer to noexcept function" and the other type is
- // "pointer to function", where the function types are otherwise the same,
- // "pointer to function";
- // FIXME: This rule is defective: it should also permit removing noexcept
- // from a pointer to member function. As a Clang extension, we also
- // permit removing 'noreturn', so we generalize this rule to;
- // - [Clang] If T1 and T2 are both of type "pointer to function" or
- // "pointer to member function" and the pointee types can be unified
- // by a function pointer conversion, that conversion is applied
- // before checking the following rules.
+ struct Step {
+ enum Kind { Pointer, ObjCPointer, MemberPointer, Array } K;
+ // Qualifiers to apply under the step kind.
+ Qualifiers Quals;
+ /// The class for a pointer-to-member; a constant array type with a bound
+ /// (if any) for an array.
+ const Type *ClassOrBound;
+
+ Step(Kind K, const Type *ClassOrBound = nullptr)
+ : K(K), Quals(), ClassOrBound(ClassOrBound) {}
+ QualType rebuild(ASTContext &Ctx, QualType T) const {
+ T = Ctx.getQualifiedType(T, Quals);
+ switch (K) {
+ case Pointer:
+ return Ctx.getPointerType(T);
+ case MemberPointer:
+ return Ctx.getMemberPointerType(T, ClassOrBound);
+ case ObjCPointer:
+ return Ctx.getObjCObjectPointerType(T);
+ case Array:
+ if (auto *CAT = cast_or_null<ConstantArrayType>(ClassOrBound))
+ return Ctx.getConstantArrayType(T, CAT->getSize(), nullptr,
+ ArrayType::Normal, 0);
+ else
+ return Ctx.getIncompleteArrayType(T, ArrayType::Normal, 0);
+ }
+ llvm_unreachable("unknown step kind");
+ }
+ };
+
+ SmallVector<Step, 8> Steps;
+
// - if T1 is "pointer to cv1 C1" and T2 is "pointer to cv2 C2", where C1
// is reference-related to C2 or C2 is reference-related to C1 (8.6.3),
// the cv-combined type of T1 and T2 or the cv-combined type of T2 and T1,
// respectively;
// - if T1 is "pointer to member of C1 of type cv1 U1" and T2 is "pointer
- // to member of C2 of type cv2 U2" where C1 is reference-related to C2 or
- // C2 is reference-related to C1 (8.6.3), the cv-combined type of T2 and
- // T1 or the cv-combined type of T1 and T2, respectively;
+ // to member of C2 of type cv2 U2" for some non-function type U, where
+ // C1 is reference-related to C2 or C2 is reference-related to C1, the
+ // cv-combined type of T2 and T1 or the cv-combined type of T1 and T2,
+ // respectively;
// - if T1 and T2 are similar types (4.5), the cv-combined type of T1 and
// T2;
//
- // If looked at in the right way, these bullets all do the same thing.
- // What we do here is, we build the two possible cv-combined types, and try
- // the conversions in both directions. If only one works, or if the two
- // composite types are the same, we have succeeded.
- // FIXME: extended qualifiers?
- //
- // Note that this will fail to find a composite pointer type for "pointer
- // to void" and "pointer to function". We can't actually perform the final
- // conversion in this case, even though a composite pointer type formally
- // exists.
- SmallVector<unsigned, 4> QualifierUnion;
- SmallVector<std::pair<const Type *, const Type *>, 4> MemberOfClass;
+ // Dismantle T1 and T2 to simultaneously determine whether they are similar
+ // and to prepare to form the cv-combined type if so.
QualType Composite1 = T1;
QualType Composite2 = T2;
unsigned NeedConstBefore = 0;
while (true) {
+ assert(!Composite1.isNull() && !Composite2.isNull());
+
+ Qualifiers Q1, Q2;
+ Composite1 = Context.getUnqualifiedArrayType(Composite1, Q1);
+ Composite2 = Context.getUnqualifiedArrayType(Composite2, Q2);
+
+ // Top-level qualifiers are ignored. Merge at all lower levels.
+ if (!Steps.empty()) {
+ // Find the qualifier union: (approximately) the unique minimal set of
+ // qualifiers that is compatible with both types.
+ Qualifiers Quals = Qualifiers::fromCVRUMask(Q1.getCVRUQualifiers() |
+ Q2.getCVRUQualifiers());
+
+ // Under one level of pointer or pointer-to-member, we can change to an
+ // unambiguous compatible address space.
+ if (Q1.getAddressSpace() == Q2.getAddressSpace()) {
+ Quals.setAddressSpace(Q1.getAddressSpace());
+ } else if (Steps.size() == 1) {
+ bool MaybeQ1 = Q1.isAddressSpaceSupersetOf(Q2);
+ bool MaybeQ2 = Q2.isAddressSpaceSupersetOf(Q1);
+ if (MaybeQ1 == MaybeQ2)
+ return QualType(); // No unique best address space.
+ Quals.setAddressSpace(MaybeQ1 ? Q1.getAddressSpace()
+ : Q2.getAddressSpace());
+ } else {
+ return QualType();
+ }
+
+ // FIXME: In C, we merge __strong and none to __strong at the top level.
+ if (Q1.getObjCGCAttr() == Q2.getObjCGCAttr())
+ Quals.setObjCGCAttr(Q1.getObjCGCAttr());
+ else
+ return QualType();
+
+ // Mismatched lifetime qualifiers never compatibly include each other.
+ if (Q1.getObjCLifetime() == Q2.getObjCLifetime())
+ Quals.setObjCLifetime(Q1.getObjCLifetime());
+ else
+ return QualType();
+
+ Steps.back().Quals = Quals;
+ if (Q1 != Quals || Q2 != Quals)
+ NeedConstBefore = Steps.size() - 1;
+ }
+
+ // FIXME: Can we unify the following with UnwrapSimilarTypes?
const PointerType *Ptr1, *Ptr2;
if ((Ptr1 = Composite1->getAs<PointerType>()) &&
(Ptr2 = Composite2->getAs<PointerType>())) {
Composite1 = Ptr1->getPointeeType();
Composite2 = Ptr2->getPointeeType();
+ Steps.emplace_back(Step::Pointer);
+ continue;
+ }
- // If we're allowed to create a non-standard composite type, keep track
- // of where we need to fill in additional 'const' qualifiers.
- if (Composite1.getCVRQualifiers() != Composite2.getCVRQualifiers())
- NeedConstBefore = QualifierUnion.size();
-
- QualifierUnion.push_back(
- Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers());
- MemberOfClass.push_back(std::make_pair(nullptr, nullptr));
+ const ObjCObjectPointerType *ObjPtr1, *ObjPtr2;
+ if ((ObjPtr1 = Composite1->getAs<ObjCObjectPointerType>()) &&
+ (ObjPtr2 = Composite2->getAs<ObjCObjectPointerType>())) {
+ Composite1 = ObjPtr1->getPointeeType();
+ Composite2 = ObjPtr2->getPointeeType();
+ Steps.emplace_back(Step::ObjCPointer);
continue;
}
@@ -6217,34 +6428,79 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc,
Composite1 = MemPtr1->getPointeeType();
Composite2 = MemPtr2->getPointeeType();
- // If we're allowed to create a non-standard composite type, keep track
- // of where we need to fill in additional 'const' qualifiers.
- if (Composite1.getCVRQualifiers() != Composite2.getCVRQualifiers())
- NeedConstBefore = QualifierUnion.size();
+ // At the top level, we can perform a base-to-derived pointer-to-member
+ // conversion:
+ //
+ // - [...] where C1 is reference-related to C2 or C2 is
+ // reference-related to C1
+ //
+ // (Note that the only kinds of reference-relatedness in scope here are
+ // "same type or derived from".) At any other level, the class must
+ // exactly match.
+ const Type *Class = nullptr;
+ QualType Cls1(MemPtr1->getClass(), 0);
+ QualType Cls2(MemPtr2->getClass(), 0);
+ if (Context.hasSameType(Cls1, Cls2))
+ Class = MemPtr1->getClass();
+ else if (Steps.empty())
+ Class = IsDerivedFrom(Loc, Cls1, Cls2) ? MemPtr1->getClass() :
+ IsDerivedFrom(Loc, Cls2, Cls1) ? MemPtr2->getClass() : nullptr;
+ if (!Class)
+ return QualType();
- QualifierUnion.push_back(
- Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers());
- MemberOfClass.push_back(std::make_pair(MemPtr1->getClass(),
- MemPtr2->getClass()));
+ Steps.emplace_back(Step::MemberPointer, Class);
continue;
}
+ // Special case: at the top level, we can decompose an Objective-C pointer
+ // and a 'cv void *'. Unify the qualifiers.
+ if (Steps.empty() && ((Composite1->isVoidPointerType() &&
+ Composite2->isObjCObjectPointerType()) ||
+ (Composite1->isObjCObjectPointerType() &&
+ Composite2->isVoidPointerType()))) {
+ Composite1 = Composite1->getPointeeType();
+ Composite2 = Composite2->getPointeeType();
+ Steps.emplace_back(Step::Pointer);
+ continue;
+ }
+
+ // FIXME: arrays
+
// FIXME: block pointer types?
// Cannot unwrap any more types.
break;
}
- // Apply the function pointer conversion to unify the types. We've already
- // unwrapped down to the function types, and we want to merge rather than
- // just convert, so do this ourselves rather than calling
+ // - if T1 or T2 is "pointer to noexcept function" and the other type is
+ // "pointer to function", where the function types are otherwise the same,
+ // "pointer to function";
+ // - if T1 or T2 is "pointer to member of C1 of type function", the other
+ // type is "pointer to member of C2 of type noexcept function", and C1
+ // is reference-related to C2 or C2 is reference-related to C1, where
+ // the function types are otherwise the same, "pointer to member of C2 of
+ // type function" or "pointer to member of C1 of type function",
+ // respectively;
+ //
+ // We also support 'noreturn' here, so as a Clang extension we generalize the
+ // above to:
+ //
+ // - [Clang] If T1 and T2 are both of type "pointer to function" or
+ // "pointer to member function" and the pointee types can be unified
+ // by a function pointer conversion, that conversion is applied
+ // before checking the following rules.
+ //
+ // We've already unwrapped down to the function types, and we want to merge
+ // rather than just convert, so do this ourselves rather than calling
// IsFunctionConversion.
//
// FIXME: In order to match the standard wording as closely as possible, we
// currently only do this under a single level of pointers. Ideally, we would
// allow this in general, and set NeedConstBefore to the relevant depth on
- // the side(s) where we changed anything.
- if (QualifierUnion.size() == 1) {
+ // the side(s) where we changed anything. If we permit that, we should also
+ // consider this conversion when determining type similarity and model it as
+ // a qualification conversion.
+ if (Steps.size() == 1) {
if (auto *FPT1 = Composite1->getAs<FunctionProtoType>()) {
if (auto *FPT2 = Composite2->getAs<FunctionProtoType>()) {
FunctionProtoType::ExtProtoInfo EPI1 = FPT1->getExtProtoInfo();
@@ -6270,88 +6526,72 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc,
}
}
- if (NeedConstBefore) {
- // Extension: Add 'const' to qualifiers that come before the first qualifier
- // mismatch, so that our (non-standard!) composite type meets the
- // requirements of C++ [conv.qual]p4 bullet 3.
- for (unsigned I = 0; I != NeedConstBefore; ++I)
- if ((QualifierUnion[I] & Qualifiers::Const) == 0)
- QualifierUnion[I] = QualifierUnion[I] | Qualifiers::Const;
+ // There are some more conversions we can perform under exactly one pointer.
+ if (Steps.size() == 1 && Steps.front().K == Step::Pointer &&
+ !Context.hasSameType(Composite1, Composite2)) {
+ // - if T1 or T2 is "pointer to cv1 void" and the other type is
+ // "pointer to cv2 T", where T is an object type or void,
+ // "pointer to cv12 void", where cv12 is the union of cv1 and cv2;
+ if (Composite1->isVoidType() && Composite2->isObjectType())
+ Composite2 = Composite1;
+ else if (Composite2->isVoidType() && Composite1->isObjectType())
+ Composite1 = Composite2;
+ // - if T1 is "pointer to cv1 C1" and T2 is "pointer to cv2 C2", where C1
+ // is reference-related to C2 or C2 is reference-related to C1 (8.6.3),
+ // the cv-combined type of T1 and T2 or the cv-combined type of T2 and
+ // T1, respectively;
+ //
+ // The "similar type" handling covers all of this except for the "T1 is a
+ // base class of T2" case in the definition of reference-related.
+ else if (IsDerivedFrom(Loc, Composite1, Composite2))
+ Composite1 = Composite2;
+ else if (IsDerivedFrom(Loc, Composite2, Composite1))
+ Composite2 = Composite1;
}
- // Rewrap the composites as pointers or member pointers with the union CVRs.
- auto MOC = MemberOfClass.rbegin();
- for (unsigned CVR : llvm::reverse(QualifierUnion)) {
- Qualifiers Quals = Qualifiers::fromCVRMask(CVR);
- auto Classes = *MOC++;
- if (Classes.first && Classes.second) {
- // Rebuild member pointer type
- Composite1 = Context.getMemberPointerType(
- Context.getQualifiedType(Composite1, Quals), Classes.first);
- Composite2 = Context.getMemberPointerType(
- Context.getQualifiedType(Composite2, Quals), Classes.second);
- } else {
- // Rebuild pointer type
- Composite1 =
- Context.getPointerType(Context.getQualifiedType(Composite1, Quals));
- Composite2 =
- Context.getPointerType(Context.getQualifiedType(Composite2, Quals));
- }
- }
-
- struct Conversion {
- Sema &S;
- Expr *&E1, *&E2;
- QualType Composite;
- InitializedEntity Entity;
- InitializationKind Kind;
- InitializationSequence E1ToC, E2ToC;
- bool Viable;
-
- Conversion(Sema &S, SourceLocation Loc, Expr *&E1, Expr *&E2,
- QualType Composite)
- : S(S), E1(E1), E2(E2), Composite(Composite),
- Entity(InitializedEntity::InitializeTemporary(Composite)),
- Kind(InitializationKind::CreateCopy(Loc, SourceLocation())),
- E1ToC(S, Entity, Kind, E1), E2ToC(S, Entity, Kind, E2),
- Viable(E1ToC && E2ToC) {}
-
- bool perform() {
- ExprResult E1Result = E1ToC.Perform(S, Entity, Kind, E1);
- if (E1Result.isInvalid())
- return true;
- E1 = E1Result.getAs<Expr>();
+ // At this point, either the inner types are the same or we have failed to
+ // find a composite pointer type.
+ if (!Context.hasSameType(Composite1, Composite2))
+ return QualType();
- ExprResult E2Result = E2ToC.Perform(S, Entity, Kind, E2);
- if (E2Result.isInvalid())
- return true;
- E2 = E2Result.getAs<Expr>();
+ // Per C++ [conv.qual]p3, add 'const' to every level before the last
+ // differing qualifier.
+ for (unsigned I = 0; I != NeedConstBefore; ++I)
+ Steps[I].Quals.addConst();
- return false;
- }
- };
+ // Rebuild the composite type.
+ QualType Composite = Composite1;
+ for (auto &S : llvm::reverse(Steps))
+ Composite = S.rebuild(Context, Composite);
- // Try to convert to each composite pointer type.
- Conversion C1(*this, Loc, E1, E2, Composite1);
- if (C1.Viable && Context.hasSameType(Composite1, Composite2)) {
- if (ConvertArgs && C1.perform())
+ if (ConvertArgs) {
+ // Convert the expressions to the composite pointer type.
+ InitializedEntity Entity =
+ InitializedEntity::InitializeTemporary(Composite);
+ InitializationKind Kind =
+ InitializationKind::CreateCopy(Loc, SourceLocation());
+
+ InitializationSequence E1ToC(*this, Entity, Kind, E1);
+ if (!E1ToC)
return QualType();
- return C1.Composite;
- }
- Conversion C2(*this, Loc, E1, E2, Composite2);
- if (C1.Viable == C2.Viable) {
- // Either Composite1 and Composite2 are viable and are different, or
- // neither is viable.
- // FIXME: How both be viable and different?
- return QualType();
- }
+ InitializationSequence E2ToC(*this, Entity, Kind, E2);
+ if (!E2ToC)
+ return QualType();
- // Convert to the chosen type.
- if (ConvertArgs && (C1.Viable ? C1 : C2).perform())
- return QualType();
+ // FIXME: Let the caller know if these fail to avoid duplicate diagnostics.
+ ExprResult E1Result = E1ToC.Perform(*this, Entity, Kind, E1);
+ if (E1Result.isInvalid())
+ return QualType();
+ E1 = E1Result.get();
+
+ ExprResult E2Result = E2ToC.Perform(*this, Entity, Kind, E2);
+ if (E2Result.isInvalid())
+ return QualType();
+ E2 = E2Result.get();
+ }
- return C1.Viable ? C1.Composite : C2.Composite;
+ return Composite;
}
ExprResult Sema::MaybeBindToTemporary(Expr *E) {
@@ -7780,8 +8020,9 @@ class TransformTypos : public TreeTransform<TransformTypos> {
// If we found a valid result, double check to make sure it's not ambiguous.
if (!IsAmbiguous && !Res.isInvalid() && !AmbiguousTypoExprs.empty()) {
- auto SavedTransformCache = std::move(TransformCache);
- TransformCache.clear();
+ auto SavedTransformCache =
+ llvm::SmallDenseMap<TypoExpr *, ExprResult, 2>(TransformCache);
+
// Ensure none of the TypoExprs have multiple typo correction candidates
// with the same edit length that pass all the checks and filters.
while (!AmbiguousTypoExprs.empty()) {
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index 87114a0fac63..ebfc1ec4b974 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -919,6 +919,18 @@ MemberExpr *Sema::BuildMemberExpr(
VK, OK, getNonOdrUseReasonInCurrentContext(Member));
E->setHadMultipleCandidates(HadMultipleCandidates);
MarkMemberReferenced(E);
+
+ // C++ [except.spec]p17:
+ // An exception-specification is considered to be needed when:
+ // - in an expression the function is the unique lookup result or the
+ // selected member of a set of overloaded functions
+ if (auto *FPT = Ty->getAs<FunctionProtoType>()) {
+ if (isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) {
+ if (auto *NewFPT = ResolveExceptionSpec(MemberNameInfo.getLoc(), FPT))
+ E->setType(Context.getQualifiedType(NewFPT, Ty.getQualifiers()));
+ }
+ }
+
return E;
}
diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp
index e18621e42a6b..c61b13cf5980 100644
--- a/clang/lib/Sema/SemaExprObjC.cpp
+++ b/clang/lib/Sema/SemaExprObjC.cpp
@@ -10,13 +10,13 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Sema/SemaInternal.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
+#include "clang/Basic/Builtins.h"
#include "clang/Edit/Commit.h"
#include "clang/Edit/Rewriters.h"
#include "clang/Lex/Preprocessor.h"
@@ -24,6 +24,7 @@
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/SemaInternal.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/ConvertUTF.h"
@@ -288,6 +289,7 @@ static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc,
S.NSNumberPointer, ReturnTInfo, S.NSNumberDecl,
/*isInstance=*/false, /*isVariadic=*/false,
/*isPropertyAccessor=*/false,
+ /*isSynthesizedAccessorStub=*/false,
/*isImplicitlyDeclared=*/true,
/*isDefined=*/false, ObjCMethodDecl::Required,
/*HasRelatedResultType=*/false);
@@ -563,6 +565,7 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
NSStringPointer, ReturnTInfo, NSStringDecl,
/*isInstance=*/false, /*isVariadic=*/false,
/*isPropertyAccessor=*/false,
+ /*isSynthesizedAccessorStub=*/false,
/*isImplicitlyDeclared=*/true,
/*isDefined=*/false, ObjCMethodDecl::Required,
/*HasRelatedResultType=*/false);
@@ -671,20 +674,15 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
// Debugger needs to work even if NSValue hasn't been defined.
TypeSourceInfo *ReturnTInfo = nullptr;
ObjCMethodDecl *M = ObjCMethodDecl::Create(
- Context,
- SourceLocation(),
- SourceLocation(),
- ValueWithBytesObjCType,
- NSValuePointer,
- ReturnTInfo,
- NSValueDecl,
- /*isInstance=*/false,
- /*isVariadic=*/false,
- /*isPropertyAccessor=*/false,
- /*isImplicitlyDeclared=*/true,
- /*isDefined=*/false,
- ObjCMethodDecl::Required,
- /*HasRelatedResultType=*/false);
+ Context, SourceLocation(), SourceLocation(), ValueWithBytesObjCType,
+ NSValuePointer, ReturnTInfo, NSValueDecl,
+ /*isInstance=*/false,
+ /*isVariadic=*/false,
+ /*isPropertyAccessor=*/false,
+ /*isSynthesizedAccessorStub=*/false,
+ /*isImplicitlyDeclared=*/true,
+ /*isDefined=*/false, ObjCMethodDecl::Required,
+ /*HasRelatedResultType=*/false);
SmallVector<ParmVarDecl *, 2> Params;
@@ -815,7 +813,7 @@ ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) {
Context, SourceLocation(), SourceLocation(), Sel, IdT, ReturnTInfo,
Context.getTranslationUnitDecl(), false /*Instance*/,
false /*isVariadic*/,
- /*isPropertyAccessor=*/false,
+ /*isPropertyAccessor=*/false, /*isSynthesizedAccessorStub=*/false,
/*isImplicitlyDeclared=*/true, /*isDefined=*/false,
ObjCMethodDecl::Required, false);
SmallVector<ParmVarDecl *, 2> Params;
@@ -916,16 +914,14 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR,
NSAPI::NSDict_dictionaryWithObjectsForKeysCount);
ObjCMethodDecl *Method = NSDictionaryDecl->lookupClassMethod(Sel);
if (!Method && getLangOpts().DebuggerObjCLiteral) {
- Method = ObjCMethodDecl::Create(Context,
- SourceLocation(), SourceLocation(), Sel,
- IdT,
- nullptr /*TypeSourceInfo */,
- Context.getTranslationUnitDecl(),
- false /*Instance*/, false/*isVariadic*/,
- /*isPropertyAccessor=*/false,
- /*isImplicitlyDeclared=*/true, /*isDefined=*/false,
- ObjCMethodDecl::Required,
- false);
+ Method = ObjCMethodDecl::Create(
+ Context, SourceLocation(), SourceLocation(), Sel, IdT,
+ nullptr /*TypeSourceInfo */, Context.getTranslationUnitDecl(),
+ false /*Instance*/, false /*isVariadic*/,
+ /*isPropertyAccessor=*/false,
+ /*isSynthesizedAccessorStub=*/false,
+ /*isImplicitlyDeclared=*/true, /*isDefined=*/false,
+ ObjCMethodDecl::Required, false);
SmallVector<ParmVarDecl *, 3> Params;
ParmVarDecl *objects = ParmVarDecl::Create(Context, Method,
SourceLocation(),
@@ -1174,6 +1170,35 @@ static void DiagnoseMismatchedSelectors(Sema &S, SourceLocation AtLoc,
}
}
+static void HelperToDiagnoseDirectSelectorsExpr(Sema &S, SourceLocation AtLoc,
+ Selector Sel,
+ ObjCMethodList &MethList,
+ bool &onlyDirect) {
+ ObjCMethodList *M = &MethList;
+ for (M = M->getNext(); M; M = M->getNext()) {
+ ObjCMethodDecl *Method = M->getMethod();
+ if (Method->getSelector() != Sel)
+ continue;
+ if (!Method->isDirectMethod())
+ onlyDirect = false;
+ }
+}
+
+static void DiagnoseDirectSelectorsExpr(Sema &S, SourceLocation AtLoc,
+ Selector Sel, bool &onlyDirect) {
+ for (Sema::GlobalMethodPool::iterator b = S.MethodPool.begin(),
+ e = S.MethodPool.end(); b != e; b++) {
+ // first, instance methods
+ ObjCMethodList &InstMethList = b->second.first;
+ HelperToDiagnoseDirectSelectorsExpr(S, AtLoc, Sel, InstMethList,
+ onlyDirect);
+
+ // second, class methods
+ ObjCMethodList &ClsMethList = b->second.second;
+ HelperToDiagnoseDirectSelectorsExpr(S, AtLoc, Sel, ClsMethList, onlyDirect);
+ }
+}
+
ExprResult Sema::ParseObjCSelectorExpression(Selector Sel,
SourceLocation AtLoc,
SourceLocation SelLoc,
@@ -1196,9 +1221,18 @@ ExprResult Sema::ParseObjCSelectorExpression(Selector Sel,
} else
Diag(SelLoc, diag::warn_undeclared_selector) << Sel;
- } else
+ } else {
+ bool onlyDirect = Method->isDirectMethod();
+ DiagnoseDirectSelectorsExpr(*this, AtLoc, Sel, onlyDirect);
DiagnoseMismatchedSelectors(*this, AtLoc, Method, LParenLoc, RParenLoc,
WarnMultipleSelectors);
+ if (onlyDirect) {
+ Diag(AtLoc, diag::err_direct_selector_expression)
+ << Method->getSelector();
+ Diag(Method->getLocation(), diag::note_direct_method_declared_at)
+ << Method->getDeclName();
+ }
+ }
if (Method &&
Method->getImplementationControl() != ObjCMethodDecl::Optional &&
@@ -1608,15 +1642,14 @@ bool Sema::CheckMessageArgumentTypes(
<< Sel << isClassMessage << SourceRange(SelectorLocs.front(),
SelectorLocs.back());
// Find the class to which we are sending this message.
- if (ReceiverType->isObjCObjectPointerType()) {
- if (ObjCInterfaceDecl *ThisClass =
- ReceiverType->getAs<ObjCObjectPointerType>()->getInterfaceDecl()) {
+ if (auto *ObjPT = ReceiverType->getAs<ObjCObjectPointerType>()) {
+ if (ObjCInterfaceDecl *ThisClass = ObjPT->getInterfaceDecl()) {
Diag(ThisClass->getLocation(), diag::note_receiver_class_declared);
if (!RecRange.isInvalid())
if (ThisClass->lookupClassMethod(Sel))
- Diag(RecRange.getBegin(),diag::note_receiver_expr_here)
- << FixItHint::CreateReplacement(RecRange,
- ThisClass->getNameAsString());
+ Diag(RecRange.getBegin(), diag::note_receiver_expr_here)
+ << FixItHint::CreateReplacement(RecRange,
+ ThisClass->getNameAsString());
}
}
}
@@ -2365,7 +2398,6 @@ static void checkFoundationAPI(Sema &S, SourceLocation Loc,
return;
QualType Ret = ImpliedMethod->getReturnType();
if (Ret->isRecordType() || Ret->isVectorType() || Ret->isExtVectorType()) {
- QualType Ret = ImpliedMethod->getReturnType();
S.Diag(Loc, diag::warn_objc_unsafe_perform_selector)
<< Method->getSelector()
<< (!Ret->isRecordType()
@@ -2771,9 +2803,6 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
}
}
- if (ReceiverType->isObjCIdType() && !isImplicit)
- Diag(Receiver->getExprLoc(), diag::warn_messaging_unqualified_id);
-
// There's a somewhat weird interaction here where we assume that we
// won't actually have a method unless we also don't need to do some
// of the more detailed type-checking on the receiver.
@@ -2975,6 +3004,30 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
(Method && Method->getMethodFamily() == OMF_init)
? getEnclosingFunction() : nullptr;
+ if (Method && Method->isDirectMethod()) {
+ if (ReceiverType->isObjCIdType() && !isImplicit) {
+ Diag(Receiver->getExprLoc(),
+ diag::err_messaging_unqualified_id_with_direct_method);
+ Diag(Method->getLocation(), diag::note_direct_method_declared_at)
+ << Method->getDeclName();
+ }
+
+ if (ReceiverType->isObjCClassType() && !isImplicit) {
+ Diag(Receiver->getExprLoc(),
+ diag::err_messaging_class_with_direct_method);
+ Diag(Method->getLocation(), diag::note_direct_method_declared_at)
+ << Method->getDeclName();
+ }
+
+ if (SuperLoc.isValid()) {
+ Diag(SuperLoc, diag::err_messaging_super_with_direct_method);
+ Diag(Method->getLocation(), diag::note_direct_method_declared_at)
+ << Method->getDeclName();
+ }
+ } else if (ReceiverType->isObjCIdType() && !isImplicit) {
+ Diag(Receiver->getExprLoc(), diag::warn_messaging_unqualified_id);
+ }
+
if (DIFunctionScopeInfo &&
DIFunctionScopeInfo->ObjCIsDesignatedInit &&
(SuperLoc.isValid() || isSelfExpr(Receiver))) {
@@ -4358,7 +4411,7 @@ Expr *Sema::stripARCUnbridgedCast(Expr *e) {
SmallVector<TypeSourceInfo *, 4> subTypes;
subExprs.reserve(n);
subTypes.reserve(n);
- for (const GenericSelectionExpr::Association &assoc : gse->associations()) {
+ for (const GenericSelectionExpr::Association assoc : gse->associations()) {
subTypes.push_back(assoc.getTypeSourceInfo());
Expr *sub = assoc.getAssociationExpr();
if (assoc.isSelected())
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 10cb7acad567..785637761e71 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -3877,9 +3877,6 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc,
if (!Info.Constructor || Info.Constructor->isInvalidDecl())
continue;
- if (!AllowExplicit && Info.Constructor->isExplicit())
- continue;
-
if (OnlyListConstructors && !S.isInitListConstructor(Info.Constructor))
continue;
@@ -3951,18 +3948,16 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc,
else
Conv = cast<CXXConversionDecl>(D);
- if (AllowExplicit || !Conv->isExplicit()) {
- if (ConvTemplate)
- S.AddTemplateConversionCandidate(
- ConvTemplate, I.getPair(), ActingDC, Initializer, DestType,
- CandidateSet, AllowExplicit, AllowExplicit,
- /*AllowResultConversion*/ false);
- else
- S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Initializer,
- DestType, CandidateSet, AllowExplicit,
- AllowExplicit,
- /*AllowResultConversion*/ false);
- }
+ if (ConvTemplate)
+ S.AddTemplateConversionCandidate(
+ ConvTemplate, I.getPair(), ActingDC, Initializer, DestType,
+ CandidateSet, AllowExplicit, AllowExplicit,
+ /*AllowResultConversion*/ false);
+ else
+ S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Initializer,
+ DestType, CandidateSet, AllowExplicit,
+ AllowExplicit,
+ /*AllowResultConversion*/ false);
}
}
}
@@ -4064,7 +4059,7 @@ static void TryConstructorInitialization(Sema &S,
// If the initializer list has no elements and T has a default constructor,
// the first phase is omitted.
- if (!(UnwrappedArgs.empty() && DestRecordDecl->hasDefaultConstructor()))
+ if (!(UnwrappedArgs.empty() && S.LookupDefaultConstructor(DestRecordDecl)))
Result = ResolveConstructorOverload(S, Kind.getLocation(), Args,
CandidateSet, DestType, Ctors, Best,
CopyInitialization, AllowExplicit,
@@ -4229,10 +4224,8 @@ static void TryReferenceListInitialization(Sema &S,
return;
SourceLocation DeclLoc = Initializer->getBeginLoc();
- bool dummy1, dummy2, dummy3, dummy4;
Sema::ReferenceCompareResult RefRelationship
- = S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, dummy1,
- dummy2, dummy3, dummy4);
+ = S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2);
if (RefRelationship >= Sema::Ref_Related) {
// Try to bind the reference here.
TryReferenceInitializationCore(S, Entity, Kind, Initializer, cv1T1, T1,
@@ -4350,7 +4343,7 @@ static void TryListInitialization(Sema &S,
// value-initialized.
if (InitList->getNumInits() == 0) {
CXXRecordDecl *RD = DestType->getAsCXXRecordDecl();
- if (RD->hasDefaultConstructor()) {
+ if (S.LookupDefaultConstructor(RD)) {
TryValueInitialization(S, Entity, Kind, Sequence, InitList);
return;
}
@@ -4469,18 +4462,8 @@ static OverloadingResult TryRefInitWithConversionFunction(
QualType cv2T2 = Initializer->getType();
QualType T2 = cv2T2.getUnqualifiedType();
- bool DerivedToBase;
- bool ObjCConversion;
- bool ObjCLifetimeConversion;
- bool FunctionConversion;
- assert(!S.CompareReferenceRelationship(
- Initializer->getBeginLoc(), T1, T2, DerivedToBase, ObjCConversion,
- ObjCLifetimeConversion, FunctionConversion) &&
+ assert(!S.CompareReferenceRelationship(Initializer->getBeginLoc(), T1, T2) &&
"Must have incompatible references when binding via conversion");
- (void)DerivedToBase;
- (void)ObjCConversion;
- (void)ObjCLifetimeConversion;
- (void)FunctionConversion;
// Build the candidate set directly in the initialization sequence
// structure, so that it will persist if we fail.
@@ -4507,7 +4490,7 @@ static OverloadingResult TryRefInitWithConversionFunction(
continue;
if (!Info.Constructor->isInvalidDecl() &&
- Info.Constructor->isConvertingConstructor(AllowExplicitCtors)) {
+ Info.Constructor->isConvertingConstructor(/*AllowExplicit*/true)) {
if (Info.ConstructorTmpl)
S.AddTemplateOverloadCandidate(
Info.ConstructorTmpl, Info.FoundDecl,
@@ -4552,8 +4535,7 @@ static OverloadingResult TryRefInitWithConversionFunction(
// FIXME: Do we need to make sure that we only consider conversion
// candidates with reference-compatible results? That might be needed to
// break recursion.
- if ((AllowExplicitConvs || !Conv->isExplicit()) &&
- (AllowRValues ||
+ if ((AllowRValues ||
Conv->getConversionType()->isLValueReferenceType())) {
if (ConvTemplate)
S.AddTemplateConversionCandidate(
@@ -4604,14 +4586,9 @@ static OverloadingResult TryRefInitWithConversionFunction(
// Determine whether we'll need to perform derived-to-base adjustments or
// other conversions.
- bool NewDerivedToBase = false;
- bool NewObjCConversion = false;
- bool NewObjCLifetimeConversion = false;
- bool NewFunctionConversion = false;
+ Sema::ReferenceConversions RefConv;
Sema::ReferenceCompareResult NewRefRelationship =
- S.CompareReferenceRelationship(
- DeclLoc, T1, cv3T3, NewDerivedToBase, NewObjCConversion,
- NewObjCLifetimeConversion, NewFunctionConversion);
+ S.CompareReferenceRelationship(DeclLoc, T1, cv3T3, &RefConv);
// Add the final conversion sequence, if necessary.
if (NewRefRelationship == Sema::Ref_Incompatible) {
@@ -4641,12 +4618,16 @@ static OverloadingResult TryRefInitWithConversionFunction(
Sequence.AddReferenceBindingStep(cv1T4, VK == VK_RValue);
VK = IsLValueRef ? VK_LValue : VK_XValue;
- if (NewDerivedToBase)
+ if (RefConv & Sema::ReferenceConversions::DerivedToBase)
Sequence.AddDerivedToBaseCastStep(cv1T1, VK);
- else if (NewObjCConversion)
+ else if (RefConv & Sema::ReferenceConversions::ObjC)
Sequence.AddObjCObjectConversionStep(cv1T1);
- else if (NewFunctionConversion)
+ else if (RefConv & Sema::ReferenceConversions::Function)
Sequence.AddQualificationConversionStep(cv1T1, VK);
+ else if (RefConv & Sema::ReferenceConversions::Qualification) {
+ if (!S.Context.hasSameType(cv1T4, cv1T1))
+ Sequence.AddQualificationConversionStep(cv1T1, VK);
+ }
return OR_Success;
}
@@ -4700,17 +4681,15 @@ static void TryReferenceInitializationCore(Sema &S,
InitializationSequence &Sequence) {
QualType DestType = Entity.getType();
SourceLocation DeclLoc = Initializer->getBeginLoc();
+
// Compute some basic properties of the types and the initializer.
bool isLValueRef = DestType->isLValueReferenceType();
bool isRValueRef = !isLValueRef;
- bool DerivedToBase = false;
- bool ObjCConversion = false;
- bool ObjCLifetimeConversion = false;
- bool FunctionConversion = false;
Expr::Classification InitCategory = Initializer->Classify(S.Context);
- Sema::ReferenceCompareResult RefRelationship = S.CompareReferenceRelationship(
- DeclLoc, cv1T1, cv2T2, DerivedToBase, ObjCConversion,
- ObjCLifetimeConversion, FunctionConversion);
+
+ Sema::ReferenceConversions RefConv;
+ Sema::ReferenceCompareResult RefRelationship =
+ S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, &RefConv);
// C++0x [dcl.init.ref]p5:
// A reference to type "cv1 T1" is initialized by an expression of type
@@ -4730,19 +4709,25 @@ static void TryReferenceInitializationCore(Sema &S,
RefRelationship == Sema::Ref_Related))) {
// - is an lvalue (but is not a bit-field), and "cv1 T1" is
// reference-compatible with "cv2 T2," or
- if (T1Quals != T2Quals)
- // Convert to cv1 T2. This should only add qualifiers unless this is a
- // c-style cast. The removal of qualifiers in that case notionally
- // happens after the reference binding, but that doesn't matter.
- Sequence.AddQualificationConversionStep(
- S.Context.getQualifiedType(T2, T1Quals),
- Initializer->getValueKind());
- if (DerivedToBase)
- Sequence.AddDerivedToBaseCastStep(cv1T1, VK_LValue);
- else if (ObjCConversion)
- Sequence.AddObjCObjectConversionStep(cv1T1);
- else if (FunctionConversion)
- Sequence.AddQualificationConversionStep(cv1T1, VK_LValue);
+ if (RefConv & (Sema::ReferenceConversions::DerivedToBase |
+ Sema::ReferenceConversions::ObjC)) {
+ // If we're converting the pointee, add any qualifiers first;
+ // these qualifiers must all be top-level, so just convert to "cv1 T2".
+ if (RefConv & (Sema::ReferenceConversions::Qualification))
+ Sequence.AddQualificationConversionStep(
+ S.Context.getQualifiedType(T2, T1Quals),
+ Initializer->getValueKind());
+ if (RefConv & Sema::ReferenceConversions::DerivedToBase)
+ Sequence.AddDerivedToBaseCastStep(cv1T1, VK_LValue);
+ else
+ Sequence.AddObjCObjectConversionStep(cv1T1);
+ } else if (RefConv & (Sema::ReferenceConversions::Qualification |
+ Sema::ReferenceConversions::Function)) {
+ // Perform a (possibly multi-level) qualification conversion.
+ // FIXME: Should we use a different step kind for function conversions?
+ Sequence.AddQualificationConversionStep(cv1T1,
+ Initializer->getValueKind());
+ }
// We only create a temporary here when binding a reference to a
// bit-field or vector element. Those cases are't supposed to be
@@ -4873,14 +4858,19 @@ static void TryReferenceInitializationCore(Sema &S,
T4Quals.addAddressSpace(T1Quals.getAddressSpace());
QualType cv1T4WithAS = S.Context.getQualifiedType(T2, T4Quals);
Sequence.AddQualificationConversionStep(cv1T4WithAS, ValueKind);
+ cv1T4 = cv1T4WithAS;
}
// In any case, the reference is bound to the resulting glvalue (or to
// an appropriate base class subobject).
- if (DerivedToBase)
+ if (RefConv & Sema::ReferenceConversions::DerivedToBase)
Sequence.AddDerivedToBaseCastStep(cv1T1, ValueKind);
- else if (ObjCConversion)
+ else if (RefConv & Sema::ReferenceConversions::ObjC)
Sequence.AddObjCObjectConversionStep(cv1T1);
+ else if (RefConv & Sema::ReferenceConversions::Qualification) {
+ if (!S.Context.hasSameType(cv1T4, cv1T1))
+ Sequence.AddQualificationConversionStep(cv1T1, ValueKind);
+ }
return;
}
@@ -5157,7 +5147,7 @@ static void TryUserDefinedConversion(Sema &S,
continue;
if (!Info.Constructor->isInvalidDecl() &&
- Info.Constructor->isConvertingConstructor(AllowExplicit)) {
+ Info.Constructor->isConvertingConstructor(/*AllowExplicit*/true)) {
if (Info.ConstructorTmpl)
S.AddTemplateOverloadCandidate(
Info.ConstructorTmpl, Info.FoundDecl,
@@ -5201,16 +5191,14 @@ static void TryUserDefinedConversion(Sema &S,
else
Conv = cast<CXXConversionDecl>(D);
- if (AllowExplicit || !Conv->isExplicit()) {
- if (ConvTemplate)
- S.AddTemplateConversionCandidate(
- ConvTemplate, I.getPair(), ActingDC, Initializer, DestType,
- CandidateSet, AllowExplicit, AllowExplicit);
- else
- S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Initializer,
- DestType, CandidateSet, AllowExplicit,
- AllowExplicit);
- }
+ if (ConvTemplate)
+ S.AddTemplateConversionCandidate(
+ ConvTemplate, I.getPair(), ActingDC, Initializer, DestType,
+ CandidateSet, AllowExplicit, AllowExplicit);
+ else
+ S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Initializer,
+ DestType, CandidateSet, AllowExplicit,
+ AllowExplicit);
}
}
}
@@ -6154,7 +6142,7 @@ static ExprResult CopyObject(Sema &S,
<< (int)Entity.getKind()
<< CurInitExpr->getType()
<< CurInitExpr->getSourceRange()),
- S, OCD_ViableCandidates, CurInitExpr);
+ S, OCD_AmbiguousCandidates, CurInitExpr);
return ExprError();
case OR_Deleted:
@@ -6295,7 +6283,7 @@ static void CheckCXX98CompatAccessibleCopy(Sema &S,
case OR_Ambiguous:
CandidateSet.NoteCandidates(PartialDiagnosticAt(Loc, Diag), S,
- OCD_ViableCandidates, CurInitExpr);
+ OCD_AmbiguousCandidates, CurInitExpr);
break;
case OR_Deleted:
@@ -6653,6 +6641,7 @@ struct IndirectLocalPathEntry {
VarInit,
LValToRVal,
LifetimeBoundCall,
+ GslReferenceInit,
GslPointerInit
} Kind;
Expr *E;
@@ -6783,12 +6772,24 @@ static bool shouldTrackFirstArgument(const FunctionDecl *FD) {
static void handleGslAnnotatedTypes(IndirectLocalPath &Path, Expr *Call,
LocalVisitor Visit) {
- auto VisitPointerArg = [&](const Decl *D, Expr *Arg) {
+ auto VisitPointerArg = [&](const Decl *D, Expr *Arg, bool Value) {
// We are not interested in the temporary base objects of gsl Pointers:
// Temp().ptr; // Here ptr might not dangle.
if (isa<MemberExpr>(Arg->IgnoreImpCasts()))
return;
- Path.push_back({IndirectLocalPathEntry::GslPointerInit, Arg, D});
+ // Once we initialized a value with a reference, it can no longer dangle.
+ if (!Value) {
+ for (auto It = Path.rbegin(), End = Path.rend(); It != End; ++It) {
+ if (It->Kind == IndirectLocalPathEntry::GslReferenceInit)
+ continue;
+ if (It->Kind == IndirectLocalPathEntry::GslPointerInit)
+ return;
+ break;
+ }
+ }
+ Path.push_back({Value ? IndirectLocalPathEntry::GslPointerInit
+ : IndirectLocalPathEntry::GslReferenceInit,
+ Arg, D});
if (Arg->isGLValue())
visitLocalsRetainedByReferenceBinding(Path, Arg, RK_ReferenceBinding,
Visit,
@@ -6802,18 +6803,21 @@ static void handleGslAnnotatedTypes(IndirectLocalPath &Path, Expr *Call,
if (auto *MCE = dyn_cast<CXXMemberCallExpr>(Call)) {
const auto *MD = cast_or_null<CXXMethodDecl>(MCE->getDirectCallee());
if (MD && shouldTrackImplicitObjectArg(MD))
- VisitPointerArg(MD, MCE->getImplicitObjectArgument());
+ VisitPointerArg(MD, MCE->getImplicitObjectArgument(),
+ !MD->getReturnType()->isReferenceType());
return;
} else if (auto *OCE = dyn_cast<CXXOperatorCallExpr>(Call)) {
FunctionDecl *Callee = OCE->getDirectCallee();
if (Callee && Callee->isCXXInstanceMember() &&
shouldTrackImplicitObjectArg(cast<CXXMethodDecl>(Callee)))
- VisitPointerArg(Callee, OCE->getArg(0));
+ VisitPointerArg(Callee, OCE->getArg(0),
+ !Callee->getReturnType()->isReferenceType());
return;
} else if (auto *CE = dyn_cast<CallExpr>(Call)) {
FunctionDecl *Callee = CE->getDirectCallee();
if (Callee && shouldTrackFirstArgument(Callee))
- VisitPointerArg(Callee, CE->getArg(0));
+ VisitPointerArg(Callee, CE->getArg(0),
+ !Callee->getReturnType()->isReferenceType());
return;
}
@@ -6821,7 +6825,7 @@ static void handleGslAnnotatedTypes(IndirectLocalPath &Path, Expr *Call,
const auto *Ctor = CCE->getConstructor();
const CXXRecordDecl *RD = Ctor->getParent();
if (CCE->getNumArgs() > 0 && RD->hasAttr<PointerAttr>())
- VisitPointerArg(Ctor->getParamDecl(0), CCE->getArgs()[0]);
+ VisitPointerArg(Ctor->getParamDecl(0), CCE->getArgs()[0], true);
}
}
@@ -6946,8 +6950,8 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(Init)) {
if (Visit(Path, Local(MTE), RK))
- visitLocalsRetainedByInitializer(Path, MTE->GetTemporaryExpr(), Visit,
- true, EnableLifetimeWarnings);
+ visitLocalsRetainedByInitializer(Path, MTE->getSubExpr(), Visit, true,
+ EnableLifetimeWarnings);
}
if (isa<CallExpr>(Init)) {
@@ -7067,9 +7071,8 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
}
} else if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(L)) {
if (MTE->getType().isConstQualified())
- visitLocalsRetainedByInitializer(Path, MTE->GetTemporaryExpr(),
- Visit, true,
- EnableLifetimeWarnings);
+ visitLocalsRetainedByInitializer(Path, MTE->getSubExpr(), Visit,
+ true, EnableLifetimeWarnings);
}
return false;
}, EnableLifetimeWarnings);
@@ -7288,6 +7291,7 @@ static SourceRange nextPathEntryRange(const IndirectLocalPath &Path, unsigned I,
case IndirectLocalPathEntry::AddressOf:
case IndirectLocalPathEntry::LValToRVal:
case IndirectLocalPathEntry::LifetimeBoundCall:
+ case IndirectLocalPathEntry::GslReferenceInit:
case IndirectLocalPathEntry::GslPointerInit:
// These exist primarily to mark the path as not permitting or
// supporting lifetime extension.
@@ -7310,7 +7314,8 @@ static bool pathOnlyInitializesGslPointer(IndirectLocalPath &Path) {
continue;
if (It->Kind == IndirectLocalPathEntry::AddressOf)
continue;
- return It->Kind == IndirectLocalPathEntry::GslPointerInit;
+ return It->Kind == IndirectLocalPathEntry::GslPointerInit ||
+ It->Kind == IndirectLocalPathEntry::GslReferenceInit;
}
return false;
}
@@ -7533,6 +7538,7 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
case IndirectLocalPathEntry::LifetimeBoundCall:
case IndirectLocalPathEntry::GslPointerInit:
+ case IndirectLocalPathEntry::GslReferenceInit:
// FIXME: Consider adding a note for these.
break;
@@ -7835,9 +7841,8 @@ ExprResult InitializationSequence::Perform(Sema &S,
// OpenCL v2.0 s6.13.11.1. atomic variables can be initialized in global scope
QualType ETy = Entity.getType();
- Qualifiers TyQualifiers = ETy.getQualifiers();
- bool HasGlobalAS = TyQualifiers.hasAddressSpace() &&
- TyQualifiers.getAddressSpace() == LangAS::opencl_global;
+ bool HasGlobalAS = ETy.hasAddressSpace() &&
+ ETy.getAddressSpace() == LangAS::opencl_global;
if (S.getLangOpts().OpenCLVersion >= 200 &&
ETy->isAtomicType() && !HasGlobalAS &&
@@ -8806,7 +8811,7 @@ bool InitializationSequence::Diagnose(Sema &S,
: (S.PDiag(diag::err_ref_init_ambiguous)
<< DestType << OnlyArg->getType()
<< Args[0]->getSourceRange())),
- S, OCD_ViableCandidates, Args);
+ S, OCD_AmbiguousCandidates, Args);
break;
case OR_No_Viable_Function: {
@@ -8906,11 +8911,17 @@ bool InitializationSequence::Diagnose(Sema &S,
S.Diag(Kind.getLocation(), diag::err_reference_bind_drops_quals)
<< NonRefType << SourceType << 1 /*addr space*/
<< Args[0]->getSourceRange();
- else
+ else if (DroppedQualifiers.hasQualifiers())
S.Diag(Kind.getLocation(), diag::err_reference_bind_drops_quals)
<< NonRefType << SourceType << 0 /*cv quals*/
<< Qualifiers::fromCVRMask(DroppedQualifiers.getCVRQualifiers())
<< DroppedQualifiers.getCVRQualifiers() << Args[0]->getSourceRange();
+ else
+ // FIXME: Consider decomposing the type and explaining which qualifiers
+ // were dropped where, or on which level a 'const' is missing, etc.
+ S.Diag(Kind.getLocation(), diag::err_reference_bind_drops_quals)
+ << NonRefType << SourceType << 2 /*incompatible quals*/
+ << Args[0]->getSourceRange();
break;
}
@@ -9000,7 +9011,7 @@ bool InitializationSequence::Diagnose(Sema &S,
PartialDiagnosticAt(Kind.getLocation(),
S.PDiag(diag::err_ovl_ambiguous_init)
<< DestType << ArgsRange),
- S, OCD_ViableCandidates, Args);
+ S, OCD_AmbiguousCandidates, Args);
break;
case OR_No_Viable_Function:
@@ -9765,9 +9776,8 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
// C++ [over.match.copy]p1: (non-list copy-initialization from class)
// The converting constructors of T are candidate functions.
if (!AllowExplicit) {
- // Only consider converting constructors.
- if (GD->isExplicit())
- continue;
+ // Overload resolution checks whether the deduction guide is declared
+ // explicit for us.
// When looking for a converting constructor, deduction guides that
// could never be called with one argument are not interesting to
@@ -9863,7 +9873,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
Kind.getLocation(),
PDiag(diag::err_deduced_class_template_ctor_ambiguous)
<< TemplateName),
- *this, OCD_ViableCandidates, Inits);
+ *this, OCD_AmbiguousCandidates, Inits);
return QualType();
case OR_No_Viable_Function: {
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index c6b19a0b195c..c2d14a44f53d 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -361,7 +361,8 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
TypeSourceInfo *MethodTypeInfo,
SourceLocation EndLoc,
ArrayRef<ParmVarDecl *> Params,
- ConstexprSpecKind ConstexprKind) {
+ ConstexprSpecKind ConstexprKind,
+ Expr *TrailingRequiresClause) {
QualType MethodType = MethodTypeInfo->getType();
TemplateParameterList *TemplateParams =
getGenericLambdaTemplateParameterList(getCurLambda(), *this);
@@ -395,7 +396,7 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
DeclarationNameInfo(MethodName, IntroducerRange.getBegin(),
MethodNameLoc),
MethodType, MethodTypeInfo, SC_None,
- /*isInline=*/true, ConstexprKind, EndLoc);
+ /*isInline=*/true, ConstexprKind, EndLoc, TrailingRequiresClause);
Method->setAccess(AS_public);
if (!TemplateParams)
Class->addDecl(Method);
@@ -917,6 +918,10 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
/*IsVariadic=*/false, /*IsCXXMethod=*/true));
EPI.HasTrailingReturn = true;
EPI.TypeQuals.addConst();
+ LangAS AS = getDefaultCXXMethodAddrSpace();
+ if (AS != LangAS::Default)
+ EPI.TypeQuals.addAddressSpace(AS);
+
// C++1y [expr.prim.lambda]:
// The lambda return type is 'auto', which is replaced by the
// trailing-return type if provided and/or deduced from 'return'
@@ -968,7 +973,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
KnownDependent, Intro.Default);
CXXMethodDecl *Method =
startLambdaDefinition(Class, Intro.Range, MethodTyInfo, EndLoc, Params,
- ParamInfo.getDeclSpec().getConstexprSpecifier());
+ ParamInfo.getDeclSpec().getConstexprSpecifier(),
+ ParamInfo.getTrailingRequiresClause());
if (ExplicitParams)
CheckCXXDefaultArguments(Method);
@@ -1248,7 +1254,7 @@ void Sema::ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope,
SmallVector<Decl*, 4> Fields(Class->fields());
ActOnFields(nullptr, Class->getLocation(), Class, Fields, SourceLocation(),
SourceLocation(), ParsedAttributesView());
- CheckCompletedCXXClass(Class);
+ CheckCompletedCXXClass(nullptr, Class);
PopFunctionScopeInfo();
}
@@ -1794,7 +1800,7 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
SmallVector<Decl*, 4> Fields(Class->fields());
ActOnFields(nullptr, Class->getLocation(), Class, Fields, SourceLocation(),
SourceLocation(), ParsedAttributesView());
- CheckCompletedCXXClass(Class);
+ CheckCompletedCXXClass(nullptr, Class);
}
Cleanup.mergeFrom(LambdaCleanup);
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index d56c5980237c..0ed51de0cc13 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -739,6 +739,18 @@ static void GetOpenCLBuiltinFctOverloads(
}
}
+/// Add extensions to the function declaration.
+/// \param S (in/out) The Sema instance.
+/// \param BIDecl (in) Description of the builtin.
+/// \param FDecl (in/out) FunctionDecl instance.
+static void AddOpenCLExtensions(Sema &S, const OpenCLBuiltinStruct &BIDecl,
+ FunctionDecl *FDecl) {
+ // Fetch extension associated with a function prototype.
+ StringRef E = FunctionExtensionTable[BIDecl.Extension];
+ if (E != "")
+ S.setOpenCLExtensionForDecl(FDecl, E);
+}
+
/// When trying to resolve a function name, if isOpenCLBuiltin() returns a
/// non-null <Index, Len> pair, then the name is referencing an OpenCL
/// builtin function. Add all candidate signatures to the LookUpResult.
@@ -765,10 +777,13 @@ static void InsertOCLBuiltinDeclarationsFromTable(Sema &S, LookupResult &LR,
ASTContext &Context = S.Context;
// Ignore this BIF if its version does not match the language options.
- if (Context.getLangOpts().OpenCLVersion < OpenCLBuiltin.MinVersion)
+ unsigned OpenCLVersion = Context.getLangOpts().OpenCLVersion;
+ if (Context.getLangOpts().OpenCLCPlusPlus)
+ OpenCLVersion = 200;
+ if (OpenCLVersion < OpenCLBuiltin.MinVersion)
continue;
if ((OpenCLBuiltin.MaxVersion != 0) &&
- (Context.getLangOpts().OpenCLVersion >= OpenCLBuiltin.MaxVersion))
+ (OpenCLVersion >= OpenCLBuiltin.MaxVersion))
continue;
SmallVector<QualType, 1> RetTypes;
@@ -812,9 +827,20 @@ static void InsertOCLBuiltinDeclarationsFromTable(Sema &S, LookupResult &LR,
}
NewOpenCLBuiltin->setParams(ParmList);
}
- if (!S.getLangOpts().OpenCLCPlusPlus) {
+
+ // Add function attributes.
+ if (OpenCLBuiltin.IsPure)
+ NewOpenCLBuiltin->addAttr(PureAttr::CreateImplicit(Context));
+ if (OpenCLBuiltin.IsConst)
+ NewOpenCLBuiltin->addAttr(ConstAttr::CreateImplicit(Context));
+ if (OpenCLBuiltin.IsConv)
+ NewOpenCLBuiltin->addAttr(ConvergentAttr::CreateImplicit(Context));
+
+ if (!S.getLangOpts().OpenCLCPlusPlus)
NewOpenCLBuiltin->addAttr(OverloadableAttr::CreateImplicit(Context));
- }
+
+ AddOpenCLExtensions(S, OpenCLBuiltin, NewOpenCLBuiltin);
+
LR.addDecl(NewOpenCLBuiltin);
}
}
@@ -3101,11 +3127,10 @@ Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *RD,
});
}
CXXDestructorDecl *DD = RD->getDestructor();
- assert(DD && "record without a destructor");
Result->setMethod(DD);
- Result->setKind(DD->isDeleted() ?
- SpecialMemberOverloadResult::NoMemberOrDeleted :
- SpecialMemberOverloadResult::Success);
+ Result->setKind(DD && !DD->isDeleted()
+ ? SpecialMemberOverloadResult::Success
+ : SpecialMemberOverloadResult::NoMemberOrDeleted);
return *Result;
}
diff --git a/clang/lib/Sema/SemaModule.cpp b/clang/lib/Sema/SemaModule.cpp
index 1fca351bfb09..10de0ca91221 100644
--- a/clang/lib/Sema/SemaModule.cpp
+++ b/clang/lib/Sema/SemaModule.cpp
@@ -31,8 +31,6 @@ static void checkModuleImportContext(Sema &S, Module *M,
ExternCLoc = LSD->getBeginLoc();
break;
case LinkageSpecDecl::lang_cxx:
- case LinkageSpecDecl::lang_cxx_11:
- case LinkageSpecDecl::lang_cxx_14:
break;
}
DC = LSD->getParent();
diff --git a/clang/lib/Sema/SemaObjCProperty.cpp b/clang/lib/Sema/SemaObjCProperty.cpp
index ac810745d2f5..f6717f4cbe5e 100644
--- a/clang/lib/Sema/SemaObjCProperty.cpp
+++ b/clang/lib/Sema/SemaObjCProperty.cpp
@@ -306,6 +306,8 @@ makePropertyAttributesAsWritten(unsigned Attributes) {
attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_atomic;
if (Attributes & ObjCDeclSpec::DQ_PR_class)
attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_class;
+ if (Attributes & ObjCDeclSpec::DQ_PR_direct)
+ attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_direct;
return (ObjCPropertyDecl::PropertyAttributeKind)attributesAsWritten;
}
@@ -705,9 +707,21 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,
if (Attributes & ObjCDeclSpec::DQ_PR_null_resettable)
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_null_resettable);
- if (Attributes & ObjCDeclSpec::DQ_PR_class)
+ if (Attributes & ObjCDeclSpec::DQ_PR_class)
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_class);
+ if ((Attributes & ObjCDeclSpec::DQ_PR_direct) ||
+ CDecl->hasAttr<ObjCDirectMembersAttr>()) {
+ if (isa<ObjCProtocolDecl>(CDecl)) {
+ Diag(PDecl->getLocation(), diag::err_objc_direct_on_protocol) << true;
+ } else if (getLangOpts().ObjCRuntime.allowsDirectDispatch()) {
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_direct);
+ } else {
+ Diag(PDecl->getLocation(), diag::warn_objc_direct_property_ignored)
+ << PDecl->getDeclName();
+ }
+ }
+
return PDecl;
}
@@ -1037,6 +1051,33 @@ static bool hasWrittenStorageAttribute(ObjCPropertyDecl *Prop,
return false;
}
+/// Create a synthesized property accessor stub inside the \@implementation.
+static ObjCMethodDecl *
+RedeclarePropertyAccessor(ASTContext &Context, ObjCImplementationDecl *Impl,
+ ObjCMethodDecl *AccessorDecl, SourceLocation AtLoc,
+ SourceLocation PropertyLoc) {
+ ObjCMethodDecl *Decl = AccessorDecl;
+ ObjCMethodDecl *ImplDecl = ObjCMethodDecl::Create(
+ Context, AtLoc.isValid() ? AtLoc : Decl->getBeginLoc(),
+ PropertyLoc.isValid() ? PropertyLoc : Decl->getEndLoc(),
+ Decl->getSelector(), Decl->getReturnType(),
+ Decl->getReturnTypeSourceInfo(), Impl, Decl->isInstanceMethod(),
+ Decl->isVariadic(), Decl->isPropertyAccessor(),
+ /* isSynthesized*/ true, Decl->isImplicit(), Decl->isDefined(),
+ Decl->getImplementationControl(), Decl->hasRelatedResultType());
+ ImplDecl->getMethodFamily();
+ if (Decl->hasAttrs())
+ ImplDecl->setAttrs(Decl->getAttrs());
+ ImplDecl->setSelfDecl(Decl->getSelfDecl());
+ ImplDecl->setCmdDecl(Decl->getCmdDecl());
+ SmallVector<SourceLocation, 1> SelLocs;
+ Decl->getSelectorLocs(SelLocs);
+ ImplDecl->setMethodParams(Context, Decl->parameters(), SelLocs);
+ ImplDecl->setLexicalDeclContext(Impl);
+ ImplDecl->setDefined(false);
+ return ImplDecl;
+}
+
/// ActOnPropertyImplDecl - This routine performs semantic checks and
/// builds the AST node for a property implementation declaration; declared
/// as \@synthesize or \@dynamic.
@@ -1404,6 +1445,18 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
if (ObjCMethodDecl *getterMethod = property->getGetterMethodDecl()) {
getterMethod->createImplicitParams(Context, IDecl);
+
+ // Redeclare the getter within the implementation as DeclContext.
+ if (Synthesize) {
+ // If the method hasn't been overridden, create a synthesized implementation.
+ ObjCMethodDecl *OMD = ClassImpDecl->getMethod(
+ getterMethod->getSelector(), getterMethod->isInstanceMethod());
+ if (!OMD)
+ OMD = RedeclarePropertyAccessor(Context, IC, getterMethod, AtLoc,
+ PropertyLoc);
+ PIDecl->setGetterMethodDecl(OMD);
+ }
+
if (getLangOpts().CPlusPlus && Synthesize && !CompleteTypeErr &&
Ivar->getType()->isRecordType()) {
// For Objective-C++, need to synthesize the AST for the IVAR object to be
@@ -1456,8 +1509,20 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
break;
}
}
+
if (ObjCMethodDecl *setterMethod = property->getSetterMethodDecl()) {
setterMethod->createImplicitParams(Context, IDecl);
+
+ // Redeclare the setter within the implementation as DeclContext.
+ if (Synthesize) {
+ ObjCMethodDecl *OMD = ClassImpDecl->getMethod(
+ setterMethod->getSelector(), setterMethod->isInstanceMethod());
+ if (!OMD)
+ OMD = RedeclarePropertyAccessor(Context, IC, setterMethod,
+ AtLoc, PropertyLoc);
+ PIDecl->setSetterMethodDecl(OMD);
+ }
+
if (getLangOpts().CPlusPlus && Synthesize && !CompleteTypeErr &&
Ivar->getType()->isRecordType()) {
// FIXME. Eventually we want to do this for Objective-C as well.
@@ -1852,10 +1917,12 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl *IMPDecl,
if (IMPDecl->FindPropertyImplDecl(
Prop->getIdentifier(), Prop->getQueryKind()))
continue;
- if (IMPDecl->getInstanceMethod(Prop->getGetterName())) {
+ ObjCMethodDecl *ImpMethod = IMPDecl->getInstanceMethod(Prop->getGetterName());
+ if (ImpMethod && !ImpMethod->getBody()) {
if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readonly)
continue;
- if (IMPDecl->getInstanceMethod(Prop->getSetterName()))
+ ImpMethod = IMPDecl->getInstanceMethod(Prop->getSetterName());
+ if (ImpMethod && !ImpMethod->getBody())
continue;
}
if (ObjCPropertyImplDecl *PID =
@@ -2083,7 +2150,6 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
void Sema::diagnoseNullResettableSynthesizedSetters(const ObjCImplDecl *impDecl) {
for (const auto *propertyImpl : impDecl->property_impls()) {
const auto *property = propertyImpl->getPropertyDecl();
-
// Warn about null_resettable properties with synthesized setters,
// because the setter won't properly handle nil.
if (propertyImpl->getPropertyImplementation()
@@ -2092,16 +2158,16 @@ void Sema::diagnoseNullResettableSynthesizedSetters(const ObjCImplDecl *impDecl)
ObjCPropertyDecl::OBJC_PR_null_resettable) &&
property->getGetterMethodDecl() &&
property->getSetterMethodDecl()) {
- auto *getterMethod = property->getGetterMethodDecl();
- auto *setterMethod = property->getSetterMethodDecl();
- if (!impDecl->getInstanceMethod(setterMethod->getSelector()) &&
- !impDecl->getInstanceMethod(getterMethod->getSelector())) {
+ auto *getterImpl = propertyImpl->getGetterMethodDecl();
+ auto *setterImpl = propertyImpl->getSetterMethodDecl();
+ if ((!getterImpl || getterImpl->isSynthesizedAccessorStub()) &&
+ (!setterImpl || setterImpl->isSynthesizedAccessorStub())) {
SourceLocation loc = propertyImpl->getLocation();
if (loc.isInvalid())
loc = impDecl->getBeginLoc();
Diag(loc, diag::warn_null_resettable_setter)
- << setterMethod->getSelector() << property->getDeclName();
+ << setterImpl->getSelector() << property->getDeclName();
}
}
}
@@ -2125,7 +2191,6 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl,
const ObjCPropertyDecl *Property = I->second;
ObjCMethodDecl *GetterMethod = nullptr;
ObjCMethodDecl *SetterMethod = nullptr;
- bool LookedUpGetterSetter = false;
unsigned Attributes = Property->getPropertyAttributes();
unsigned AttributesAsWritten = Property->getPropertyAttributesAsWritten();
@@ -2138,7 +2203,10 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl,
SetterMethod = Property->isClassProperty() ?
IMPDecl->getClassMethod(Property->getSetterName()) :
IMPDecl->getInstanceMethod(Property->getSetterName());
- LookedUpGetterSetter = true;
+ if (GetterMethod && GetterMethod->isSynthesizedAccessorStub())
+ GetterMethod = nullptr;
+ if (SetterMethod && SetterMethod->isSynthesizedAccessorStub())
+ SetterMethod = nullptr;
if (GetterMethod) {
Diag(GetterMethod->getLocation(),
diag::warn_default_atomic_custom_getter_setter)
@@ -2161,15 +2229,13 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl,
Property->getIdentifier(), Property->getQueryKind())) {
if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
continue;
- if (!LookedUpGetterSetter) {
- GetterMethod = Property->isClassProperty() ?
- IMPDecl->getClassMethod(Property->getGetterName()) :
- IMPDecl->getInstanceMethod(Property->getGetterName());
- SetterMethod = Property->isClassProperty() ?
- IMPDecl->getClassMethod(Property->getSetterName()) :
- IMPDecl->getInstanceMethod(Property->getSetterName());
- }
- if ((GetterMethod && !SetterMethod) || (!GetterMethod && SetterMethod)) {
+ GetterMethod = PIDecl->getGetterMethodDecl();
+ SetterMethod = PIDecl->getSetterMethodDecl();
+ if (GetterMethod && GetterMethod->isSynthesizedAccessorStub())
+ GetterMethod = nullptr;
+ if (SetterMethod && SetterMethod->isSynthesizedAccessorStub())
+ SetterMethod = nullptr;
+ if ((bool)GetterMethod ^ (bool)SetterMethod) {
SourceLocation MethodLoc =
(GetterMethod ? GetterMethod->getLocation()
: SetterMethod->getLocation());
@@ -2210,8 +2276,10 @@ void Sema::DiagnoseOwningPropertyGetterSynthesis(const ObjCImplementationDecl *D
for (const auto *PID : D->property_impls()) {
const ObjCPropertyDecl *PD = PID->getPropertyDecl();
if (PD && !PD->hasAttr<NSReturnsNotRetainedAttr>() &&
- !PD->isClassProperty() &&
- !D->getInstanceMethod(PD->getGetterName())) {
+ !PD->isClassProperty()) {
+ ObjCMethodDecl *IM = PID->getGetterMethodDecl();
+ if (IM && !IM->isSynthesizedAccessorStub())
+ continue;
ObjCMethodDecl *method = PD->getGetterMethodDecl();
if (!method)
continue;
@@ -2396,20 +2464,21 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
}
}
- GetterMethod = ObjCMethodDecl::Create(Context, Loc, Loc,
- property->getGetterName(),
- resultTy, nullptr, CD,
- !IsClassProperty, /*isVariadic=*/false,
- /*isPropertyAccessor=*/true,
- /*isImplicitlyDeclared=*/true, /*isDefined=*/false,
- (property->getPropertyImplementation() ==
- ObjCPropertyDecl::Optional) ?
- ObjCMethodDecl::Optional :
- ObjCMethodDecl::Required);
+ GetterMethod = ObjCMethodDecl::Create(
+ Context, Loc, Loc, property->getGetterName(), resultTy, nullptr, CD,
+ !IsClassProperty, /*isVariadic=*/false,
+ /*isPropertyAccessor=*/true, /*isSynthesizedAccessorStub=*/false,
+ /*isImplicitlyDeclared=*/true, /*isDefined=*/false,
+ (property->getPropertyImplementation() == ObjCPropertyDecl::Optional)
+ ? ObjCMethodDecl::Optional
+ : ObjCMethodDecl::Required);
CD->addDecl(GetterMethod);
AddPropertyAttrs(*this, GetterMethod, property);
+ if (property->isDirectProperty())
+ GetterMethod->addAttr(ObjCDirectAttr::CreateImplicit(Context, Loc));
+
if (property->hasAttr<NSReturnsNotRetainedAttr>())
GetterMethod->addAttr(NSReturnsNotRetainedAttr::CreateImplicit(Context,
Loc));
@@ -2429,6 +2498,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
// A user declared getter will be synthesize when @synthesize of
// the property with the same name is seen in the @implementation
GetterMethod->setPropertyAccessor(true);
+
+ GetterMethod->createImplicitParams(Context,
+ GetterMethod->getClassInterface());
property->setGetterMethodDecl(GetterMethod);
// Skip setter if property is read-only.
@@ -2447,6 +2519,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
nullptr, CD, !IsClassProperty,
/*isVariadic=*/false,
/*isPropertyAccessor=*/true,
+ /*isSynthesizedAccessorStub=*/false,
/*isImplicitlyDeclared=*/true,
/*isDefined=*/false,
(property->getPropertyImplementation() ==
@@ -2483,6 +2556,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
AddPropertyAttrs(*this, SetterMethod, property);
+ if (property->isDirectProperty())
+ SetterMethod->addAttr(ObjCDirectAttr::CreateImplicit(Context, Loc));
+
CD->addDecl(SetterMethod);
if (const SectionAttr *SA = property->getAttr<SectionAttr>())
SetterMethod->addAttr(SectionAttr::CreateImplicit(
@@ -2496,6 +2572,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
// A user declared setter will be synthesize when @synthesize of
// the property with the same name is seen in the @implementation
SetterMethod->setPropertyAccessor(true);
+
+ SetterMethod->createImplicitParams(Context,
+ SetterMethod->getClassInterface());
property->setSetterMethodDecl(SetterMethod);
}
// Add any synthesized methods to the global pool. This allows us to
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index c7e0d2aee036..3fce0e27e9b3 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -23,13 +23,17 @@
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/TypeOrdering.h"
#include "clang/Basic/OpenMPKinds.h"
+#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaInternal.h"
+#include "llvm/ADT/IndexedMap.h"
#include "llvm/ADT/PointerEmbeddedInt.h"
+#include "llvm/Frontend/OpenMP/OMPConstants.h"
using namespace clang;
+using namespace llvm::omp;
//===----------------------------------------------------------------------===//
// Stack of data-sharing attributes for variables
@@ -48,12 +52,6 @@ enum DefaultDataSharingAttributes {
DSA_shared = 1 << 1, /// Default data sharing attribute 'shared'.
};
-/// Attributes of the defaultmap clause.
-enum DefaultMapAttributes {
- DMA_unspecified, /// Default mapping is not specified.
- DMA_tofrom_scalar, /// Default mapping is 'tofrom:scalar'.
-};
-
/// Stack for tracking declarations used in OpenMP directives and
/// clauses and their data-sharing attributes.
class DSAStackTy {
@@ -85,7 +83,7 @@ private:
DeclRefExpr *PrivateCopy = nullptr;
};
using DeclSAMapTy = llvm::SmallDenseMap<const ValueDecl *, DSAInfo, 8>;
- using AlignedMapTy = llvm::SmallDenseMap<const ValueDecl *, const Expr *, 8>;
+ using UsedRefMapTy = llvm::SmallDenseMap<const ValueDecl *, const Expr *, 8>;
using LCDeclInfo = std::pair<unsigned, VarDecl *>;
using LoopControlVariablesMapTy =
llvm::SmallDenseMap<const ValueDecl *, LCDeclInfo, 8>;
@@ -115,17 +113,25 @@ private:
};
using DeclReductionMapTy =
llvm::SmallDenseMap<const ValueDecl *, ReductionData, 4>;
+ struct DefaultmapInfo {
+ OpenMPDefaultmapClauseModifier ImplicitBehavior =
+ OMPC_DEFAULTMAP_MODIFIER_unknown;
+ SourceLocation SLoc;
+ DefaultmapInfo() = default;
+ DefaultmapInfo(OpenMPDefaultmapClauseModifier M, SourceLocation Loc)
+ : ImplicitBehavior(M), SLoc(Loc) {}
+ };
struct SharingMapTy {
DeclSAMapTy SharingMap;
DeclReductionMapTy ReductionMap;
- AlignedMapTy AlignedMap;
+ UsedRefMapTy AlignedMap;
+ UsedRefMapTy NontemporalMap;
MappedExprComponentsTy MappedExprComponents;
LoopControlVariablesMapTy LCVMap;
DefaultDataSharingAttributes DefaultAttr = DSA_unspecified;
SourceLocation DefaultAttrLoc;
- DefaultMapAttributes DefaultMapAttr = DMA_unspecified;
- SourceLocation DefaultMapAttrLoc;
+ DefaultmapInfo DefaultmapMap[OMPC_DEFAULTMAP_unknown];
OpenMPDirectiveKind Directive = OMPD_unknown;
DeclarationNameInfo DirectiveName;
Scope *CurScope = nullptr;
@@ -416,6 +422,10 @@ public:
/// add it and return NULL; otherwise return previous occurrence's expression
/// for diagnostics.
const Expr *addUniqueAligned(const ValueDecl *D, const Expr *NewDE);
+ /// If 'nontemporal' declaration for given variable \a D was not seen yet,
+ /// add it and return NULL; otherwise return previous occurrence's expression
+ /// for diagnostics.
+ const Expr *addUniqueNontemporal(const ValueDecl *D, const Expr *NewDE);
/// Register specified variable as loop control variable.
void addLoopControlVariable(const ValueDecl *D, VarDecl *Capture);
@@ -592,10 +602,18 @@ public:
getTopOfStack().DefaultAttr = DSA_shared;
getTopOfStack().DefaultAttrLoc = Loc;
}
- /// Set default data mapping attribute to 'tofrom:scalar'.
- void setDefaultDMAToFromScalar(SourceLocation Loc) {
- getTopOfStack().DefaultMapAttr = DMA_tofrom_scalar;
- getTopOfStack().DefaultMapAttrLoc = Loc;
+ /// Set default data mapping attribute to Modifier:Kind
+ void setDefaultDMAAttr(OpenMPDefaultmapClauseModifier M,
+ OpenMPDefaultmapClauseKind Kind,
+ SourceLocation Loc) {
+ DefaultmapInfo &DMI = getTopOfStack().DefaultmapMap[Kind];
+ DMI.ImplicitBehavior = M;
+ DMI.SLoc = Loc;
+ }
+ /// Check whether the implicit-behavior has been set in defaultmap
+ bool checkDefaultmapCategory(OpenMPDefaultmapClauseKind VariableCategory) {
+ return getTopOfStack().DefaultmapMap[VariableCategory].ImplicitBehavior !=
+ OMPC_DEFAULTMAP_MODIFIER_unknown;
}
DefaultDataSharingAttributes getDefaultDSA() const {
@@ -606,16 +624,53 @@ public:
return isStackEmpty() ? SourceLocation()
: getTopOfStack().DefaultAttrLoc;
}
- DefaultMapAttributes getDefaultDMA() const {
- return isStackEmpty() ? DMA_unspecified
- : getTopOfStack().DefaultMapAttr;
+ OpenMPDefaultmapClauseModifier
+ getDefaultmapModifier(OpenMPDefaultmapClauseKind Kind) const {
+ return isStackEmpty()
+ ? OMPC_DEFAULTMAP_MODIFIER_unknown
+ : getTopOfStack().DefaultmapMap[Kind].ImplicitBehavior;
+ }
+ OpenMPDefaultmapClauseModifier
+ getDefaultmapModifierAtLevel(unsigned Level,
+ OpenMPDefaultmapClauseKind Kind) const {
+ return getStackElemAtLevel(Level).DefaultmapMap[Kind].ImplicitBehavior;
+ }
+ bool isDefaultmapCapturedByRef(unsigned Level,
+ OpenMPDefaultmapClauseKind Kind) const {
+ OpenMPDefaultmapClauseModifier M =
+ getDefaultmapModifierAtLevel(Level, Kind);
+ if (Kind == OMPC_DEFAULTMAP_scalar || Kind == OMPC_DEFAULTMAP_pointer) {
+ return (M == OMPC_DEFAULTMAP_MODIFIER_alloc) ||
+ (M == OMPC_DEFAULTMAP_MODIFIER_to) ||
+ (M == OMPC_DEFAULTMAP_MODIFIER_from) ||
+ (M == OMPC_DEFAULTMAP_MODIFIER_tofrom);
+ }
+ return true;
+ }
+ static bool mustBeFirstprivateBase(OpenMPDefaultmapClauseModifier M,
+ OpenMPDefaultmapClauseKind Kind) {
+ switch (Kind) {
+ case OMPC_DEFAULTMAP_scalar:
+ case OMPC_DEFAULTMAP_pointer:
+ return (M == OMPC_DEFAULTMAP_MODIFIER_unknown) ||
+ (M == OMPC_DEFAULTMAP_MODIFIER_firstprivate) ||
+ (M == OMPC_DEFAULTMAP_MODIFIER_default);
+ case OMPC_DEFAULTMAP_aggregate:
+ return M == OMPC_DEFAULTMAP_MODIFIER_firstprivate;
+ default:
+ break;
+ }
+ llvm_unreachable("Unexpected OpenMPDefaultmapClauseKind enum");
}
- DefaultMapAttributes getDefaultDMAAtLevel(unsigned Level) const {
- return getStackElemAtLevel(Level).DefaultMapAttr;
+ bool mustBeFirstprivateAtLevel(unsigned Level,
+ OpenMPDefaultmapClauseKind Kind) const {
+ OpenMPDefaultmapClauseModifier M =
+ getDefaultmapModifierAtLevel(Level, Kind);
+ return mustBeFirstprivateBase(M, Kind);
}
- SourceLocation getDefaultDMALocation() const {
- return isStackEmpty() ? SourceLocation()
- : getTopOfStack().DefaultMapAttrLoc;
+ bool mustBeFirstprivate(OpenMPDefaultmapClauseKind Kind) const {
+ OpenMPDefaultmapClauseModifier M = getDefaultmapModifier(Kind);
+ return mustBeFirstprivateBase(M, Kind);
}
/// Checks if the specified variable is a threadprivate.
@@ -862,7 +917,7 @@ static const Expr *getExprAsWritten(const Expr *E) {
E = FE->getSubExpr();
if (const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E))
- E = MTE->GetTemporaryExpr();
+ E = MTE->getSubExpr();
while (const auto *Binder = dyn_cast<CXXBindTemporaryExpr>(E))
E = Binder->getSubExpr();
@@ -1023,6 +1078,21 @@ const Expr *DSAStackTy::addUniqueAligned(const ValueDecl *D,
return It->second;
}
+const Expr *DSAStackTy::addUniqueNontemporal(const ValueDecl *D,
+ const Expr *NewDE) {
+ assert(!isStackEmpty() && "Data sharing attributes stack is empty");
+ D = getCanonicalDecl(D);
+ SharingMapTy &StackElem = getTopOfStack();
+ auto It = StackElem.NontemporalMap.find(D);
+ if (It == StackElem.NontemporalMap.end()) {
+ assert(NewDE && "Unexpected nullptr expr to be added into aligned map");
+ StackElem.NontemporalMap[D] = NewDE;
+ return nullptr;
+ }
+ assert(It->second && "Unexpected nullptr expr in the aligned map");
+ return It->second;
+}
+
void DSAStackTy::addLoopControlVariable(const ValueDecl *D, VarDecl *Capture) {
assert(!isStackEmpty() && "Data-sharing attributes stack is empty");
D = getCanonicalDecl(D);
@@ -1716,6 +1786,20 @@ void Sema::checkOpenMPDeviceExpr(const Expr *E) {
<< Context.getTargetInfo().getTriple().str() << E->getSourceRange();
}
+static OpenMPDefaultmapClauseKind
+getVariableCategoryFromDecl(const LangOptions &LO, const ValueDecl *VD) {
+ if (LO.OpenMP <= 45) {
+ if (VD->getType().getNonReferenceType()->isScalarType())
+ return OMPC_DEFAULTMAP_scalar;
+ return OMPC_DEFAULTMAP_aggregate;
+ }
+ if (VD->getType().getNonReferenceType()->isAnyPointerType())
+ return OMPC_DEFAULTMAP_pointer;
+ if (VD->getType().getNonReferenceType()->isScalarType())
+ return OMPC_DEFAULTMAP_scalar;
+ return OMPC_DEFAULTMAP_aggregate;
+}
+
bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level,
unsigned OpenMPCaptureLevel) const {
assert(LangOpts.OpenMP && "OpenMP is not allowed");
@@ -1834,11 +1918,13 @@ bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level,
} else {
// By default, all the data that has a scalar type is mapped by copy
// (except for reduction variables).
+ // Defaultmap scalar is mutual exclusive to defaultmap pointer
IsByRef =
(DSAStack->isForceCaptureByReferenceInTargetExecutable() &&
!Ty->isAnyPointerType()) ||
!Ty->isScalarType() ||
- DSAStack->getDefaultDMAAtLevel(Level) == DMA_tofrom_scalar ||
+ DSAStack->isDefaultmapCapturedByRef(
+ Level, getVariableCategoryFromDecl(LangOpts, D)) ||
DSAStack->hasExplicitDSA(
D, [](OpenMPClauseKind K) { return K == OMPC_reduction; }, Level);
}
@@ -1894,6 +1980,11 @@ VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D, bool CheckScopeInfo,
assert(LangOpts.OpenMP && "OpenMP is not allowed");
D = getCanonicalDecl(D);
+ auto *VD = dyn_cast<VarDecl>(D);
+ // Do not capture constexpr variables.
+ if (VD && VD->isConstexpr())
+ return nullptr;
+
// If we want to determine whether the variable should be captured from the
// perspective of the current capturing scope, and we've already left all the
// capturing scopes of the top directive on the stack, check from the
@@ -1904,7 +1995,6 @@ VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D, bool CheckScopeInfo,
// If we are attempting to capture a global variable in a directive with
// 'target' we return true so that this global is also mapped to the device.
//
- auto *VD = dyn_cast<VarDecl>(D);
if (VD && !VD->hasLocalStorage() &&
(getCurCapturedRegion() || getCurBlock() || getCurLambda())) {
if (isInOpenMPDeclareTargetContext()) {
@@ -2051,9 +2141,8 @@ void Sema::setOpenMPCaptureKind(FieldDecl *FD, const ValueDecl *D,
if (DSAStack->hasExplicitDirective(isOpenMPTargetExecutionDirective,
NewLevel)) {
OMPC = OMPC_map;
- if (D->getType()->isScalarType() &&
- DSAStack->getDefaultDMAAtLevel(NewLevel) !=
- DefaultMapAttributes::DMA_tofrom_scalar)
+ if (DSAStack->mustBeFirstprivateAtLevel(
+ NewLevel, getVariableCategoryFromDecl(LangOpts, D)))
OMPC = OMPC_firstprivate;
break;
}
@@ -2141,6 +2230,11 @@ void Sema::EndOpenMPClause() {
static void checkAllocateClauses(Sema &S, DSAStackTy *Stack,
ArrayRef<OMPClause *> Clauses);
+static std::pair<ValueDecl *, bool>
+getPrivateItem(Sema &S, Expr *&RefExpr, SourceLocation &ELoc,
+ SourceRange &ERange, bool AllowArraySection = false);
+static DeclRefExpr *buildCapture(Sema &S, ValueDecl *D, Expr *CaptureExpr,
+ bool WithInit);
void Sema::EndOpenMPDSABlock(Stmt *CurDirective) {
// OpenMP [2.14.3.5, Restrictions, C/C++, p.1]
@@ -2185,6 +2279,31 @@ void Sema::EndOpenMPDSABlock(Stmt *CurDirective) {
}
}
Clause->setPrivateCopies(PrivateCopies);
+ continue;
+ }
+ // Finalize nontemporal clause by handling private copies, if any.
+ if (auto *Clause = dyn_cast<OMPNontemporalClause>(C)) {
+ SmallVector<Expr *, 8> PrivateRefs;
+ for (Expr *RefExpr : Clause->varlists()) {
+ assert(RefExpr && "NULL expr in OpenMP nontemporal clause.");
+ SourceLocation ELoc;
+ SourceRange ERange;
+ Expr *SimpleRefExpr = RefExpr;
+ auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange);
+ if (Res.second)
+ // It will be analyzed later.
+ PrivateRefs.push_back(RefExpr);
+ ValueDecl *D = Res.first;
+ if (!D)
+ continue;
+
+ const DSAStackTy::DSAVarData DVar =
+ DSAStack->getTopDSA(D, /*FromParent=*/false);
+ PrivateRefs.push_back(DVar.PrivateCopy ? DVar.PrivateCopy
+ : SimpleRefExpr);
+ }
+ Clause->setPrivateRefs(PrivateRefs);
+ continue;
}
}
// Check allocate clauses.
@@ -2759,14 +2878,51 @@ static void reportOriginalDsa(Sema &SemaRef, const DSAStackTy *Stack,
}
}
+static OpenMPMapClauseKind
+getMapClauseKindFromModifier(OpenMPDefaultmapClauseModifier M,
+ bool IsAggregateOrDeclareTarget) {
+ OpenMPMapClauseKind Kind = OMPC_MAP_unknown;
+ switch (M) {
+ case OMPC_DEFAULTMAP_MODIFIER_alloc:
+ Kind = OMPC_MAP_alloc;
+ break;
+ case OMPC_DEFAULTMAP_MODIFIER_to:
+ Kind = OMPC_MAP_to;
+ break;
+ case OMPC_DEFAULTMAP_MODIFIER_from:
+ Kind = OMPC_MAP_from;
+ break;
+ case OMPC_DEFAULTMAP_MODIFIER_tofrom:
+ Kind = OMPC_MAP_tofrom;
+ break;
+ case OMPC_DEFAULTMAP_MODIFIER_firstprivate:
+ case OMPC_DEFAULTMAP_MODIFIER_last:
+ llvm_unreachable("Unexpected defaultmap implicit behavior");
+ case OMPC_DEFAULTMAP_MODIFIER_none:
+ case OMPC_DEFAULTMAP_MODIFIER_default:
+ case OMPC_DEFAULTMAP_MODIFIER_unknown:
+ // IsAggregateOrDeclareTarget could be true if:
+ // 1. the implicit behavior for aggregate is tofrom
+ // 2. it's a declare target link
+ if (IsAggregateOrDeclareTarget) {
+ Kind = OMPC_MAP_tofrom;
+ break;
+ }
+ llvm_unreachable("Unexpected defaultmap implicit behavior");
+ }
+ assert(Kind != OMPC_MAP_unknown && "Expect map kind to be known");
+ return Kind;
+}
+
namespace {
class DSAAttrChecker final : public StmtVisitor<DSAAttrChecker, void> {
DSAStackTy *Stack;
Sema &SemaRef;
bool ErrorFound = false;
+ bool TryCaptureCXXThisMembers = false;
CapturedStmt *CS = nullptr;
llvm::SmallVector<Expr *, 4> ImplicitFirstprivate;
- llvm::SmallVector<Expr *, 4> ImplicitMap;
+ llvm::SmallVector<Expr *, 4> ImplicitMap[OMPC_MAP_delete];
Sema::VarsWithInheritedDSAType VarsWithInheritedDSA;
llvm::SmallDenseSet<const ValueDecl *, 4> ImplicitDeclarations;
@@ -2775,12 +2931,26 @@ class DSAAttrChecker final : public StmtVisitor<DSAAttrChecker, void> {
if (!S->hasAssociatedStmt() || !S->getAssociatedStmt())
return;
visitSubCaptures(S->getInnermostCapturedStmt());
+ // Try to capture inner this->member references to generate correct mappings
+ // and diagnostics.
+ if (TryCaptureCXXThisMembers ||
+ (isOpenMPTargetExecutionDirective(Stack->getCurrentDirective()) &&
+ llvm::any_of(S->getInnermostCapturedStmt()->captures(),
+ [](const CapturedStmt::Capture &C) {
+ return C.capturesThis();
+ }))) {
+ bool SavedTryCaptureCXXThisMembers = TryCaptureCXXThisMembers;
+ TryCaptureCXXThisMembers = true;
+ Visit(S->getInnermostCapturedStmt()->getCapturedStmt());
+ TryCaptureCXXThisMembers = SavedTryCaptureCXXThisMembers;
+ }
}
public:
void VisitDeclRefExpr(DeclRefExpr *E) {
- if (E->isTypeDependent() || E->isValueDependent() ||
- E->containsUnexpandedParameterPack() || E->isInstantiationDependent())
+ if (TryCaptureCXXThisMembers || E->isTypeDependent() ||
+ E->isValueDependent() || E->containsUnexpandedParameterPack() ||
+ E->isInstantiationDependent())
return;
if (auto *VD = dyn_cast<VarDecl>(E->getDecl())) {
// Check the datasharing rules for the expressions in the clauses.
@@ -2825,6 +2995,39 @@ public:
return;
}
+ // OpenMP 5.0 [2.19.7.2, defaultmap clause, Description]
+ // If implicit-behavior is none, each variable referenced in the
+ // 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
+ // clause on a combined construct where target. is one of the
+ // constituent constructs), or an is_device_ptr clause.
+ OpenMPDefaultmapClauseKind ClauseKind =
+ getVariableCategoryFromDecl(SemaRef.getLangOpts(), VD);
+ if (SemaRef.getLangOpts().OpenMP >= 50) {
+ bool IsModifierNone = Stack->getDefaultmapModifier(ClauseKind) ==
+ OMPC_DEFAULTMAP_MODIFIER_none;
+ if (DVar.CKind == OMPC_unknown && IsModifierNone &&
+ VarsWithInheritedDSA.count(VD) == 0 && !Res) {
+ // Only check for data-mapping attribute and is_device_ptr here
+ // since we have already make sure that the declaration does not
+ // have a data-sharing attribute above
+ if (!Stack->checkMappableExprComponentListsForDecl(
+ VD, /*CurrentRegionOnly=*/true,
+ [VD](OMPClauseMappableExprCommon::MappableExprComponentListRef
+ MapExprComponents,
+ OpenMPClauseKind) {
+ auto MI = MapExprComponents.rbegin();
+ auto ME = MapExprComponents.rend();
+ return MI != ME && MI->getAssociatedDeclaration() == VD;
+ })) {
+ VarsWithInheritedDSA[VD] = E;
+ return;
+ }
+ }
+ }
+
if (isOpenMPTargetExecutionDirective(DKind) &&
!Stack->isLoopControlVariable(VD).first) {
if (!Stack->checkMappableExprComponentListsForDecl(
@@ -2854,13 +3057,16 @@ public:
VD->getType().getNonReferenceType()->getAsCXXRecordDecl())
IsFirstprivate = RD->isLambda();
IsFirstprivate =
- IsFirstprivate ||
- (VD->getType().getNonReferenceType()->isScalarType() &&
- Stack->getDefaultDMA() != DMA_tofrom_scalar && !Res);
- if (IsFirstprivate)
+ IsFirstprivate || (Stack->mustBeFirstprivate(ClauseKind) && !Res);
+ if (IsFirstprivate) {
ImplicitFirstprivate.emplace_back(E);
- else
- ImplicitMap.emplace_back(E);
+ } else {
+ OpenMPDefaultmapClauseModifier M =
+ Stack->getDefaultmapModifier(ClauseKind);
+ OpenMPMapClauseKind Kind = getMapClauseKindFromModifier(
+ M, ClauseKind == OMPC_DEFAULTMAP_aggregate || Res);
+ ImplicitMap[Kind].emplace_back(E);
+ }
return;
}
}
@@ -2939,7 +3145,11 @@ public:
if (Stack->isClassPreviouslyMapped(TE->getType()))
return;
- ImplicitMap.emplace_back(E);
+ OpenMPDefaultmapClauseModifier Modifier =
+ Stack->getDefaultmapModifier(OMPC_DEFAULTMAP_aggregate);
+ OpenMPMapClauseKind Kind = getMapClauseKindFromModifier(
+ Modifier, /*IsAggregateOrDeclareTarget*/ true);
+ ImplicitMap[Kind].emplace_back(E);
return;
}
@@ -3014,7 +3224,7 @@ public:
})) {
Visit(E->getBase());
}
- } else {
+ } else if (!TryCaptureCXXThisMembers) {
Visit(E->getBase());
}
}
@@ -3068,7 +3278,9 @@ public:
ArrayRef<Expr *> getImplicitFirstprivate() const {
return ImplicitFirstprivate;
}
- ArrayRef<Expr *> getImplicitMap() const { return ImplicitMap; }
+ ArrayRef<Expr *> getImplicitMap(OpenMPDefaultmapClauseKind Kind) const {
+ return ImplicitMap[Kind];
+ }
const Sema::VarsWithInheritedDSAType &getVarsWithInheritedDSA() const {
return VarsWithInheritedDSA;
}
@@ -3090,6 +3302,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
case OMPD_parallel_for:
case OMPD_parallel_for_simd:
case OMPD_parallel_sections:
+ case OMPD_parallel_master:
case OMPD_teams:
case OMPD_teams_distribute:
case OMPD_teams_distribute_simd: {
@@ -3282,7 +3495,8 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
AlwaysInlineAttr::Keyword_forceinline));
break;
}
- case OMPD_parallel_master_taskloop: {
+ case OMPD_parallel_master_taskloop:
+ case OMPD_parallel_master_taskloop_simd: {
QualType KmpInt32Ty =
Context.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1)
.withConst();
@@ -3779,7 +3993,10 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack,
ShouldBeInTargetRegion,
ShouldBeInTeamsRegion
} Recommend = NoRecommend;
- if (isOpenMPSimdDirective(ParentRegion) && CurrentRegion != OMPD_ordered) {
+ if (isOpenMPSimdDirective(ParentRegion) &&
+ ((SemaRef.LangOpts.OpenMP <= 45 && CurrentRegion != OMPD_ordered) ||
+ (SemaRef.LangOpts.OpenMP >= 50 && CurrentRegion != OMPD_ordered &&
+ CurrentRegion != OMPD_simd && CurrentRegion != OMPD_atomic))) {
// OpenMP [2.16, Nesting of Regions]
// OpenMP constructs may not be nested inside a simd region.
// OpenMP [2.8.1,simd Construct, Restrictions]
@@ -3788,9 +4005,14 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack,
// Allowing a SIMD construct nested in another SIMD construct is an
// extension. The OpenMP 4.5 spec does not allow it. Issue a warning
// message.
+ // OpenMP 5.0 [2.9.3.1, simd Construct, Restrictions]
+ // The only OpenMP constructs that can be encountered during execution of
+ // a simd region are the atomic construct, the loop construct, the simd
+ // construct and the ordered construct with the simd clause.
SemaRef.Diag(StartLoc, (CurrentRegion != OMPD_simd)
? diag::err_omp_prohibited_region_simd
- : diag::warn_omp_nesting_simd);
+ : diag::warn_omp_nesting_simd)
+ << (SemaRef.LangOpts.OpenMP >= 50 ? 1 : 0);
return CurrentRegion != OMPD_simd;
}
if (ParentRegion == OMPD_atomic) {
@@ -3888,6 +4110,7 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack,
NestingProhibited = isOpenMPWorksharingDirective(ParentRegion) ||
isOpenMPTaskingDirective(ParentRegion) ||
ParentRegion == OMPD_master ||
+ ParentRegion == OMPD_parallel_master ||
ParentRegion == OMPD_critical ||
ParentRegion == OMPD_ordered;
} else if (isOpenMPWorksharingDirective(CurrentRegion) &&
@@ -3899,6 +4122,7 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack,
NestingProhibited = isOpenMPWorksharingDirective(ParentRegion) ||
isOpenMPTaskingDirective(ParentRegion) ||
ParentRegion == OMPD_master ||
+ ParentRegion == OMPD_parallel_master ||
ParentRegion == OMPD_critical ||
ParentRegion == OMPD_ordered;
Recommend = ShouldBeInParallelRegion;
@@ -3982,13 +4206,17 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack,
return false;
}
+struct Kind2Unsigned {
+ using argument_type = OpenMPDirectiveKind;
+ unsigned operator()(argument_type DK) { return unsigned(DK); }
+};
static bool checkIfClauses(Sema &S, OpenMPDirectiveKind Kind,
ArrayRef<OMPClause *> Clauses,
ArrayRef<OpenMPDirectiveKind> AllowedNameModifiers) {
bool ErrorFound = false;
unsigned NamedModifiersNumber = 0;
- SmallVector<const OMPIfClause *, OMPC_unknown + 1> FoundNameModifiers(
- OMPD_unknown + 1);
+ llvm::IndexedMap<const OMPIfClause *, Kind2Unsigned> FoundNameModifiers;
+ FoundNameModifiers.resize(unsigned(OMPD_unknown) + 1);
SmallVector<SourceLocation, 4> NameModifierLoc;
for (const OMPClause *C : Clauses) {
if (const auto *IC = dyn_cast_or_null<OMPIfClause>(C)) {
@@ -4064,9 +4292,10 @@ static bool checkIfClauses(Sema &S, OpenMPDirectiveKind Kind,
return ErrorFound;
}
-static std::pair<ValueDecl *, bool>
-getPrivateItem(Sema &S, Expr *&RefExpr, SourceLocation &ELoc,
- SourceRange &ERange, bool AllowArraySection = false) {
+static std::pair<ValueDecl *, bool> getPrivateItem(Sema &S, Expr *&RefExpr,
+ SourceLocation &ELoc,
+ SourceRange &ERange,
+ bool AllowArraySection) {
if (RefExpr->isTypeDependent() || RefExpr->isValueDependent() ||
RefExpr->containsUnexpandedParameterPack())
return std::make_pair(nullptr, true);
@@ -4271,8 +4500,12 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
SmallVector<Expr *, 4> ImplicitFirstprivates(
DSAChecker.getImplicitFirstprivate().begin(),
DSAChecker.getImplicitFirstprivate().end());
- SmallVector<Expr *, 4> ImplicitMaps(DSAChecker.getImplicitMap().begin(),
- DSAChecker.getImplicitMap().end());
+ SmallVector<Expr *, 4> ImplicitMaps[OMPC_MAP_delete];
+ for (unsigned I = 0; I < OMPC_MAP_delete; ++I) {
+ ArrayRef<Expr *> ImplicitMap =
+ DSAChecker.getImplicitMap(static_cast<OpenMPDefaultmapClauseKind>(I));
+ ImplicitMaps[I].append(ImplicitMap.begin(), ImplicitMap.end());
+ }
// Mark taskgroup task_reduction descriptors as implicitly firstprivate.
for (OMPClause *C : Clauses) {
if (auto *IRC = dyn_cast<OMPInReductionClause>(C)) {
@@ -4292,16 +4525,21 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
ErrorFound = true;
}
}
- if (!ImplicitMaps.empty()) {
+ int ClauseKindCnt = -1;
+ for (ArrayRef<Expr *> ImplicitMap : ImplicitMaps) {
+ ++ClauseKindCnt;
+ if (ImplicitMap.empty())
+ continue;
CXXScopeSpec MapperIdScopeSpec;
DeclarationNameInfo MapperId;
+ auto Kind = static_cast<OpenMPMapClauseKind>(ClauseKindCnt);
if (OMPClause *Implicit = ActOnOpenMPMapClause(
- llvm::None, llvm::None, MapperIdScopeSpec, MapperId,
- OMPC_MAP_tofrom, /*IsMapTypeImplicit=*/true, SourceLocation(),
- SourceLocation(), ImplicitMaps, OMPVarListLocTy())) {
+ llvm::None, llvm::None, MapperIdScopeSpec, MapperId, Kind,
+ /*IsMapTypeImplicit=*/true, SourceLocation(), SourceLocation(),
+ ImplicitMap, OMPVarListLocTy())) {
ClausesWithImplicit.emplace_back(Implicit);
ErrorFound |=
- cast<OMPMapClause>(Implicit)->varlist_size() != ImplicitMaps.size();
+ cast<OMPMapClause>(Implicit)->varlist_size() != ImplicitMap.size();
} else {
ErrorFound = true;
}
@@ -4318,6 +4556,8 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
case OMPD_simd:
Res = ActOnOpenMPSimdDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc,
VarsWithInheritedDSA);
+ if (LangOpts.OpenMP >= 50)
+ AllowedNameModifiers.push_back(OMPD_simd);
break;
case OMPD_for:
Res = ActOnOpenMPForDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc,
@@ -4326,6 +4566,8 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
case OMPD_for_simd:
Res = ActOnOpenMPForSimdDirective(ClausesWithImplicit, AStmt, StartLoc,
EndLoc, VarsWithInheritedDSA);
+ if (LangOpts.OpenMP >= 50)
+ AllowedNameModifiers.push_back(OMPD_simd);
break;
case OMPD_sections:
Res = ActOnOpenMPSectionsDirective(ClausesWithImplicit, AStmt, StartLoc,
@@ -4358,6 +4600,13 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
Res = ActOnOpenMPParallelForSimdDirective(
ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
AllowedNameModifiers.push_back(OMPD_parallel);
+ if (LangOpts.OpenMP >= 50)
+ AllowedNameModifiers.push_back(OMPD_simd);
+ break;
+ case OMPD_parallel_master:
+ Res = ActOnOpenMPParallelMasterDirective(ClausesWithImplicit, AStmt,
+ StartLoc, EndLoc);
+ AllowedNameModifiers.push_back(OMPD_parallel);
break;
case OMPD_parallel_sections:
Res = ActOnOpenMPParallelSectionsDirective(ClausesWithImplicit, AStmt,
@@ -4466,6 +4715,8 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
Res = ActOnOpenMPTaskLoopSimdDirective(ClausesWithImplicit, AStmt, StartLoc,
EndLoc, VarsWithInheritedDSA);
AllowedNameModifiers.push_back(OMPD_taskloop);
+ if (LangOpts.OpenMP >= 50)
+ AllowedNameModifiers.push_back(OMPD_simd);
break;
case OMPD_master_taskloop:
Res = ActOnOpenMPMasterTaskLoopDirective(
@@ -4476,6 +4727,8 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
Res = ActOnOpenMPMasterTaskLoopSimdDirective(
ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
AllowedNameModifiers.push_back(OMPD_taskloop);
+ if (LangOpts.OpenMP >= 50)
+ AllowedNameModifiers.push_back(OMPD_simd);
break;
case OMPD_parallel_master_taskloop:
Res = ActOnOpenMPParallelMasterTaskLoopDirective(
@@ -4483,6 +4736,14 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
AllowedNameModifiers.push_back(OMPD_taskloop);
AllowedNameModifiers.push_back(OMPD_parallel);
break;
+ case OMPD_parallel_master_taskloop_simd:
+ Res = ActOnOpenMPParallelMasterTaskLoopSimdDirective(
+ ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
+ AllowedNameModifiers.push_back(OMPD_taskloop);
+ AllowedNameModifiers.push_back(OMPD_parallel);
+ if (LangOpts.OpenMP >= 50)
+ AllowedNameModifiers.push_back(OMPD_simd);
+ break;
case OMPD_distribute:
Res = ActOnOpenMPDistributeDirective(ClausesWithImplicit, AStmt, StartLoc,
EndLoc, VarsWithInheritedDSA);
@@ -4501,21 +4762,29 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
Res = ActOnOpenMPDistributeParallelForSimdDirective(
ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
AllowedNameModifiers.push_back(OMPD_parallel);
+ if (LangOpts.OpenMP >= 50)
+ AllowedNameModifiers.push_back(OMPD_simd);
break;
case OMPD_distribute_simd:
Res = ActOnOpenMPDistributeSimdDirective(
ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
+ if (LangOpts.OpenMP >= 50)
+ AllowedNameModifiers.push_back(OMPD_simd);
break;
case OMPD_target_parallel_for_simd:
Res = ActOnOpenMPTargetParallelForSimdDirective(
ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
AllowedNameModifiers.push_back(OMPD_target);
AllowedNameModifiers.push_back(OMPD_parallel);
+ if (LangOpts.OpenMP >= 50)
+ AllowedNameModifiers.push_back(OMPD_simd);
break;
case OMPD_target_simd:
Res = ActOnOpenMPTargetSimdDirective(ClausesWithImplicit, AStmt, StartLoc,
EndLoc, VarsWithInheritedDSA);
AllowedNameModifiers.push_back(OMPD_target);
+ if (LangOpts.OpenMP >= 50)
+ AllowedNameModifiers.push_back(OMPD_simd);
break;
case OMPD_teams_distribute:
Res = ActOnOpenMPTeamsDistributeDirective(
@@ -4524,11 +4793,15 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
case OMPD_teams_distribute_simd:
Res = ActOnOpenMPTeamsDistributeSimdDirective(
ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
+ if (LangOpts.OpenMP >= 50)
+ AllowedNameModifiers.push_back(OMPD_simd);
break;
case OMPD_teams_distribute_parallel_for_simd:
Res = ActOnOpenMPTeamsDistributeParallelForSimdDirective(
ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
AllowedNameModifiers.push_back(OMPD_parallel);
+ if (LangOpts.OpenMP >= 50)
+ AllowedNameModifiers.push_back(OMPD_simd);
break;
case OMPD_teams_distribute_parallel_for:
Res = ActOnOpenMPTeamsDistributeParallelForDirective(
@@ -4556,11 +4829,15 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
AllowedNameModifiers.push_back(OMPD_target);
AllowedNameModifiers.push_back(OMPD_parallel);
+ if (LangOpts.OpenMP >= 50)
+ AllowedNameModifiers.push_back(OMPD_simd);
break;
case OMPD_target_teams_distribute_simd:
Res = ActOnOpenMPTargetTeamsDistributeSimdDirective(
ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
AllowedNameModifiers.push_back(OMPD_target);
+ if (LangOpts.OpenMP >= 50)
+ AllowedNameModifiers.push_back(OMPD_simd);
break;
case OMPD_declare_target:
case OMPD_end_declare_target:
@@ -4586,13 +4863,17 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
case OMPC_num_threads:
case OMPC_dist_schedule:
// Do not analyse if no parent teams directive.
- if (isOpenMPTeamsDirective(DSAStack->getCurrentDirective()))
+ if (isOpenMPTeamsDirective(Kind))
break;
continue;
case OMPC_if:
- if (isOpenMPTeamsDirective(DSAStack->getCurrentDirective()) &&
+ if (isOpenMPTeamsDirective(Kind) &&
cast<OMPIfClause>(C)->getNameModifier() != OMPD_target)
break;
+ if (isOpenMPParallelDirective(Kind) &&
+ isOpenMPTaskLoopDirective(Kind) &&
+ cast<OMPIfClause>(C)->getNameModifier() != OMPD_parallel)
+ break;
continue;
case OMPC_schedule:
break;
@@ -4601,7 +4882,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
case OMPC_final:
case OMPC_priority:
// Do not analyze if no parent parallel directive.
- if (isOpenMPParallelDirective(DSAStack->getCurrentDirective()))
+ if (isOpenMPParallelDirective(Kind))
break;
continue;
case OMPC_ordered:
@@ -4644,6 +4925,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
case OMPC_from:
case OMPC_use_device_ptr:
case OMPC_is_device_ptr:
+ case OMPC_nontemporal:
continue;
case OMPC_allocator:
case OMPC_flush:
@@ -4671,9 +4953,17 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
if (P.getFirst()->isImplicit() || isa<OMPCapturedExprDecl>(P.getFirst()))
continue;
ErrorFound = true;
- Diag(P.second->getExprLoc(), diag::err_omp_no_dsa_for_variable)
- << P.first << P.second->getSourceRange();
- Diag(DSAStack->getDefaultDSALocation(), diag::note_omp_default_dsa_none);
+ if (DSAStack->getDefaultDSA() == DSA_none) {
+ Diag(P.second->getExprLoc(), diag::err_omp_no_dsa_for_variable)
+ << P.first << P.second->getSourceRange();
+ Diag(DSAStack->getDefaultDSALocation(), diag::note_omp_default_dsa_none);
+ } else if (getLangOpts().OpenMP >= 50) {
+ Diag(P.second->getExprLoc(),
+ diag::err_omp_defaultmap_no_attr_for_variable)
+ << P.first << P.second->getSourceRange();
+ Diag(DSAStack->getDefaultDSALocation(),
+ diag::note_omp_defaultmap_attr_none);
+ }
}
if (!AllowedNameModifiers.empty())
@@ -4781,8 +5071,9 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective(
// OpenMP [2.8.1, simd construct, Restrictions]
// A list-item cannot appear in more than one aligned clause.
if (AlignedArgs.count(CanonPVD) > 0) {
- Diag(E->getExprLoc(), diag::err_omp_aligned_twice)
- << 1 << E->getSourceRange();
+ Diag(E->getExprLoc(), diag::err_omp_used_in_clause_twice)
+ << 1 << getOpenMPClauseName(OMPC_aligned)
+ << E->getSourceRange();
Diag(AlignedArgs[CanonPVD]->getExprLoc(),
diag::note_omp_explicit_dsa)
<< getOpenMPClauseName(OMPC_aligned);
@@ -4804,8 +5095,8 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective(
}
if (isa<CXXThisExpr>(E)) {
if (AlignedThis) {
- Diag(E->getExprLoc(), diag::err_omp_aligned_twice)
- << 2 << E->getSourceRange();
+ Diag(E->getExprLoc(), diag::err_omp_used_in_clause_twice)
+ << 2 << getOpenMPClauseName(OMPC_aligned) << E->getSourceRange();
Diag(AlignedThis->getExprLoc(), diag::note_omp_explicit_dsa)
<< getOpenMPClauseName(OMPC_aligned);
}
@@ -4950,6 +5241,29 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective(
return DG;
}
+static void setPrototype(Sema &S, FunctionDecl *FD, FunctionDecl *FDWithProto,
+ QualType NewType) {
+ assert(NewType->isFunctionProtoType() &&
+ "Expected function type with prototype.");
+ assert(FD->getType()->isFunctionNoProtoType() &&
+ "Expected function with type with no prototype.");
+ assert(FDWithProto->getType()->isFunctionProtoType() &&
+ "Expected function with prototype.");
+ // Synthesize parameters with the same types.
+ FD->setType(NewType);
+ SmallVector<ParmVarDecl *, 16> Params;
+ for (const ParmVarDecl *P : FDWithProto->parameters()) {
+ auto *Param = ParmVarDecl::Create(S.getASTContext(), FD, SourceLocation(),
+ SourceLocation(), nullptr, P->getType(),
+ /*TInfo=*/nullptr, SC_None, nullptr);
+ Param->setScopeInfo(0, Params.size());
+ Param->setImplicit();
+ Params.push_back(Param);
+ }
+
+ FD->setParams(Params);
+}
+
Optional<std::pair<FunctionDecl *, Expr *>>
Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
Expr *VariantRef, SourceRange SR) {
@@ -5048,7 +5362,9 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
if (ICS.isFailure()) {
Diag(VariantRef->getExprLoc(),
diag::err_omp_declare_variant_incompat_types)
- << VariantRef->getType() << FnPtrType << VariantRef->getSourceRange();
+ << VariantRef->getType()
+ << ((Method && !Method->isStatic()) ? FnPtrType : FD->getType())
+ << VariantRef->getSourceRange();
return None;
}
VariantRefCast = PerformImplicitConversion(
@@ -5088,6 +5404,24 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
return None;
}
+ // Check if function types are compatible in C.
+ if (!LangOpts.CPlusPlus) {
+ QualType NewType =
+ Context.mergeFunctionTypes(FD->getType(), NewFD->getType());
+ if (NewType.isNull()) {
+ Diag(VariantRef->getExprLoc(),
+ diag::err_omp_declare_variant_incompat_types)
+ << NewFD->getType() << FD->getType() << VariantRef->getSourceRange();
+ return None;
+ }
+ if (NewType->isFunctionProtoType()) {
+ if (FD->getType()->isFunctionNoProtoType())
+ setPrototype(*this, FD, NewFD, NewType);
+ else if (NewFD->getType()->isFunctionNoProtoType())
+ setPrototype(*this, NewFD, FD, NewType);
+ }
+ }
+
// Check if variant function is not marked with declare variant directive.
if (NewFD->hasAttrs() && NewFD->hasAttr<OMPDeclareVariantAttr>()) {
Diag(VariantRef->getExprLoc(),
@@ -5148,10 +5482,9 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
// Check general compatibility.
if (areMultiversionVariantFunctionsCompatible(
- FD, NewFD, PDiag(diag::err_omp_declare_variant_noproto),
- PartialDiagnosticAt(
- SR.getBegin(),
- PDiag(diag::note_omp_declare_variant_specified_here) << SR),
+ FD, NewFD, PartialDiagnostic::NullDiagnostic(),
+ PartialDiagnosticAt(SourceLocation(),
+ PartialDiagnostic::NullDiagnostic()),
PartialDiagnosticAt(
VariantRef->getExprLoc(),
PDiag(diag::err_omp_declare_variant_doesnt_support)),
@@ -5166,28 +5499,73 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
void Sema::ActOnOpenMPDeclareVariantDirective(
FunctionDecl *FD, Expr *VariantRef, SourceRange SR,
- const Sema::OpenMPDeclareVariantCtsSelectorData &Data) {
- if (Data.CtxSet == OMPDeclareVariantAttr::CtxSetUnknown ||
- Data.Ctx == OMPDeclareVariantAttr::CtxUnknown)
+ ArrayRef<OMPCtxSelectorData> Data) {
+ if (Data.empty())
return;
- Expr *Score = nullptr;
- OMPDeclareVariantAttr::ScoreType ST = OMPDeclareVariantAttr::ScoreUnknown;
- if (Data.CtxScore.isUsable()) {
- ST = OMPDeclareVariantAttr::ScoreSpecified;
- Score = Data.CtxScore.get();
- if (!Score->isTypeDependent() && !Score->isValueDependent() &&
- !Score->isInstantiationDependent() &&
- !Score->containsUnexpandedParameterPack()) {
- llvm::APSInt Result;
- ExprResult ICE = VerifyIntegerConstantExpression(Score, &Result);
- if (ICE.isInvalid())
- return;
+ SmallVector<Expr *, 4> CtxScores;
+ SmallVector<unsigned, 4> CtxSets;
+ SmallVector<unsigned, 4> Ctxs;
+ SmallVector<StringRef, 4> ImplVendors, DeviceKinds;
+ bool IsError = false;
+ for (const OMPCtxSelectorData &D : Data) {
+ OpenMPContextSelectorSetKind CtxSet = D.CtxSet;
+ OpenMPContextSelectorKind Ctx = D.Ctx;
+ if (CtxSet == OMP_CTX_SET_unknown || Ctx == OMP_CTX_unknown)
+ return;
+ Expr *Score = nullptr;
+ if (D.Score.isUsable()) {
+ Score = D.Score.get();
+ if (!Score->isTypeDependent() && !Score->isValueDependent() &&
+ !Score->isInstantiationDependent() &&
+ !Score->containsUnexpandedParameterPack()) {
+ Score =
+ PerformOpenMPImplicitIntegerConversion(Score->getExprLoc(), Score)
+ .get();
+ if (Score)
+ Score = VerifyIntegerConstantExpression(Score).get();
+ }
+ } else {
+ // OpenMP 5.0, 2.3.3 Matching and Scoring Context Selectors.
+ // The kind, arch, and isa selectors are given the values 2^l, 2^(l+1) and
+ // 2^(l+2), respectively, where l is the number of traits in the construct
+ // set.
+ // TODO: implement correct logic for isa and arch traits.
+ // TODO: take the construct context set into account when it is
+ // implemented.
+ int L = 0; // Currently set the number of traits in construct set to 0,
+ // since the construct trait set in not supported yet.
+ if (CtxSet == OMP_CTX_SET_device && Ctx == OMP_CTX_kind)
+ Score = ActOnIntegerConstant(SourceLocation(), std::pow(2, L)).get();
+ else
+ Score = ActOnIntegerConstant(SourceLocation(), 0).get();
}
+ switch (Ctx) {
+ case OMP_CTX_vendor:
+ assert(CtxSet == OMP_CTX_SET_implementation &&
+ "Expected implementation context selector set.");
+ ImplVendors.append(D.Names.begin(), D.Names.end());
+ break;
+ case OMP_CTX_kind:
+ assert(CtxSet == OMP_CTX_SET_device &&
+ "Expected device context selector set.");
+ DeviceKinds.append(D.Names.begin(), D.Names.end());
+ break;
+ case OMP_CTX_unknown:
+ llvm_unreachable("Unknown context selector kind.");
+ }
+ IsError = IsError || !Score;
+ CtxSets.push_back(CtxSet);
+ Ctxs.push_back(Ctx);
+ CtxScores.push_back(Score);
+ }
+ if (!IsError) {
+ auto *NewAttr = OMPDeclareVariantAttr::CreateImplicit(
+ Context, VariantRef, CtxScores.begin(), CtxScores.size(),
+ CtxSets.begin(), CtxSets.size(), Ctxs.begin(), Ctxs.size(),
+ ImplVendors.begin(), ImplVendors.size(), DeviceKinds.begin(),
+ DeviceKinds.size(), SR);
+ FD->addAttr(NewAttr);
}
- auto *NewAttr = OMPDeclareVariantAttr::CreateImplicit(
- Context, VariantRef, Score, Data.CtxSet, ST, Data.Ctx,
- Data.ImplVendors.begin(), Data.ImplVendors.size(), SR);
- FD->addAttr(NewAttr);
}
void Sema::markOpenMPDeclareVariantFuncsReferenced(SourceLocation Loc,
@@ -5200,7 +5578,7 @@ void Sema::markOpenMPDeclareVariantFuncsReferenced(SourceLocation Loc,
Func->specific_attrs<OMPDeclareVariantAttr>()) {
// TODO: add checks for active OpenMP context where possible.
Expr *VariantRef = A->getVariantFuncRef();
- auto *DRE = dyn_cast<DeclRefExpr>(VariantRef->IgnoreParenImpCasts());
+ auto *DRE = cast<DeclRefExpr>(VariantRef->IgnoreParenImpCasts());
auto *F = cast<FunctionDecl>(DRE->getDecl());
if (!F->isDefined() && F->isTemplateInstantiation())
InstantiateFunctionDefinition(Loc, F->getFirstDecl());
@@ -6953,7 +7331,8 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
"Expected canonical for or range-based for loops.");
CurStmt = cast<CXXForRangeStmt>(CurStmt)->getBody();
}
- CurStmt = CurStmt->IgnoreContainers();
+ CurStmt = OMPLoopDirective::tryToFindNextInnerLoop(
+ CurStmt, SemaRef.LangOpts.OpenMP >= 50);
}
for (unsigned Cnt = NestedLoopCount; Cnt < OrderedLoopCount; ++Cnt) {
if (checkOpenMPIterationSpace(
@@ -6980,7 +7359,8 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
"Expected canonical for or range-based for loops.");
CurStmt = cast<CXXForRangeStmt>(CurStmt)->getBody();
}
- CurStmt = CurStmt->IgnoreContainers();
+ CurStmt = OMPLoopDirective::tryToFindNextInnerLoop(
+ CurStmt, SemaRef.LangOpts.OpenMP >= 50);
}
Built.clear(/* size */ NestedLoopCount);
@@ -7995,6 +8375,28 @@ StmtResult Sema::ActOnOpenMPParallelForSimdDirective(
}
StmtResult
+Sema::ActOnOpenMPParallelMasterDirective(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 OMPParallelMasterDirective::Create(Context, StartLoc, EndLoc, Clauses,
+ AStmt);
+}
+
+StmtResult
Sema::ActOnOpenMPParallelSectionsDirective(ArrayRef<OMPClause *> Clauses,
Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc) {
@@ -8137,7 +8539,8 @@ StmtResult Sema::ActOnOpenMPOrderedDirective(ArrayRef<OMPClause *> Clauses,
// OpenMP [2.8.1,simd Construct, Restrictions]
// An ordered construct with the simd clause is the only OpenMP construct
// that can appear in the simd region.
- Diag(StartLoc, diag::err_omp_prohibited_region_simd);
+ Diag(StartLoc, diag::err_omp_prohibited_region_simd)
+ << (LangOpts.OpenMP >= 50 ? 1 : 0);
ErrorFound = true;
} else if (DependFound && (TC || SC)) {
Diag(DependFound->getBeginLoc(), diag::err_omp_depend_clause_thread_simd)
@@ -9467,6 +9870,74 @@ StmtResult Sema::ActOnOpenMPParallelMasterTaskLoopDirective(
Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
}
+StmtResult Sema::ActOnOpenMPParallelMasterTaskLoopSimdDirective(
+ 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_master_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();
+ }
+
+ OMPLoopDirective::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_master_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 (checkGrainsizeNumTasksClauses(*this, Clauses))
+ 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 OMPParallelMasterTaskLoopSimdDirective::Create(
+ Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
+}
+
StmtResult Sema::ActOnOpenMPDistributeDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
@@ -10317,6 +10788,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
case OMPC_atomic_default_mem_order:
case OMPC_device_type:
case OMPC_match:
+ case OMPC_nontemporal:
llvm_unreachable("Clause is not allowed.");
}
return Res;
@@ -10328,29 +10800,47 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
// A return value of OMPD_unknown signifies that the expression should not
// be captured.
static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
- OpenMPDirectiveKind DKind, OpenMPClauseKind CKind,
+ OpenMPDirectiveKind DKind, OpenMPClauseKind CKind, unsigned OpenMPVersion,
OpenMPDirectiveKind NameModifier = OMPD_unknown) {
OpenMPDirectiveKind CaptureRegion = OMPD_unknown;
switch (CKind) {
case OMPC_if:
switch (DKind) {
+ case OMPD_target_parallel_for_simd:
+ if (OpenMPVersion >= 50 &&
+ (NameModifier == OMPD_unknown || NameModifier == OMPD_simd)) {
+ CaptureRegion = OMPD_parallel;
+ break;
+ }
+ LLVM_FALLTHROUGH;
case OMPD_target_parallel:
case OMPD_target_parallel_for:
- case OMPD_target_parallel_for_simd:
// 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)
CaptureRegion = OMPD_target;
break;
- case OMPD_target_teams_distribute_parallel_for:
case OMPD_target_teams_distribute_parallel_for_simd:
+ if (OpenMPVersion >= 50 &&
+ (NameModifier == OMPD_unknown || NameModifier == OMPD_simd)) {
+ CaptureRegion = OMPD_parallel;
+ break;
+ }
+ LLVM_FALLTHROUGH;
+ case OMPD_target_teams_distribute_parallel_for:
// If this clause applies to the nested 'parallel' region, capture within
// the 'teams' region, otherwise do not capture.
if (NameModifier == OMPD_unknown || NameModifier == OMPD_parallel)
CaptureRegion = OMPD_teams;
break;
- case OMPD_teams_distribute_parallel_for:
case OMPD_teams_distribute_parallel_for_simd:
+ if (OpenMPVersion >= 50 &&
+ (NameModifier == OMPD_unknown || NameModifier == OMPD_simd)) {
+ CaptureRegion = OMPD_parallel;
+ break;
+ }
+ LLVM_FALLTHROUGH;
+ case OMPD_teams_distribute_parallel_for:
CaptureRegion = OMPD_teams;
break;
case OMPD_target_update:
@@ -10362,24 +10852,63 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
if (NameModifier == OMPD_unknown || NameModifier == OMPD_taskloop)
CaptureRegion = OMPD_parallel;
break;
+ case OMPD_parallel_master_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_for_simd:
+ if (OpenMPVersion <= 45)
+ break;
+ if (NameModifier == OMPD_unknown || NameModifier == OMPD_simd)
+ CaptureRegion = OMPD_parallel;
+ break;
+ case OMPD_taskloop_simd:
+ case OMPD_master_taskloop_simd:
+ if (OpenMPVersion <= 45)
+ break;
+ if (NameModifier == OMPD_unknown || NameModifier == OMPD_simd)
+ CaptureRegion = OMPD_taskloop;
+ break;
+ case OMPD_distribute_parallel_for_simd:
+ if (OpenMPVersion <= 45)
+ break;
+ if (NameModifier == OMPD_unknown || NameModifier == OMPD_simd)
+ CaptureRegion = OMPD_parallel;
+ break;
+ case OMPD_target_simd:
+ if (OpenMPVersion >= 50 &&
+ (NameModifier == OMPD_unknown || NameModifier == OMPD_simd))
+ CaptureRegion = OMPD_target;
+ break;
+ case OMPD_teams_distribute_simd:
+ case OMPD_target_teams_distribute_simd:
+ if (OpenMPVersion >= 50 &&
+ (NameModifier == OMPD_unknown || NameModifier == OMPD_simd))
+ CaptureRegion = OMPD_teams;
+ break;
case OMPD_cancel:
case OMPD_parallel:
+ case OMPD_parallel_master:
case OMPD_parallel_sections:
case OMPD_parallel_for:
- case OMPD_parallel_for_simd:
case OMPD_target:
- case OMPD_target_simd:
case OMPD_target_teams:
case OMPD_target_teams_distribute:
- case OMPD_target_teams_distribute_simd:
case OMPD_distribute_parallel_for:
- case OMPD_distribute_parallel_for_simd:
case OMPD_task:
case OMPD_taskloop:
- case OMPD_taskloop_simd:
case OMPD_master_taskloop:
- case OMPD_master_taskloop_simd:
case OMPD_target_data:
+ case OMPD_simd:
+ case OMPD_for_simd:
+ case OMPD_distribute_simd:
// Do not capture if-clause expressions.
break;
case OMPD_threadprivate:
@@ -10396,9 +10925,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_teams:
- case OMPD_simd:
case OMPD_for:
- case OMPD_for_simd:
case OMPD_sections:
case OMPD_section:
case OMPD_single:
@@ -10408,9 +10935,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_distribute:
case OMPD_ordered:
case OMPD_atomic:
- case OMPD_distribute_simd:
case OMPD_teams_distribute:
- case OMPD_teams_distribute_simd:
case OMPD_requires:
llvm_unreachable("Unexpected OpenMP directive with if-clause");
case OMPD_unknown:
@@ -10431,12 +10956,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
CaptureRegion = OMPD_teams;
break;
case OMPD_parallel:
+ case OMPD_parallel_master:
case OMPD_parallel_sections:
case OMPD_parallel_for:
case OMPD_parallel_for_simd:
case OMPD_distribute_parallel_for:
case OMPD_distribute_parallel_for_simd:
case OMPD_parallel_master_taskloop:
+ case OMPD_parallel_master_taskloop_simd:
// Do not capture num_threads-clause expressions.
break;
case OMPD_target_data:
@@ -10513,12 +11040,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_master_taskloop:
case OMPD_master_taskloop_simd:
case OMPD_parallel_master_taskloop:
+ case OMPD_parallel_master_taskloop_simd:
case OMPD_target_data:
case OMPD_target_enter_data:
case OMPD_target_exit_data:
case OMPD_target_update:
case OMPD_cancel:
case OMPD_parallel:
+ case OMPD_parallel_master:
case OMPD_parallel_sections:
case OMPD_parallel_for:
case OMPD_parallel_for_simd:
@@ -10583,12 +11112,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_master_taskloop:
case OMPD_master_taskloop_simd:
case OMPD_parallel_master_taskloop:
+ case OMPD_parallel_master_taskloop_simd:
case OMPD_target_data:
case OMPD_target_enter_data:
case OMPD_target_exit_data:
case OMPD_target_update:
case OMPD_cancel:
case OMPD_parallel:
+ case OMPD_parallel_master:
case OMPD_parallel_sections:
case OMPD_parallel_for:
case OMPD_parallel_for_simd:
@@ -10653,6 +11184,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_master_taskloop:
case OMPD_master_taskloop_simd:
case OMPD_parallel_master_taskloop:
+ case OMPD_parallel_master_taskloop_simd:
case OMPD_target_data:
case OMPD_target_enter_data:
case OMPD_target_exit_data:
@@ -10667,6 +11199,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_target_parallel:
case OMPD_cancel:
case OMPD_parallel:
+ case OMPD_parallel_master:
case OMPD_parallel_sections:
case OMPD_threadprivate:
case OMPD_allocate:
@@ -10727,6 +11260,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_master_taskloop:
case OMPD_master_taskloop_simd:
case OMPD_parallel_master_taskloop:
+ case OMPD_parallel_master_taskloop_simd:
case OMPD_target_data:
case OMPD_target_enter_data:
case OMPD_target_exit_data:
@@ -10737,6 +11271,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_target_parallel:
case OMPD_cancel:
case OMPD_parallel:
+ case OMPD_parallel_master:
case OMPD_parallel_sections:
case OMPD_threadprivate:
case OMPD_allocate:
@@ -10802,8 +11337,10 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_master_taskloop:
case OMPD_master_taskloop_simd:
case OMPD_parallel_master_taskloop:
+ case OMPD_parallel_master_taskloop_simd:
case OMPD_cancel:
case OMPD_parallel:
+ case OMPD_parallel_master:
case OMPD_parallel_sections:
case OMPD_parallel_for:
case OMPD_parallel_for_simd:
@@ -10851,6 +11388,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_master_taskloop_simd:
break;
case OMPD_parallel_master_taskloop:
+ case OMPD_parallel_master_taskloop_simd:
CaptureRegion = OMPD_parallel;
break;
case OMPD_target_update:
@@ -10876,6 +11414,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_distribute_parallel_for_simd:
case OMPD_cancel:
case OMPD_parallel:
+ case OMPD_parallel_master:
case OMPD_parallel_sections:
case OMPD_parallel_for:
case OMPD_parallel_for_simd:
@@ -10960,6 +11499,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPC_atomic_default_mem_order:
case OMPC_device_type:
case OMPC_match:
+ case OMPC_nontemporal:
llvm_unreachable("Unexpected OpenMP clause.");
}
return CaptureRegion;
@@ -10984,8 +11524,8 @@ OMPClause *Sema::ActOnOpenMPIfClause(OpenMPDirectiveKind NameModifier,
ValExpr = Val.get();
OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
- CaptureRegion =
- getOpenMPCaptureRegionForClause(DKind, OMPC_if, NameModifier);
+ CaptureRegion = getOpenMPCaptureRegionForClause(
+ DKind, OMPC_if, LangOpts.OpenMP, NameModifier);
if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) {
ValExpr = MakeFullExpr(ValExpr).get();
llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
@@ -11016,7 +11556,8 @@ OMPClause *Sema::ActOnOpenMPFinalClause(Expr *Condition,
ValExpr = MakeFullExpr(Val.get()).get();
OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
- CaptureRegion = getOpenMPCaptureRegionForClause(DKind, OMPC_final);
+ CaptureRegion =
+ getOpenMPCaptureRegionForClause(DKind, OMPC_final, LangOpts.OpenMP);
if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) {
ValExpr = MakeFullExpr(ValExpr).get();
llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
@@ -11101,7 +11642,8 @@ isNonNegativeIntegerValue(Expr *&ValExpr, Sema &SemaRef, OpenMPClauseKind CKind,
}
if (!BuildCapture)
return true;
- *CaptureRegion = getOpenMPCaptureRegionForClause(DKind, CKind);
+ *CaptureRegion =
+ getOpenMPCaptureRegionForClause(DKind, CKind, SemaRef.LangOpts.OpenMP);
if (*CaptureRegion != OMPD_unknown &&
!SemaRef.CurContext->isDependentContext()) {
ValExpr = SemaRef.MakeFullExpr(ValExpr).get();
@@ -11128,7 +11670,7 @@ OMPClause *Sema::ActOnOpenMPNumThreadsClause(Expr *NumThreads,
OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
OpenMPDirectiveKind CaptureRegion =
- getOpenMPCaptureRegionForClause(DKind, OMPC_num_threads);
+ getOpenMPCaptureRegionForClause(DKind, OMPC_num_threads, LangOpts.OpenMP);
if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) {
ValExpr = MakeFullExpr(ValExpr).get();
llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
@@ -11315,9 +11857,8 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
ArgumentLoc, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_proc_bind:
- Res = ActOnOpenMPProcBindClause(
- static_cast<OpenMPProcBindClauseKind>(Argument), ArgumentLoc, StartLoc,
- LParenLoc, EndLoc);
+ Res = ActOnOpenMPProcBindClause(static_cast<ProcBindKind>(Argument),
+ ArgumentLoc, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_atomic_default_mem_order:
Res = ActOnOpenMPAtomicDefaultMemOrderClause(
@@ -11381,6 +11922,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
case OMPC_dynamic_allocators:
case OMPC_device_type:
case OMPC_match:
+ case OMPC_nontemporal:
llvm_unreachable("Clause is not allowed.");
}
return Res;
@@ -11391,7 +11933,6 @@ getListOfPossibleValues(OpenMPClauseKind K, unsigned First, unsigned Last,
ArrayRef<unsigned> Exclude = llvm::None) {
SmallString<256> Buffer;
llvm::raw_svector_ostream Out(Buffer);
- unsigned Bound = Last >= 2 ? Last - 2 : 0;
unsigned Skipped = Exclude.size();
auto S = Exclude.begin(), E = Exclude.end();
for (unsigned I = First; I < Last; ++I) {
@@ -11400,9 +11941,9 @@ getListOfPossibleValues(OpenMPClauseKind K, unsigned First, unsigned Last,
continue;
}
Out << "'" << getOpenMPSimpleClauseTypeName(K, I) << "'";
- if (I == Bound - Skipped)
+ if (I + Skipped + 2 == Last)
Out << " or ";
- else if (I != Bound + 1 - Skipped)
+ else if (I + Skipped + 1 != Last)
Out << ", ";
}
return Out.str();
@@ -11437,15 +11978,16 @@ OMPClause *Sema::ActOnOpenMPDefaultClause(OpenMPDefaultClauseKind Kind,
OMPDefaultClause(Kind, KindKwLoc, StartLoc, LParenLoc, EndLoc);
}
-OMPClause *Sema::ActOnOpenMPProcBindClause(OpenMPProcBindClauseKind Kind,
+OMPClause *Sema::ActOnOpenMPProcBindClause(ProcBindKind Kind,
SourceLocation KindKwLoc,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
- if (Kind == OMPC_PROC_BIND_unknown) {
+ if (Kind == OMP_PROC_BIND_unknown) {
Diag(KindKwLoc, diag::err_omp_unexpected_clause_value)
- << getListOfPossibleValues(OMPC_proc_bind, /*First=*/0,
- /*Last=*/OMPC_PROC_BIND_unknown)
+ << getListOfPossibleValues(OMPC_proc_bind,
+ /*First=*/unsigned(OMP_PROC_BIND_master),
+ /*Last=*/5)
<< getOpenMPClauseName(OMPC_proc_bind);
return nullptr;
}
@@ -11561,6 +12103,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
case OMPC_atomic_default_mem_order:
case OMPC_device_type:
case OMPC_match:
+ case OMPC_nontemporal:
llvm_unreachable("Clause is not allowed.");
}
return Res;
@@ -11659,8 +12202,8 @@ OMPClause *Sema::ActOnOpenMPScheduleClause(
return nullptr;
}
} else if (getOpenMPCaptureRegionForClause(
- DSAStack->getCurrentDirective(), OMPC_schedule) !=
- OMPD_unknown &&
+ DSAStack->getCurrentDirective(), OMPC_schedule,
+ LangOpts.OpenMP) != OMPD_unknown &&
!CurContext->isDependentContext()) {
ValExpr = MakeFullExpr(ValExpr).get();
llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
@@ -11772,6 +12315,7 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind,
case OMPC_atomic_default_mem_order:
case OMPC_device_type:
case OMPC_match:
+ case OMPC_nontemporal:
llvm_unreachable("Clause is not allowed.");
}
return Res;
@@ -11857,11 +12401,10 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
OpenMPClauseKind Kind, ArrayRef<Expr *> VarList, Expr *TailExpr,
const OMPVarListLocTy &Locs, SourceLocation ColonLoc,
CXXScopeSpec &ReductionOrMapperIdScopeSpec,
- DeclarationNameInfo &ReductionOrMapperId, OpenMPDependClauseKind DepKind,
- OpenMPLinearClauseKind LinKind,
+ DeclarationNameInfo &ReductionOrMapperId, int ExtraModifier,
ArrayRef<OpenMPMapModifierKind> MapTypeModifiers,
- ArrayRef<SourceLocation> MapTypeModifiersLoc, OpenMPMapClauseKind MapType,
- bool IsMapTypeImplicit, SourceLocation DepLinMapLoc) {
+ ArrayRef<SourceLocation> MapTypeModifiersLoc, bool IsMapTypeImplicit,
+ SourceLocation DepLinMapLastLoc) {
SourceLocation StartLoc = Locs.StartLoc;
SourceLocation LParenLoc = Locs.LParenLoc;
SourceLocation EndLoc = Locs.EndLoc;
@@ -11874,7 +12417,11 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
Res = ActOnOpenMPFirstprivateClause(VarList, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_lastprivate:
- Res = ActOnOpenMPLastprivateClause(VarList, StartLoc, LParenLoc, EndLoc);
+ assert(0 <= ExtraModifier && ExtraModifier <= OMPC_LASTPRIVATE_unknown &&
+ "Unexpected lastprivate modifier.");
+ Res = ActOnOpenMPLastprivateClause(
+ VarList, static_cast<OpenMPLastprivateModifier>(ExtraModifier),
+ DepLinMapLastLoc, ColonLoc, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_shared:
Res = ActOnOpenMPSharedClause(VarList, StartLoc, LParenLoc, EndLoc);
@@ -11895,8 +12442,12 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
ReductionOrMapperId);
break;
case OMPC_linear:
- Res = ActOnOpenMPLinearClause(VarList, TailExpr, StartLoc, LParenLoc,
- LinKind, DepLinMapLoc, ColonLoc, EndLoc);
+ assert(0 <= ExtraModifier && ExtraModifier <= OMPC_LINEAR_unknown &&
+ "Unexpected linear modifier.");
+ Res = ActOnOpenMPLinearClause(
+ VarList, TailExpr, StartLoc, LParenLoc,
+ static_cast<OpenMPLinearClauseKind>(ExtraModifier), DepLinMapLastLoc,
+ ColonLoc, EndLoc);
break;
case OMPC_aligned:
Res = ActOnOpenMPAlignedClause(VarList, TailExpr, StartLoc, LParenLoc,
@@ -11912,14 +12463,19 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
Res = ActOnOpenMPFlushClause(VarList, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_depend:
- Res = ActOnOpenMPDependClause(DepKind, DepLinMapLoc, ColonLoc, VarList,
- StartLoc, LParenLoc, EndLoc);
+ assert(0 <= ExtraModifier && ExtraModifier <= OMPC_DEPEND_unknown &&
+ "Unexpected depend modifier.");
+ Res = ActOnOpenMPDependClause(
+ static_cast<OpenMPDependClauseKind>(ExtraModifier), DepLinMapLastLoc,
+ ColonLoc, VarList, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_map:
- Res = ActOnOpenMPMapClause(MapTypeModifiers, MapTypeModifiersLoc,
- ReductionOrMapperIdScopeSpec,
- ReductionOrMapperId, MapType, IsMapTypeImplicit,
- DepLinMapLoc, ColonLoc, VarList, Locs);
+ assert(0 <= ExtraModifier && ExtraModifier <= OMPC_MAP_unknown &&
+ "Unexpected map modifier.");
+ Res = ActOnOpenMPMapClause(
+ MapTypeModifiers, MapTypeModifiersLoc, ReductionOrMapperIdScopeSpec,
+ ReductionOrMapperId, static_cast<OpenMPMapClauseKind>(ExtraModifier),
+ IsMapTypeImplicit, DepLinMapLastLoc, ColonLoc, VarList, Locs);
break;
case OMPC_to:
Res = ActOnOpenMPToClause(VarList, ReductionOrMapperIdScopeSpec,
@@ -11939,6 +12495,9 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
Res = ActOnOpenMPAllocateClause(TailExpr, VarList, StartLoc, LParenLoc,
ColonLoc, EndLoc);
break;
+ case OMPC_nontemporal:
+ Res = ActOnOpenMPNontemporalClause(VarList, StartLoc, LParenLoc, EndLoc);
+ break;
case OMPC_if:
case OMPC_final:
case OMPC_num_threads:
@@ -12442,10 +13001,19 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
buildPreInits(Context, ExprCaptures));
}
-OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList,
- SourceLocation StartLoc,
- SourceLocation LParenLoc,
- SourceLocation EndLoc) {
+OMPClause *Sema::ActOnOpenMPLastprivateClause(
+ ArrayRef<Expr *> VarList, OpenMPLastprivateModifier LPKind,
+ SourceLocation LPKindLoc, SourceLocation ColonLoc, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation EndLoc) {
+ if (LPKind == OMPC_LASTPRIVATE_unknown && LPKindLoc.isValid()) {
+ assert(ColonLoc.isValid() && "Colon location must be valid.");
+ Diag(LPKindLoc, diag::err_omp_unexpected_clause_value)
+ << getListOfPossibleValues(OMPC_lastprivate, /*First=*/0,
+ /*Last=*/OMPC_LASTPRIVATE_unknown)
+ << getOpenMPClauseName(OMPC_lastprivate);
+ return nullptr;
+ }
+
SmallVector<Expr *, 8> Vars;
SmallVector<Expr *, 8> SrcExprs;
SmallVector<Expr *, 8> DstExprs;
@@ -12491,6 +13059,19 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList,
if (rejectConstNotMutableType(*this, D, Type, OMPC_lastprivate, ELoc))
continue;
+ // OpenMP 5.0 [2.19.4.5 lastprivate Clause, Restrictions]
+ // A list item that appears in a lastprivate clause with the conditional
+ // modifier must be a scalar variable.
+ if (LPKind == OMPC_LASTPRIVATE_conditional && !Type->isScalarType()) {
+ Diag(ELoc, diag::err_omp_lastprivate_conditional_non_scalar);
+ bool IsDecl = !VD || VD->isThisDeclarationADefinition(Context) ==
+ VarDecl::DeclarationOnly;
+ Diag(D->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << D;
+ continue;
+ }
+
OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective();
// OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a Construct]
@@ -12599,6 +13180,7 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList,
return OMPLastprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc,
Vars, SrcExprs, DstExprs, AssignmentOps,
+ LPKind, LPKindLoc, ColonLoc,
buildPreInits(Context, ExprCaptures),
buildPostUpdate(*this, ExprPostUpdates));
}
@@ -12916,7 +13498,8 @@ buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range,
}
}
if (ReductionIdScopeSpec.isSet()) {
- SemaRef.Diag(Loc, diag::err_omp_not_resolved_reduction_identifier) << Range;
+ SemaRef.Diag(Loc, diag::err_omp_not_resolved_reduction_identifier)
+ << Ty << Range;
return ExprError();
}
return ExprEmpty();
@@ -13771,8 +14354,8 @@ bool Sema::CheckOpenMPLinearDecl(const ValueDecl *D, SourceLocation ELoc,
// A list item must be of integral or pointer type.
Type = Type.getUnqualifiedType().getCanonicalType();
const auto *Ty = Type.getTypePtrOrNull();
- if (!Ty || (!Ty->isDependentType() && !Ty->isIntegralType(Context) &&
- !Ty->isPointerType())) {
+ if (!Ty || (LinKind != OMPC_LINEAR_ref && !Ty->isDependentType() &&
+ !Ty->isIntegralType(Context) && !Ty->isPointerType())) {
Diag(ELoc, diag::err_omp_linear_expected_int_or_ptr) << Type;
if (D) {
bool IsDecl =
@@ -14066,7 +14649,8 @@ OMPClause *Sema::ActOnOpenMPAlignedClause(
// OpenMP [2.8.1, simd construct, Restrictions]
// A list-item cannot appear in more than one aligned clause.
if (const Expr *PrevRef = DSAStack->addUniqueAligned(D, SimpleRefExpr)) {
- Diag(ELoc, diag::err_omp_aligned_twice) << 0 << ERange;
+ Diag(ELoc, diag::err_omp_used_in_clause_twice)
+ << 0 << getOpenMPClauseName(OMPC_aligned) << ERange;
Diag(PrevRef->getExprLoc(), diag::note_omp_explicit_dsa)
<< getOpenMPClauseName(OMPC_aligned);
continue;
@@ -14437,6 +15021,22 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind,
}
OpsOffs.emplace_back(RHS, OOK);
} else {
+ // OpenMP 5.0 [2.17.11, Restrictions]
+ // List items used in depend clauses cannot be zero-length array sections.
+ const auto *OASE = dyn_cast<OMPArraySectionExpr>(SimpleExpr);
+ if (OASE) {
+ const Expr *Length = OASE->getLength();
+ Expr::EvalResult Result;
+ if (Length && !Length->isValueDependent() &&
+ Length->EvaluateAsInt(Result, Context) &&
+ Result.Val.getInt().isNullValue()) {
+ Diag(ELoc,
+ diag::err_omp_depend_zero_length_array_section_not_allowed)
+ << SimpleExpr->getSourceRange();
+ continue;
+ }
+ }
+
auto *ASE = dyn_cast<ArraySubscriptExpr>(SimpleExpr);
if (!RefExpr->IgnoreParenImpCasts()->isLValue() ||
(ASE &&
@@ -14496,7 +15096,7 @@ OMPClause *Sema::ActOnOpenMPDeviceClause(Expr *Device, SourceLocation StartLoc,
OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
OpenMPDirectiveKind CaptureRegion =
- getOpenMPCaptureRegionForClause(DKind, OMPC_device);
+ getOpenMPCaptureRegionForClause(DKind, OMPC_device, LangOpts.OpenMP);
if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) {
ValExpr = MakeFullExpr(ValExpr).get();
llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
@@ -14517,7 +15117,7 @@ static bool checkTypeMappable(SourceLocation SL, SourceRange SR, Sema &SemaRef,
return false;
}
if (FullCheck && !SemaRef.CurContext->isDependentContext() &&
- !QTy.isTrivialType(SemaRef.Context))
+ !QTy.isTriviallyCopyableType(SemaRef.Context))
SemaRef.Diag(SL, diag::warn_omp_non_trivial_type_mapped) << QTy << SR;
return true;
}
@@ -15408,8 +16008,22 @@ static void checkMappableExpressionList(
return MC.getAssociatedDeclaration();
});
assert(I != CurComponents.end() && "Null decl on map clause.");
- QualType Type =
- I->getAssociatedDeclaration()->getType().getNonReferenceType();
+ QualType Type;
+ auto *ASE = dyn_cast<ArraySubscriptExpr>(VE->IgnoreParens());
+ auto *OASE = dyn_cast<OMPArraySectionExpr>(VE->IgnoreParens());
+ if (ASE) {
+ Type = ASE->getType().getNonReferenceType();
+ } else if (OASE) {
+ QualType BaseType =
+ OMPArraySectionExpr::getBaseOriginalType(OASE->getBase());
+ if (const auto *ATy = BaseType->getAsArrayTypeUnsafe())
+ Type = ATy->getElementType();
+ else
+ Type = BaseType->getPointeeType();
+ Type = Type.getNonReferenceType();
+ } else {
+ Type = VE->getType();
+ }
// OpenMP 4.5 [2.10.5, target update Construct, Restrictions, p.4]
// A list item in a to or from clause must have a mappable type.
@@ -15419,6 +16033,8 @@ static void checkMappableExpressionList(
DSAS, Type))
continue;
+ Type = I->getAssociatedDeclaration()->getType().getNonReferenceType();
+
if (CKind == OMPC_map) {
// target enter data
// OpenMP [2.10.2, Restrictions, p. 99]
@@ -15948,7 +16564,7 @@ OMPClause *Sema::ActOnOpenMPNumTeamsClause(Expr *NumTeams,
OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
OpenMPDirectiveKind CaptureRegion =
- getOpenMPCaptureRegionForClause(DKind, OMPC_num_teams);
+ getOpenMPCaptureRegionForClause(DKind, OMPC_num_teams, LangOpts.OpenMP);
if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) {
ValExpr = MakeFullExpr(ValExpr).get();
llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
@@ -15974,8 +16590,8 @@ OMPClause *Sema::ActOnOpenMPThreadLimitClause(Expr *ThreadLimit,
return nullptr;
OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
- OpenMPDirectiveKind CaptureRegion =
- getOpenMPCaptureRegionForClause(DKind, OMPC_thread_limit);
+ OpenMPDirectiveKind CaptureRegion = getOpenMPCaptureRegionForClause(
+ DKind, OMPC_thread_limit, LangOpts.OpenMP);
if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) {
ValExpr = MakeFullExpr(ValExpr).get();
llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
@@ -16100,8 +16716,8 @@ OMPClause *Sema::ActOnOpenMPDistScheduleClause(
return nullptr;
}
} else if (getOpenMPCaptureRegionForClause(
- DSAStack->getCurrentDirective(), OMPC_dist_schedule) !=
- OMPD_unknown &&
+ DSAStack->getCurrentDirective(), OMPC_dist_schedule,
+ LangOpts.OpenMP) != OMPD_unknown &&
!CurContext->isDependentContext()) {
ValExpr = MakeFullExpr(ValExpr).get();
llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
@@ -16120,26 +16736,57 @@ OMPClause *Sema::ActOnOpenMPDefaultmapClause(
OpenMPDefaultmapClauseModifier M, OpenMPDefaultmapClauseKind Kind,
SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation MLoc,
SourceLocation KindLoc, SourceLocation EndLoc) {
- // OpenMP 4.5 only supports 'defaultmap(tofrom: scalar)'
- if (M != OMPC_DEFAULTMAP_MODIFIER_tofrom || Kind != OMPC_DEFAULTMAP_scalar) {
- std::string Value;
- SourceLocation Loc;
- Value += "'";
- if (M != OMPC_DEFAULTMAP_MODIFIER_tofrom) {
- Value += getOpenMPSimpleClauseTypeName(OMPC_defaultmap,
- OMPC_DEFAULTMAP_MODIFIER_tofrom);
- Loc = MLoc;
- } else {
- Value += getOpenMPSimpleClauseTypeName(OMPC_defaultmap,
- OMPC_DEFAULTMAP_scalar);
- Loc = KindLoc;
+ if (getLangOpts().OpenMP < 50) {
+ if (M != OMPC_DEFAULTMAP_MODIFIER_tofrom ||
+ Kind != OMPC_DEFAULTMAP_scalar) {
+ std::string Value;
+ SourceLocation Loc;
+ Value += "'";
+ if (M != OMPC_DEFAULTMAP_MODIFIER_tofrom) {
+ Value += getOpenMPSimpleClauseTypeName(OMPC_defaultmap,
+ OMPC_DEFAULTMAP_MODIFIER_tofrom);
+ Loc = MLoc;
+ } else {
+ Value += getOpenMPSimpleClauseTypeName(OMPC_defaultmap,
+ OMPC_DEFAULTMAP_scalar);
+ Loc = KindLoc;
+ }
+ Value += "'";
+ Diag(Loc, diag::err_omp_unexpected_clause_value)
+ << Value << getOpenMPClauseName(OMPC_defaultmap);
+ return nullptr;
+ }
+ } else {
+ bool isDefaultmapModifier = (M != OMPC_DEFAULTMAP_MODIFIER_unknown);
+ bool isDefaultmapKind = (Kind != OMPC_DEFAULTMAP_unknown);
+ if (!isDefaultmapKind || !isDefaultmapModifier) {
+ std::string ModifierValue = "'alloc', 'from', 'to', 'tofrom', "
+ "'firstprivate', 'none', 'default'";
+ std::string KindValue = "'scalar', 'aggregate', 'pointer'";
+ if (!isDefaultmapKind && isDefaultmapModifier) {
+ Diag(KindLoc, diag::err_omp_unexpected_clause_value)
+ << KindValue << getOpenMPClauseName(OMPC_defaultmap);
+ } else if (isDefaultmapKind && !isDefaultmapModifier) {
+ Diag(MLoc, diag::err_omp_unexpected_clause_value)
+ << ModifierValue << getOpenMPClauseName(OMPC_defaultmap);
+ } else {
+ Diag(MLoc, diag::err_omp_unexpected_clause_value)
+ << ModifierValue << getOpenMPClauseName(OMPC_defaultmap);
+ Diag(KindLoc, diag::err_omp_unexpected_clause_value)
+ << KindValue << getOpenMPClauseName(OMPC_defaultmap);
+ }
+ return nullptr;
+ }
+
+ // OpenMP [5.0, 2.12.5, Restrictions, p. 174]
+ // At most one defaultmap clause for each category can appear on the
+ // directive.
+ if (DSAStack->checkDefaultmapCategory(Kind)) {
+ Diag(StartLoc, diag::err_omp_one_defaultmap_each_category);
+ return nullptr;
}
- Value += "'";
- Diag(Loc, diag::err_omp_unexpected_clause_value)
- << Value << getOpenMPClauseName(OMPC_defaultmap);
- return nullptr;
}
- DSAStack->setDefaultDMAToFromScalar(StartLoc);
+ DSAStack->setDefaultDMAAttr(M, Kind, StartLoc);
return new (Context)
OMPDefaultmapClause(StartLoc, LParenLoc, MLoc, KindLoc, EndLoc, Kind, M);
@@ -16604,3 +17251,42 @@ OMPClause *Sema::ActOnOpenMPAllocateClause(
return OMPAllocateClause::Create(Context, StartLoc, LParenLoc, Allocator,
ColonLoc, EndLoc, Vars);
}
+
+OMPClause *Sema::ActOnOpenMPNontemporalClause(ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ SmallVector<Expr *, 8> Vars;
+ for (Expr *RefExpr : VarList) {
+ assert(RefExpr && "NULL expr in OpenMP nontemporal clause.");
+ SourceLocation ELoc;
+ SourceRange ERange;
+ Expr *SimpleRefExpr = RefExpr;
+ auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange);
+ if (Res.second)
+ // It will be analyzed later.
+ Vars.push_back(RefExpr);
+ ValueDecl *D = Res.first;
+ if (!D)
+ continue;
+
+ // OpenMP 5.0, 2.9.3.1 simd Construct, Restrictions.
+ // A list-item cannot appear in more than one nontemporal clause.
+ if (const Expr *PrevRef =
+ DSAStack->addUniqueNontemporal(D, SimpleRefExpr)) {
+ Diag(ELoc, diag::err_omp_used_in_clause_twice)
+ << 0 << getOpenMPClauseName(OMPC_nontemporal) << ERange;
+ Diag(PrevRef->getExprLoc(), diag::note_omp_explicit_dsa)
+ << getOpenMPClauseName(OMPC_nontemporal);
+ continue;
+ }
+
+ Vars.push_back(RefExpr);
+ }
+
+ if (Vars.empty())
+ return nullptr;
+
+ return OMPNontemporalClause::Create(Context, StartLoc, LParenLoc, EndLoc,
+ Vars);
+}
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 47c1e3cec0ea..0fd932fac970 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -60,14 +60,18 @@ CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn, NamedDecl *FoundDecl,
// being used.
if (FoundDecl != Fn && S.DiagnoseUseOfDecl(Fn, Loc))
return ExprError();
- if (auto *FPT = Fn->getType()->getAs<FunctionProtoType>())
- S.ResolveExceptionSpec(Loc, FPT);
DeclRefExpr *DRE = new (S.Context)
DeclRefExpr(S.Context, Fn, false, Fn->getType(), VK_LValue, Loc, LocInfo);
if (HadMultipleCandidates)
DRE->setHadMultipleCandidates(true);
S.MarkDeclRefReferenced(DRE, Base);
+ if (auto *FPT = DRE->getType()->getAs<FunctionProtoType>()) {
+ if (isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) {
+ S.ResolveExceptionSpec(Loc, FPT);
+ DRE->setType(Fn->getType());
+ }
+ }
return S.ImpCastExprToType(DRE, S.Context.getPointerType(DRE->getType()),
CK_FunctionToPointerDecay);
}
@@ -591,6 +595,12 @@ namespace {
TemplateArgumentList *TemplateArgs;
unsigned CallArgIndex;
};
+ // Structure used by DeductionFailureInfo to store information about
+ // unsatisfied constraints.
+ struct CNSInfo {
+ TemplateArgumentList *TemplateArgs;
+ ConstraintSatisfaction Satisfaction;
+ };
}
/// Convert from Sema's representation of template deduction information
@@ -661,6 +671,14 @@ clang::MakeDeductionFailureInfo(ASTContext &Context,
}
break;
+ case Sema::TDK_ConstraintsNotSatisfied: {
+ CNSInfo *Saved = new (Context) CNSInfo;
+ Saved->TemplateArgs = Info.take();
+ Saved->Satisfaction = Info.AssociatedConstraintsSatisfaction;
+ Result.Data = Saved;
+ break;
+ }
+
case Sema::TDK_Success:
case Sema::TDK_NonDependentConversionFailure:
llvm_unreachable("not a deduction failure");
@@ -701,6 +719,15 @@ void DeductionFailureInfo::Destroy() {
}
break;
+ case Sema::TDK_ConstraintsNotSatisfied:
+ // FIXME: Destroy the template argument list?
+ Data = nullptr;
+ if (PartialDiagnosticAt *Diag = getSFINAEDiagnostic()) {
+ Diag->~PartialDiagnosticAt();
+ HasDiagnostic = false;
+ }
+ break;
+
// Unhandled
case Sema::TDK_MiscellaneousDeductionFailure:
break;
@@ -726,6 +753,7 @@ TemplateParameter DeductionFailureInfo::getTemplateParameter() {
case Sema::TDK_NonDeducedMismatch:
case Sema::TDK_CUDATargetMismatch:
case Sema::TDK_NonDependentConversionFailure:
+ case Sema::TDK_ConstraintsNotSatisfied:
return TemplateParameter();
case Sema::TDK_Incomplete:
@@ -769,6 +797,9 @@ TemplateArgumentList *DeductionFailureInfo::getTemplateArgumentList() {
case Sema::TDK_SubstitutionFailure:
return static_cast<TemplateArgumentList*>(Data);
+ case Sema::TDK_ConstraintsNotSatisfied:
+ return static_cast<CNSInfo*>(Data)->TemplateArgs;
+
// Unhandled
case Sema::TDK_MiscellaneousDeductionFailure:
break;
@@ -789,6 +820,7 @@ const TemplateArgument *DeductionFailureInfo::getFirstArg() {
case Sema::TDK_SubstitutionFailure:
case Sema::TDK_CUDATargetMismatch:
case Sema::TDK_NonDependentConversionFailure:
+ case Sema::TDK_ConstraintsNotSatisfied:
return nullptr;
case Sema::TDK_IncompletePack:
@@ -820,6 +852,7 @@ const TemplateArgument *DeductionFailureInfo::getSecondArg() {
case Sema::TDK_SubstitutionFailure:
case Sema::TDK_CUDATargetMismatch:
case Sema::TDK_NonDependentConversionFailure:
+ case Sema::TDK_ConstraintsNotSatisfied:
return nullptr;
case Sema::TDK_Inconsistent:
@@ -1104,7 +1137,8 @@ Sema::CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &Old,
}
bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
- bool UseMemberUsingDeclRules, bool ConsiderCudaAttrs) {
+ bool UseMemberUsingDeclRules, bool ConsiderCudaAttrs,
+ bool ConsiderRequiresClauses) {
// C++ [basic.start.main]p2: This function shall not be overloaded.
if (New->isMain())
return false;
@@ -1240,19 +1274,36 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
if (getLangOpts().CUDA && ConsiderCudaAttrs) {
// Don't allow overloading of destructors. (In theory we could, but it
// would be a giant change to clang.)
- if (isa<CXXDestructorDecl>(New))
- return false;
-
- CUDAFunctionTarget NewTarget = IdentifyCUDATarget(New),
- OldTarget = IdentifyCUDATarget(Old);
- if (NewTarget == CFT_InvalidTarget)
- return false;
+ if (!isa<CXXDestructorDecl>(New)) {
+ CUDAFunctionTarget NewTarget = IdentifyCUDATarget(New),
+ OldTarget = IdentifyCUDATarget(Old);
+ if (NewTarget != CFT_InvalidTarget) {
+ assert((OldTarget != CFT_InvalidTarget) &&
+ "Unexpected invalid target.");
+
+ // Allow overloading of functions with same signature and different CUDA
+ // target attributes.
+ if (NewTarget != OldTarget)
+ return true;
+ }
+ }
+ }
- assert((OldTarget != CFT_InvalidTarget) && "Unexpected invalid target.");
+ if (ConsiderRequiresClauses) {
+ Expr *NewRC = New->getTrailingRequiresClause(),
+ *OldRC = Old->getTrailingRequiresClause();
+ if ((NewRC != nullptr) != (OldRC != nullptr))
+ // RC are most certainly different - these are overloads.
+ return true;
- // Allow overloading of functions with same signature and different CUDA
- // target attributes.
- return NewTarget != OldTarget;
+ if (NewRC) {
+ llvm::FoldingSetNodeID NewID, OldID;
+ NewRC->Profile(NewID, Context, /*Canonical=*/true);
+ OldRC->Profile(OldID, Context, /*Canonical=*/true);
+ if (NewID != OldID)
+ // RCs are not equivalent - these are overloads.
+ return true;
+ }
}
// The signatures match; this is not an overload.
@@ -1326,7 +1377,7 @@ TryUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
ICS.Ambiguous.setToType(ToType);
for (OverloadCandidateSet::iterator Cand = Conversions.begin();
Cand != Conversions.end(); ++Cand)
- if (Cand->Viable)
+ if (Cand->Best)
ICS.Ambiguous.addConversion(Cand->FoundDecl, Cand->Function);
break;
@@ -2802,8 +2853,8 @@ void Sema::HandleFunctionTypeMismatch(PartialDiagnostic &PDiag,
// Get the function type from the pointers.
if (FromType->isMemberPointerType() && ToType->isMemberPointerType()) {
- const MemberPointerType *FromMember = FromType->getAs<MemberPointerType>(),
- *ToMember = ToType->getAs<MemberPointerType>();
+ const auto *FromMember = FromType->castAs<MemberPointerType>(),
+ *ToMember = ToType->castAs<MemberPointerType>();
if (!Context.hasSameType(FromMember->getClass(), ToMember->getClass())) {
PDiag << ft_different_class << QualType(ToMember->getClass(), 0)
<< QualType(FromMember->getClass(), 0);
@@ -2898,8 +2949,12 @@ bool Sema::FunctionParamTypesAreEqual(const FunctionProtoType *OldType,
N = NewType->param_type_begin(),
E = OldType->param_type_end();
O && (O != E); ++O, ++N) {
- if (!Context.hasSameType(O->getUnqualifiedType(),
- N->getUnqualifiedType())) {
+ // 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());
+
+ if (!Context.hasSameType(Old, New)) {
if (ArgPos)
*ArgPos = O - OldType->param_type_begin();
return false;
@@ -3114,6 +3169,70 @@ static bool isNonTrivialObjCLifetimeConversion(Qualifiers FromQuals,
return true;
}
+/// Perform a single iteration of the loop for checking if a qualification
+/// conversion is valid.
+///
+/// Specifically, check whether any change between the qualifiers of \p
+/// FromType and \p ToType is permissible, given knowledge about whether every
+/// outer layer is const-qualified.
+static bool isQualificationConversionStep(QualType FromType, QualType ToType,
+ bool CStyle,
+ bool &PreviousToQualsIncludeConst,
+ bool &ObjCLifetimeConversion) {
+ Qualifiers FromQuals = FromType.getQualifiers();
+ Qualifiers ToQuals = ToType.getQualifiers();
+
+ // Ignore __unaligned qualifier if this type is void.
+ if (ToType.getUnqualifiedType()->isVoidType())
+ FromQuals.removeUnaligned();
+
+ // Objective-C ARC:
+ // Check Objective-C lifetime conversions.
+ if (FromQuals.getObjCLifetime() != ToQuals.getObjCLifetime()) {
+ if (ToQuals.compatiblyIncludesObjCLifetime(FromQuals)) {
+ if (isNonTrivialObjCLifetimeConversion(FromQuals, ToQuals))
+ ObjCLifetimeConversion = true;
+ FromQuals.removeObjCLifetime();
+ ToQuals.removeObjCLifetime();
+ } else {
+ // Qualification conversions cannot cast between different
+ // Objective-C lifetime qualifiers.
+ return false;
+ }
+ }
+
+ // Allow addition/removal of GC attributes but not changing GC attributes.
+ if (FromQuals.getObjCGCAttr() != ToQuals.getObjCGCAttr() &&
+ (!FromQuals.hasObjCGCAttr() || !ToQuals.hasObjCGCAttr())) {
+ FromQuals.removeObjCGCAttr();
+ ToQuals.removeObjCGCAttr();
+ }
+
+ // -- for every j > 0, if const is in cv 1,j then const is in cv
+ // 2,j, and similarly for volatile.
+ if (!CStyle && !ToQuals.compatiblyIncludes(FromQuals))
+ return false;
+
+ // For a C-style cast, just require the address spaces to overlap.
+ // FIXME: Does "superset" also imply the representation of a pointer is the
+ // same? We're assuming that it does here and in compatiblyIncludes.
+ if (CStyle && !ToQuals.isAddressSpaceSupersetOf(FromQuals) &&
+ !FromQuals.isAddressSpaceSupersetOf(ToQuals))
+ return false;
+
+ // -- if the cv 1,j and cv 2,j are different, then const is in
+ // every cv for 0 < k < j.
+ if (!CStyle && FromQuals.getCVRQualifiers() != ToQuals.getCVRQualifiers() &&
+ !PreviousToQualsIncludeConst)
+ return false;
+
+ // Keep track of whether all prior cv-qualifiers in the "to" type
+ // include const.
+ PreviousToQualsIncludeConst =
+ PreviousToQualsIncludeConst && ToQuals.hasConst();
+ return true;
+}
+
/// IsQualificationConversion - Determines whether the conversion from
/// an rvalue of type FromType to ToType is a qualification conversion
/// (C++ 4.4).
@@ -3139,73 +3258,16 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType,
bool PreviousToQualsIncludeConst = true;
bool UnwrappedAnyPointer = false;
while (Context.UnwrapSimilarTypes(FromType, ToType)) {
- // Within each iteration of the loop, we check the qualifiers to
- // determine if this still looks like a qualification
- // conversion. Then, if all is well, we unwrap one more level of
- // pointers or pointers-to-members and do it all again
- // until there are no more pointers or pointers-to-members left to
- // unwrap.
- UnwrappedAnyPointer = true;
-
- Qualifiers FromQuals = FromType.getQualifiers();
- Qualifiers ToQuals = ToType.getQualifiers();
-
- // Ignore __unaligned qualifier if this type is void.
- if (ToType.getUnqualifiedType()->isVoidType())
- FromQuals.removeUnaligned();
-
- // Objective-C ARC:
- // Check Objective-C lifetime conversions.
- if (FromQuals.getObjCLifetime() != ToQuals.getObjCLifetime() &&
- UnwrappedAnyPointer) {
- if (ToQuals.compatiblyIncludesObjCLifetime(FromQuals)) {
- if (isNonTrivialObjCLifetimeConversion(FromQuals, ToQuals))
- ObjCLifetimeConversion = true;
- FromQuals.removeObjCLifetime();
- ToQuals.removeObjCLifetime();
- } else {
- // Qualification conversions cannot cast between different
- // Objective-C lifetime qualifiers.
- return false;
- }
- }
-
- // Allow addition/removal of GC attributes but not changing GC attributes.
- if (FromQuals.getObjCGCAttr() != ToQuals.getObjCGCAttr() &&
- (!FromQuals.hasObjCGCAttr() || !ToQuals.hasObjCGCAttr())) {
- FromQuals.removeObjCGCAttr();
- ToQuals.removeObjCGCAttr();
- }
-
- // -- for every j > 0, if const is in cv 1,j then const is in cv
- // 2,j, and similarly for volatile.
- if (!CStyle && !ToQuals.compatiblyIncludes(FromQuals))
- return false;
-
- // -- if the cv 1,j and cv 2,j are different, then const is in
- // every cv for 0 < k < j.
- if (!CStyle && FromQuals.getCVRQualifiers() != ToQuals.getCVRQualifiers()
- && !PreviousToQualsIncludeConst)
+ if (!isQualificationConversionStep(FromType, ToType, CStyle,
+ PreviousToQualsIncludeConst,
+ ObjCLifetimeConversion))
return false;
-
- // Keep track of whether all prior cv-qualifiers in the "to" type
- // include const.
- PreviousToQualsIncludeConst
- = PreviousToQualsIncludeConst && ToQuals.hasConst();
- }
-
- // Allows address space promotion by language rules implemented in
- // Type::Qualifiers::isAddressSpaceSupersetOf.
- Qualifiers FromQuals = FromType.getQualifiers();
- Qualifiers ToQuals = ToType.getQualifiers();
- if (!ToQuals.isAddressSpaceSupersetOf(FromQuals) &&
- !FromQuals.isAddressSpaceSupersetOf(ToQuals)) {
- return false;
+ UnwrappedAnyPointer = true;
}
// We are left with FromType and ToType being the pointee types
// after unwrapping the original FromType and ToType the same number
- // of types. If we unwrapped any pointers, and if FromType and
+ // of times. If we unwrapped any pointers, and if FromType and
// ToType have the same unqualified type (since we checked
// qualifiers above), then this is a qualification conversion.
return UnwrappedAnyPointer && Context.hasSameUnqualifiedType(FromType,ToType);
@@ -3242,8 +3304,7 @@ static bool tryAtomicConversion(Sema &S, Expr *From, QualType ToType,
static bool isFirstArgumentCompatibleWithType(ASTContext &Context,
CXXConstructorDecl *Constructor,
QualType Type) {
- const FunctionProtoType *CtorType =
- Constructor->getType()->getAs<FunctionProtoType>();
+ const auto *CtorType = Constructor->getType()->castAs<FunctionProtoType>();
if (CtorType->getNumParams() > 0) {
QualType FirstArg = CtorType->getParamType(0);
if (Context.hasSameUnqualifiedType(Type, FirstArg.getNonReferenceType()))
@@ -3265,8 +3326,7 @@ IsInitializerListConstructorConversion(Sema &S, Expr *From, QualType ToType,
continue;
bool Usable = !Info.Constructor->isInvalidDecl() &&
- S.isInitListConstructor(Info.Constructor) &&
- (AllowExplicit || !Info.Constructor->isExplicit());
+ S.isInitListConstructor(Info.Constructor);
if (Usable) {
// If the first argument is (a reference to) the target type,
// suppress conversions.
@@ -3388,11 +3448,9 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
continue;
bool Usable = !Info.Constructor->isInvalidDecl();
- if (ListInitializing)
- Usable = Usable && (AllowExplicit || !Info.Constructor->isExplicit());
- else
- Usable = Usable &&
- Info.Constructor->isConvertingConstructor(AllowExplicit);
+ if (!ListInitializing)
+ Usable = Usable && Info.Constructor->isConvertingConstructor(
+ /*AllowExplicit*/ true);
if (Usable) {
bool SuppressUserConversions = !ConstructorsOnly;
if (SuppressUserConversions && ListInitializing) {
@@ -3446,16 +3504,14 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
else
Conv = cast<CXXConversionDecl>(D);
- if (AllowExplicit || !Conv->isExplicit()) {
- if (ConvTemplate)
- S.AddTemplateConversionCandidate(
- ConvTemplate, FoundDecl, ActingContext, From, ToType,
- CandidateSet, AllowObjCConversionOnExplicit, AllowExplicit);
- else
- S.AddConversionCandidate(
- Conv, FoundDecl, ActingContext, From, ToType, CandidateSet,
- AllowObjCConversionOnExplicit, AllowExplicit);
- }
+ if (ConvTemplate)
+ S.AddTemplateConversionCandidate(
+ ConvTemplate, FoundDecl, ActingContext, From, ToType,
+ CandidateSet, AllowObjCConversionOnExplicit, AllowExplicit);
+ else
+ S.AddConversionCandidate(
+ Conv, FoundDecl, ActingContext, From, ToType, CandidateSet,
+ AllowObjCConversionOnExplicit, AllowExplicit);
}
}
}
@@ -3547,7 +3603,10 @@ Sema::DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType) {
(OvResult == OR_No_Viable_Function && !CandidateSet.empty())))
return false;
- auto Cands = CandidateSet.CompleteCandidates(*this, OCD_AllCandidates, From);
+ auto Cands = CandidateSet.CompleteCandidates(
+ *this,
+ OvResult == OR_Ambiguous ? OCD_AmbiguousCandidates : OCD_AllCandidates,
+ From);
if (OvResult == OR_Ambiguous)
Diag(From->getBeginLoc(), diag::err_typecheck_ambiguous_condition)
<< From->getType() << ToType << From->getSourceRange();
@@ -3929,19 +3988,21 @@ CompareStandardConversionSequences(Sema &S, SourceLocation Loc,
}
}
- // Compare based on qualification conversions (C++ 13.3.3.2p3,
- // bullet 3).
- if (ImplicitConversionSequence::CompareKind QualCK
- = CompareQualificationConversions(S, SCS1, SCS2))
- return QualCK;
-
if (SCS1.ReferenceBinding && SCS2.ReferenceBinding) {
// Check for a better reference binding based on the kind of bindings.
if (isBetterReferenceBindingKind(SCS1, SCS2))
return ImplicitConversionSequence::Better;
else if (isBetterReferenceBindingKind(SCS2, SCS1))
return ImplicitConversionSequence::Worse;
+ }
+ // Compare based on qualification conversions (C++ 13.3.3.2p3,
+ // bullet 3).
+ if (ImplicitConversionSequence::CompareKind QualCK
+ = CompareQualificationConversions(S, SCS1, SCS2))
+ return QualCK;
+
+ if (SCS1.ReferenceBinding && SCS2.ReferenceBinding) {
// C++ [over.ics.rank]p3b4:
// -- S1 and S2 are reference bindings (8.5.3), and the types to
// which the references refer are the same type except for
@@ -3973,7 +4034,7 @@ CompareStandardConversionSequences(Sema &S, SourceLocation Loc,
T2 = S.Context.getQualifiedType(UnqualT2, T2Quals);
if (T2.isMoreQualifiedThan(T1))
return ImplicitConversionSequence::Better;
- else if (T1.isMoreQualifiedThan(T2))
+ if (T1.isMoreQualifiedThan(T2))
return ImplicitConversionSequence::Worse;
}
}
@@ -4047,22 +4108,16 @@ CompareQualificationConversions(Sema &S,
QualType T2 = SCS2.getToType(2);
T1 = S.Context.getCanonicalType(T1);
T2 = S.Context.getCanonicalType(T2);
+ assert(!T1->isReferenceType() && !T2->isReferenceType());
Qualifiers T1Quals, T2Quals;
QualType UnqualT1 = S.Context.getUnqualifiedArrayType(T1, T1Quals);
QualType UnqualT2 = S.Context.getUnqualifiedArrayType(T2, T2Quals);
- // If the types are the same, we won't learn anything by unwrapped
+ // If the types are the same, we won't learn anything by unwrapping
// them.
if (UnqualT1 == UnqualT2)
return ImplicitConversionSequence::Indistinguishable;
- // If the type is an array type, promote the element qualifiers to the type
- // for comparison.
- if (isa<ArrayType>(T1) && T1Quals)
- T1 = S.Context.getQualifiedType(UnqualT1, T1Quals);
- if (isa<ArrayType>(T2) && T2Quals)
- T2 = S.Context.getQualifiedType(UnqualT2, T2Quals);
-
ImplicitConversionSequence::CompareKind Result
= ImplicitConversionSequence::Indistinguishable;
@@ -4290,14 +4345,10 @@ CompareDerivedToBaseConversions(Sema &S, SourceLocation Loc,
if (SCS1.Second == ICK_Pointer_Member && SCS2.Second == ICK_Pointer_Member &&
FromType1->isMemberPointerType() && FromType2->isMemberPointerType() &&
ToType1->isMemberPointerType() && ToType2->isMemberPointerType()) {
- const MemberPointerType * FromMemPointer1 =
- FromType1->getAs<MemberPointerType>();
- const MemberPointerType * ToMemPointer1 =
- ToType1->getAs<MemberPointerType>();
- const MemberPointerType * FromMemPointer2 =
- FromType2->getAs<MemberPointerType>();
- const MemberPointerType * ToMemPointer2 =
- ToType2->getAs<MemberPointerType>();
+ const auto *FromMemPointer1 = FromType1->castAs<MemberPointerType>();
+ const auto *ToMemPointer1 = ToType1->castAs<MemberPointerType>();
+ const auto *FromMemPointer2 = FromType2->castAs<MemberPointerType>();
+ const auto *ToMemPointer2 = ToType2->castAs<MemberPointerType>();
const Type *FromPointeeType1 = FromMemPointer1->getClass();
const Type *ToPointeeType1 = ToMemPointer1->getClass();
const Type *FromPointeeType2 = FromMemPointer2->getClass();
@@ -4360,20 +4411,26 @@ static bool isTypeValid(QualType T) {
return true;
}
+static QualType withoutUnaligned(ASTContext &Ctx, QualType T) {
+ if (!T.getQualifiers().hasUnaligned())
+ return T;
+
+ Qualifiers Q;
+ T = Ctx.getUnqualifiedArrayType(T, Q);
+ Q.removeUnaligned();
+ return Ctx.getQualifiedType(T, Q);
+}
+
/// CompareReferenceRelationship - Compare the two types T1 and T2 to
-/// determine whether they are reference-related,
-/// reference-compatible, reference-compatible with added
-/// qualification, or incompatible, for use in C++ initialization by
+/// determine whether they are reference-compatible,
+/// reference-related, or incompatible, for use in C++ initialization by
/// reference (C++ [dcl.ref.init]p4). Neither type can be a reference
/// type, and the first type (T1) is the pointee type of the reference
/// type being initialized.
Sema::ReferenceCompareResult
Sema::CompareReferenceRelationship(SourceLocation Loc,
QualType OrigT1, QualType OrigT2,
- bool &DerivedToBase,
- bool &ObjCConversion,
- bool &ObjCLifetimeConversion,
- bool &FunctionConversion) {
+ ReferenceConversions *ConvOut) {
assert(!OrigT1->isReferenceType() &&
"T1 must be the pointee type of the reference type");
assert(!OrigT2->isReferenceType() && "T2 cannot be a reference type");
@@ -4384,76 +4441,84 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
QualType UnqualT1 = Context.getUnqualifiedArrayType(T1, T1Quals);
QualType UnqualT2 = Context.getUnqualifiedArrayType(T2, T2Quals);
- // C++ [dcl.init.ref]p4:
+ ReferenceConversions ConvTmp;
+ ReferenceConversions &Conv = ConvOut ? *ConvOut : ConvTmp;
+ Conv = ReferenceConversions();
+
+ // C++2a [dcl.init.ref]p4:
// Given types "cv1 T1" and "cv2 T2," "cv1 T1" is
- // reference-related to "cv2 T2" if T1 is the same type as T2, or
+ // reference-related to "cv2 T2" if T1 is similar to T2, or
// T1 is a base class of T2.
- DerivedToBase = false;
- ObjCConversion = false;
- ObjCLifetimeConversion = false;
+ // "cv1 T1" is reference-compatible with "cv2 T2" if
+ // a prvalue of type "pointer to cv2 T2" can be converted to the type
+ // "pointer to cv1 T1" via a standard conversion sequence.
+
+ // Check for standard conversions we can apply to pointers: derived-to-base
+ // conversions, ObjC pointer conversions, and function pointer conversions.
+ // (Qualification conversions are checked last.)
QualType ConvertedT2;
if (UnqualT1 == UnqualT2) {
// Nothing to do.
} else if (isCompleteType(Loc, OrigT2) &&
isTypeValid(UnqualT1) && isTypeValid(UnqualT2) &&
IsDerivedFrom(Loc, UnqualT2, UnqualT1))
- DerivedToBase = true;
+ Conv |= ReferenceConversions::DerivedToBase;
else if (UnqualT1->isObjCObjectOrInterfaceType() &&
UnqualT2->isObjCObjectOrInterfaceType() &&
Context.canBindObjCObjectType(UnqualT1, UnqualT2))
- ObjCConversion = true;
+ Conv |= ReferenceConversions::ObjC;
else if (UnqualT2->isFunctionType() &&
IsFunctionConversion(UnqualT2, UnqualT1, ConvertedT2)) {
- // C++1z [dcl.init.ref]p4:
- // cv1 T1" is reference-compatible with "cv2 T2" if [...] T2 is "noexcept
- // function" and T1 is "function"
- //
- // We extend this to also apply to 'noreturn', so allow any function
- // conversion between function types.
- FunctionConversion = true;
+ Conv |= ReferenceConversions::Function;
+ // No need to check qualifiers; function types don't have them.
return Ref_Compatible;
- } else
- return Ref_Incompatible;
-
- // At this point, we know that T1 and T2 are reference-related (at
- // least).
-
- // If the type is an array type, promote the element qualifiers to the type
- // for comparison.
- if (isa<ArrayType>(T1) && T1Quals)
- T1 = Context.getQualifiedType(UnqualT1, T1Quals);
- if (isa<ArrayType>(T2) && T2Quals)
- T2 = Context.getQualifiedType(UnqualT2, T2Quals);
-
- // C++ [dcl.init.ref]p4:
- // "cv1 T1" is reference-compatible with "cv2 T2" if T1 is
- // reference-related to T2 and cv1 is the same cv-qualification
- // as, or greater cv-qualification than, cv2. For purposes of
- // overload resolution, cases for which cv1 is greater
- // cv-qualification than cv2 are identified as
- // reference-compatible with added qualification (see 13.3.3.2).
- //
- // Note that we also require equivalence of Objective-C GC and address-space
- // qualifiers when performing these computations, so that e.g., an int in
- // address space 1 is not reference-compatible with an int in address
- // space 2.
- if (T1Quals.getObjCLifetime() != T2Quals.getObjCLifetime() &&
- T1Quals.compatiblyIncludesObjCLifetime(T2Quals)) {
- if (isNonTrivialObjCLifetimeConversion(T2Quals, T1Quals))
- ObjCLifetimeConversion = true;
-
- T1Quals.removeObjCLifetime();
- T2Quals.removeObjCLifetime();
}
+ bool ConvertedReferent = Conv != 0;
- // MS compiler ignores __unaligned qualifier for references; do the same.
- T1Quals.removeUnaligned();
- T2Quals.removeUnaligned();
+ // We can have a qualification conversion. Compute whether the types are
+ // similar at the same time.
+ bool PreviousToQualsIncludeConst = true;
+ bool TopLevel = true;
+ do {
+ if (T1 == T2)
+ break;
- if (T1Quals.compatiblyIncludes(T2Quals))
- return Ref_Compatible;
- else
- return Ref_Related;
+ // We will need a qualification conversion.
+ Conv |= ReferenceConversions::Qualification;
+
+ // Track whether we performed a qualification conversion anywhere other
+ // than the top level. This matters for ranking reference bindings in
+ // overload resolution.
+ if (!TopLevel)
+ Conv |= ReferenceConversions::NestedQualification;
+
+ // MS compiler ignores __unaligned qualifier for references; do the same.
+ T1 = withoutUnaligned(Context, T1);
+ T2 = withoutUnaligned(Context, T2);
+
+ // If we find a qualifier mismatch, the types are not reference-compatible,
+ // but are still be reference-related if they're similar.
+ bool ObjCLifetimeConversion = false;
+ if (!isQualificationConversionStep(T2, T1, /*CStyle=*/false,
+ PreviousToQualsIncludeConst,
+ ObjCLifetimeConversion))
+ return (ConvertedReferent || Context.hasSimilarType(T1, T2))
+ ? Ref_Related
+ : Ref_Incompatible;
+
+ // FIXME: Should we track this for any level other than the first?
+ if (ObjCLifetimeConversion)
+ Conv |= ReferenceConversions::ObjCLifetime;
+
+ TopLevel = false;
+ } while (Context.UnwrapSimilarTypes(T1, T2));
+
+ // At this point, if the types are reference-related, we must either have the
+ // same inner type (ignoring qualifiers), or must have already worked out how
+ // to convert the referent.
+ return (ConvertedReferent || Context.hasSameUnqualifiedType(T1, T2))
+ ? Ref_Compatible
+ : Ref_Incompatible;
}
/// Look for a user-defined conversion to a value reference-compatible
@@ -4464,8 +4529,7 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
Expr *Init, QualType T2, bool AllowRvalues,
bool AllowExplicit) {
assert(T2->isRecordType() && "Can only find conversions of record types.");
- CXXRecordDecl *T2RecordDecl
- = dyn_cast<CXXRecordDecl>(T2->castAs<RecordType>()->getDecl());
+ auto *T2RecordDecl = cast<CXXRecordDecl>(T2->castAs<RecordType>()->getDecl());
OverloadCandidateSet CandidateSet(
DeclLoc, OverloadCandidateSet::CSK_InitByUserDefinedConversion);
@@ -4484,17 +4548,7 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
else
Conv = cast<CXXConversionDecl>(D);
- // If this is an explicit conversion, and we're not allowed to consider
- // explicit conversions, skip it.
- if (!AllowExplicit && Conv->isExplicit())
- continue;
-
if (AllowRvalues) {
- bool DerivedToBase = false;
- bool ObjCConversion = false;
- bool ObjCLifetimeConversion = false;
- bool FunctionConversion = false;
-
// If we are initializing an rvalue reference, don't permit conversion
// functions that return lvalues.
if (!ConvTemplate && DeclType->isRValueReferenceType()) {
@@ -4510,9 +4564,8 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
Conv->getConversionType()
.getNonReferenceType()
.getUnqualifiedType(),
- DeclType.getNonReferenceType().getUnqualifiedType(),
- DerivedToBase, ObjCConversion, ObjCLifetimeConversion,
- FunctionConversion) == Sema::Ref_Incompatible)
+ DeclType.getNonReferenceType().getUnqualifiedType()) ==
+ Sema::Ref_Incompatible)
continue;
} else {
// If the conversion function doesn't return a reference type,
@@ -4571,7 +4624,7 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
ICS.setAmbiguous();
for (OverloadCandidateSet::iterator Cand = CandidateSet.begin();
Cand != CandidateSet.end(); ++Cand)
- if (Cand->Viable)
+ if (Cand->Best)
ICS.Ambiguous.addConversion(Cand->FoundDecl, Cand->Function);
return true;
@@ -4613,14 +4666,44 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
// Compute some basic properties of the types and the initializer.
bool isRValRef = DeclType->isRValueReferenceType();
- bool DerivedToBase = false;
- bool ObjCConversion = false;
- bool ObjCLifetimeConversion = false;
- bool FunctionConversion = false;
Expr::Classification InitCategory = Init->Classify(S.Context);
- Sema::ReferenceCompareResult RefRelationship = S.CompareReferenceRelationship(
- DeclLoc, T1, T2, DerivedToBase, ObjCConversion, ObjCLifetimeConversion,
- FunctionConversion);
+
+ Sema::ReferenceConversions RefConv;
+ Sema::ReferenceCompareResult RefRelationship =
+ S.CompareReferenceRelationship(DeclLoc, T1, T2, &RefConv);
+
+ auto SetAsReferenceBinding = [&](bool BindsDirectly) {
+ ICS.setStandard();
+ ICS.Standard.First = ICK_Identity;
+ // FIXME: A reference binding can be a function conversion too. We should
+ // consider that when ordering reference-to-function bindings.
+ ICS.Standard.Second = (RefConv & Sema::ReferenceConversions::DerivedToBase)
+ ? ICK_Derived_To_Base
+ : (RefConv & Sema::ReferenceConversions::ObjC)
+ ? ICK_Compatible_Conversion
+ : ICK_Identity;
+ // FIXME: As a speculative fix to a defect introduced by CWG2352, we rank
+ // a reference binding that performs a non-top-level qualification
+ // conversion as a qualification conversion, not as an identity conversion.
+ ICS.Standard.Third = (RefConv &
+ Sema::ReferenceConversions::NestedQualification)
+ ? ICK_Qualification
+ : ICK_Identity;
+ ICS.Standard.FromTypePtr = T2.getAsOpaquePtr();
+ ICS.Standard.setToType(0, T2);
+ ICS.Standard.setToType(1, T1);
+ ICS.Standard.setToType(2, T1);
+ ICS.Standard.ReferenceBinding = true;
+ ICS.Standard.DirectBinding = BindsDirectly;
+ ICS.Standard.IsLvalueReference = !isRValRef;
+ ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType();
+ ICS.Standard.BindsToRvalue = InitCategory.isRValue();
+ ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false;
+ ICS.Standard.ObjCLifetimeConversionBinding =
+ (RefConv & Sema::ReferenceConversions::ObjCLifetime) != 0;
+ ICS.Standard.CopyConstructor = nullptr;
+ ICS.Standard.DeprecatedStringLiteralToCharPtr = false;
+ };
// C++0x [dcl.init.ref]p5:
// A reference to type "cv1 T1" is initialized by an expression
@@ -4640,25 +4723,7 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
// has a type that is a derived class of the parameter type,
// in which case the implicit conversion sequence is a
// derived-to-base Conversion (13.3.3.1).
- ICS.setStandard();
- ICS.Standard.First = ICK_Identity;
- ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base
- : ObjCConversion? ICK_Compatible_Conversion
- : ICK_Identity;
- ICS.Standard.Third = ICK_Identity;
- ICS.Standard.FromTypePtr = T2.getAsOpaquePtr();
- ICS.Standard.setToType(0, T2);
- ICS.Standard.setToType(1, T1);
- ICS.Standard.setToType(2, T1);
- ICS.Standard.ReferenceBinding = true;
- ICS.Standard.DirectBinding = true;
- ICS.Standard.IsLvalueReference = !isRValRef;
- ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType();
- ICS.Standard.BindsToRvalue = false;
- ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false;
- ICS.Standard.ObjCLifetimeConversionBinding = ObjCLifetimeConversion;
- ICS.Standard.CopyConstructor = nullptr;
- ICS.Standard.DeprecatedStringLiteralToCharPtr = false;
+ SetAsReferenceBinding(/*BindsDirectly=*/true);
// Nothing more to do: the inaccessibility/ambiguity check for
// derived-to-base conversions is suppressed when we're
@@ -4696,34 +4761,16 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
// lvalue and "cv1 T1" is reference-compatible with "cv2 T2", or
if (RefRelationship == Sema::Ref_Compatible &&
(InitCategory.isXValue() ||
- (InitCategory.isPRValue() && (T2->isRecordType() || T2->isArrayType())) ||
+ (InitCategory.isPRValue() &&
+ (T2->isRecordType() || T2->isArrayType())) ||
(InitCategory.isLValue() && T2->isFunctionType()))) {
- ICS.setStandard();
- ICS.Standard.First = ICK_Identity;
- ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base
- : ObjCConversion? ICK_Compatible_Conversion
- : ICK_Identity;
- ICS.Standard.Third = ICK_Identity;
- ICS.Standard.FromTypePtr = T2.getAsOpaquePtr();
- ICS.Standard.setToType(0, T2);
- ICS.Standard.setToType(1, T1);
- ICS.Standard.setToType(2, T1);
- ICS.Standard.ReferenceBinding = true;
- // In C++0x, this is always a direct binding. In C++98/03, it's a direct
+ // In C++11, this is always a direct binding. In C++98/03, it's a direct
// binding unless we're binding to a class prvalue.
// Note: Although xvalues wouldn't normally show up in C++98/03 code, we
// allow the use of rvalue references in C++98/03 for the benefit of
// standard library implementors; therefore, we need the xvalue check here.
- ICS.Standard.DirectBinding =
- S.getLangOpts().CPlusPlus11 ||
- !(InitCategory.isPRValue() || T2->isRecordType());
- ICS.Standard.IsLvalueReference = !isRValRef;
- ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType();
- ICS.Standard.BindsToRvalue = InitCategory.isRValue();
- ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false;
- ICS.Standard.ObjCLifetimeConversionBinding = ObjCLifetimeConversion;
- ICS.Standard.CopyConstructor = nullptr;
- ICS.Standard.DeprecatedStringLiteralToCharPtr = false;
+ SetAsReferenceBinding(/*BindsDirectly=*/S.getLangOpts().CPlusPlus11 ||
+ !(InitCategory.isPRValue() || T2->isRecordType()));
return ICS;
}
@@ -5042,13 +5089,8 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType,
}
// Compute some basic properties of the types and the initializer.
- bool dummy1 = false;
- bool dummy2 = false;
- bool dummy3 = false;
- bool dummy4 = false;
Sema::ReferenceCompareResult RefRelationship =
- S.CompareReferenceRelationship(From->getBeginLoc(), T1, T2, dummy1,
- dummy2, dummy3, dummy4);
+ S.CompareReferenceRelationship(From->getBeginLoc(), T1, T2);
if (RefRelationship >= Sema::Ref_Related) {
return TryReferenceInit(S, Init, ToType, /*FIXME*/ From->getBeginLoc(),
@@ -5218,7 +5260,7 @@ TryObjectArgumentInitialization(Sema &S, SourceLocation Loc, QualType FromType,
return ICS;
}
- if (FromTypeCanon.getQualifiers().hasAddressSpace()) {
+ if (FromTypeCanon.hasAddressSpace()) {
Qualifiers QualsImplicitParamType = ImplicitParamType.getQualifiers();
Qualifiers QualsFromType = FromTypeCanon.getQualifiers();
if (!QualsImplicitParamType.isAddressSpaceSupersetOf(QualsFromType)) {
@@ -5367,7 +5409,10 @@ Sema::PerformObjectArgumentInitialization(Expr *From,
if (!Context.hasSameType(From->getType(), DestType)) {
CastKind CK;
- if (FromRecordType.getAddressSpace() != DestType.getAddressSpace())
+ QualType PteeTy = DestType->getPointeeType();
+ LangAS DestAS =
+ PteeTy.isNull() ? DestType.getAddressSpace() : PteeTy.getAddressSpace();
+ if (FromRecordType.getAddressSpace() != DestAS)
CK = CK_AddressSpaceConversion;
else
CK = CK_NoOp;
@@ -6046,7 +6091,7 @@ static bool IsAcceptableNonMemberOperatorCandidate(ASTContext &Context,
if (T1->isRecordType() || (!T2.isNull() && T2->isRecordType()))
return true;
- const FunctionProtoType *Proto = Fn->getType()->getAs<FunctionProtoType>();
+ const auto *Proto = Fn->getType()->castAs<FunctionProtoType>();
if (Proto->getNumParams() < 1)
return false;
@@ -6146,6 +6191,15 @@ void Sema::AddOverloadCandidate(
Candidate.IgnoreObjectArgument = false;
Candidate.ExplicitCallArguments = Args.size();
+ // Explicit functions are not actually candidates at all if we're not
+ // allowing them in this context, but keep them around so we can point
+ // to them in diagnostics.
+ if (!AllowExplicit && ExplicitSpecifier::getFromDecl(Function).isExplicit()) {
+ Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_explicit;
+ return;
+ }
+
if (Function->isMultiVersion() && Function->hasAttr<TargetAttr>() &&
!Function->getAttr<TargetAttr>()->isDefaultVersion()) {
Candidate.Viable = false;
@@ -6237,6 +6291,16 @@ void Sema::AddOverloadCandidate(
return;
}
+ if (Expr *RequiresClause = Function->getTrailingRequiresClause()) {
+ ConstraintSatisfaction Satisfaction;
+ if (CheckConstraintSatisfaction(RequiresClause, Satisfaction) ||
+ !Satisfaction.IsSatisfied) {
+ Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_constraints_not_satisfied;
+ return;
+ }
+ }
+
// Determine the implicit conversion sequences for each of the
// arguments.
for (unsigned ArgIdx = 0; ArgIdx < Args.size(); ++ArgIdx) {
@@ -6269,15 +6333,6 @@ void Sema::AddOverloadCandidate(
}
}
- if (!AllowExplicit) {
- ExplicitSpecifier ES = ExplicitSpecifier::getFromDecl(Function);
- if (ES.getKind() != ExplicitSpecKind::ResolvedFalse) {
- Candidate.Viable = false;
- Candidate.FailureKind = ovl_fail_explicit_resolved;
- return;
- }
- }
-
if (EnableIfAttr *FailedAttr = CheckEnableIf(Function, Args)) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_enable_if;
@@ -6753,6 +6808,16 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
return;
}
+ if (Expr *RequiresClause = Method->getTrailingRequiresClause()) {
+ ConstraintSatisfaction Satisfaction;
+ if (CheckConstraintSatisfaction(RequiresClause, Satisfaction) ||
+ !Satisfaction.IsSatisfied) {
+ Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_constraints_not_satisfied;
+ return;
+ }
+ }
+
// Determine the implicit conversion sequences for each of the
// arguments.
for (unsigned ArgIdx = 0; ArgIdx < Args.size(); ++ArgIdx) {
@@ -6866,6 +6931,12 @@ void Sema::AddMethodTemplateCandidate(
Conversions, PO);
}
+/// Determine whether a given function template has a simple explicit specifier
+/// or a non-value-dependent explicit-specification that evaluates to true.
+static bool isNonDependentlyExplicit(FunctionTemplateDecl *FTD) {
+ return ExplicitSpecifier::getFromDecl(FTD->getTemplatedDecl()).isExplicit();
+}
+
/// Add a C++ function template specialization as a candidate
/// in the candidate set, using template argument deduction to produce
/// an appropriate function template specialization.
@@ -6878,6 +6949,18 @@ void Sema::AddTemplateOverloadCandidate(
if (!CandidateSet.isNewCandidate(FunctionTemplate, PO))
return;
+ // If the function template has a non-dependent explicit specification,
+ // exclude it now if appropriate; we are not permitted to perform deduction
+ // and substitution in this case.
+ if (!AllowExplicit && isNonDependentlyExplicit(FunctionTemplate)) {
+ OverloadCandidate &Candidate = CandidateSet.addCandidate();
+ Candidate.FoundDecl = FoundDecl;
+ Candidate.Function = FunctionTemplate->getTemplatedDecl();
+ Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_explicit;
+ return;
+ }
+
// C++ [over.match.funcs]p7:
// In each case where a candidate is a function template, candidate
// function template specializations are generated using template argument
@@ -7065,6 +7148,9 @@ void Sema::AddConversionCandidate(
// Per C++ [over.match.conv]p1, [over.match.ref]p1, an explicit conversion
// operator is only a candidate if its return type is the target type or
// can be converted to the target type with a qualification conversion.
+ //
+ // FIXME: Include such functions in the candidate list and explain why we
+ // can't select them.
if (Conversion->isExplicit() &&
!isAllowableExplicitConversion(*this, ConvType, ToType,
AllowObjCConversionOnExplicit))
@@ -7086,6 +7172,15 @@ void Sema::AddConversionCandidate(
Candidate.Viable = true;
Candidate.ExplicitCallArguments = 1;
+ // Explicit functions are not actually candidates at all if we're not
+ // allowing them in this context, but keep them around so we can point
+ // to them in diagnostics.
+ if (!AllowExplicit && Conversion->isExplicit()) {
+ Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_explicit;
+ return;
+ }
+
// C++ [over.match.funcs]p4:
// For conversion functions, the function is considered to be a member of
// the class of the implicit implied object argument for the purpose of
@@ -7109,6 +7204,17 @@ void Sema::AddConversionCandidate(
return;
}
+ Expr *RequiresClause = Conversion->getTrailingRequiresClause();
+ if (RequiresClause) {
+ ConstraintSatisfaction Satisfaction;
+ if (CheckConstraintSatisfaction(RequiresClause, Satisfaction) ||
+ !Satisfaction.IsSatisfied) {
+ Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_constraints_not_satisfied;
+ return;
+ }
+ }
+
// We won't go through a user-defined type conversion function to convert a
// derived to base as such conversions are given Conversion Rank. They only
// go through a copy constructor. 13.3.3.1.2-p4 [over.ics.user]
@@ -7199,13 +7305,6 @@ void Sema::AddConversionCandidate(
"Can only end up with a standard conversion sequence or failure");
}
- if (!AllowExplicit && Conversion->getExplicitSpecifier().getKind() !=
- ExplicitSpecKind::ResolvedFalse) {
- Candidate.Viable = false;
- Candidate.FailureKind = ovl_fail_explicit_resolved;
- return;
- }
-
if (EnableIfAttr *FailedAttr = CheckEnableIf(Conversion, None)) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_enable_if;
@@ -7236,6 +7335,18 @@ void Sema::AddTemplateConversionCandidate(
if (!CandidateSet.isNewCandidate(FunctionTemplate))
return;
+ // If the function template has a non-dependent explicit specification,
+ // exclude it now if appropriate; we are not permitted to perform deduction
+ // and substitution in this case.
+ if (!AllowExplicit && isNonDependentlyExplicit(FunctionTemplate)) {
+ OverloadCandidate &Candidate = CandidateSet.addCandidate();
+ Candidate.FoundDecl = FoundDecl;
+ Candidate.Function = FunctionTemplate->getTemplatedDecl();
+ Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_explicit;
+ return;
+ }
+
TemplateDeductionInfo Info(CandidateSet.getLocation());
CXXConversionDecl *Specialization = nullptr;
if (TemplateDeductionResult Result
@@ -9440,6 +9551,35 @@ bool clang::isBetterOverloadCandidate(
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))
+ return false;
+ if (!AtLeastAsConstrained1)
+ return false;
+ if (S.IsAtLeastAsConstrained(Cand2.Function, {RC2}, Cand1.Function,
+ {RC1}, AtLeastAsConstrained2))
+ return false;
+ if (!AtLeastAsConstrained2)
+ return true;
+ } else if (RC1 || RC2)
+ return RC1 != nullptr;
+ }
+ }
+
// -- F1 is a constructor for a class D, F2 is a constructor for a base
// class B of D, and for all arguments the corresponding parameters of
// F1 and F2 have the same type.
@@ -9527,8 +9667,7 @@ bool Sema::isEquivalentInternalLinkageDeclaration(const NamedDecl *A,
// entity in different modules.
if (!VA->getDeclContext()->getRedeclContext()->Equals(
VB->getDeclContext()->getRedeclContext()) ||
- getOwningModule(const_cast<ValueDecl *>(VA)) ==
- getOwningModule(const_cast<ValueDecl *>(VB)) ||
+ getOwningModule(VA) == getOwningModule(VB) ||
VA->isExternallyVisible() || VB->isExternallyVisible())
return false;
@@ -9565,12 +9704,12 @@ void Sema::diagnoseEquivalentInternalLinkageDeclarations(
SourceLocation Loc, const NamedDecl *D, ArrayRef<const NamedDecl *> Equiv) {
Diag(Loc, diag::ext_equivalent_internal_linkage_decl_in_modules) << D;
- Module *M = getOwningModule(const_cast<NamedDecl*>(D));
+ Module *M = getOwningModule(D);
Diag(D->getLocation(), diag::note_equivalent_internal_linkage_decl)
<< !M << (M ? M->getFullModuleName() : "");
for (auto *E : Equiv) {
- Module *M = getOwningModule(const_cast<NamedDecl*>(E));
+ Module *M = getOwningModule(E);
Diag(E->getLocation(), diag::note_equivalent_internal_linkage_decl)
<< !M << (M ? M->getFullModuleName() : "");
}
@@ -9622,11 +9761,13 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc,
// Find the best viable function.
Best = end();
- for (auto *Cand : Candidates)
+ for (auto *Cand : Candidates) {
+ Cand->Best = false;
if (Cand->Viable)
if (Best == end() ||
isBetterOverloadCandidate(S, *Cand, *Best, Loc, Kind))
Best = Cand;
+ }
// If we didn't find any viable functions, abort.
if (Best == end())
@@ -9634,22 +9775,33 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc,
llvm::SmallVector<const NamedDecl *, 4> EquivalentCands;
+ llvm::SmallVector<OverloadCandidate*, 4> PendingBest;
+ PendingBest.push_back(&*Best);
+ Best->Best = true;
+
// Make sure that this function is better than every other viable
// function. If not, we have an ambiguity.
- for (auto *Cand : Candidates) {
- if (Cand->Viable && Cand != Best &&
- !isBetterOverloadCandidate(S, *Best, *Cand, Loc, Kind)) {
- if (S.isEquivalentInternalLinkageDeclaration(Best->Function,
- Cand->Function)) {
- EquivalentCands.push_back(Cand->Function);
- continue;
+ while (!PendingBest.empty()) {
+ auto *Curr = PendingBest.pop_back_val();
+ for (auto *Cand : Candidates) {
+ if (Cand->Viable && !Cand->Best &&
+ !isBetterOverloadCandidate(S, *Curr, *Cand, Loc, Kind)) {
+ PendingBest.push_back(Cand);
+ Cand->Best = true;
+
+ if (S.isEquivalentInternalLinkageDeclaration(Cand->Function,
+ Curr->Function))
+ EquivalentCands.push_back(Cand->Function);
+ else
+ Best = end();
}
-
- Best = end();
- return OR_Ambiguous;
}
}
+ // If we found more than one best candidate, this is ambiguous.
+ if (Best == end())
+ return OR_Ambiguous;
+
// Best is the best viable function.
if (Best->Function && Best->Function->isDeleted())
return OR_Deleted;
@@ -9673,6 +9825,7 @@ enum OverloadCandidateKind {
oc_implicit_move_constructor,
oc_implicit_copy_assignment,
oc_implicit_move_assignment,
+ oc_implicit_equality_comparison,
oc_inherited_constructor
};
@@ -9701,6 +9854,9 @@ ClassifyOverloadCandidate(Sema &S, NamedDecl *Found, FunctionDecl *Fn,
}();
OverloadCandidateKind Kind = [&]() {
+ if (Fn->isImplicit() && Fn->getOverloadedOperator() == OO_EqualEqual)
+ return oc_implicit_equality_comparison;
+
if (CRK & CRK_Reversed)
return oc_reversed_binary_operator;
@@ -9791,6 +9947,24 @@ static bool checkAddressOfFunctionIsAvailable(Sema &S, const FunctionDecl *FD,
return false;
}
+ if (const Expr *RC = FD->getTrailingRequiresClause()) {
+ ConstraintSatisfaction Satisfaction;
+ if (S.CheckConstraintSatisfaction(RC, Satisfaction))
+ return false;
+ if (!Satisfaction.IsSatisfied) {
+ if (Complain) {
+ if (InOverloadResolution)
+ S.Diag(FD->getBeginLoc(),
+ diag::note_ovl_candidate_unsatisfied_constraints);
+ else
+ S.Diag(Loc, diag::err_addrof_function_constraints_not_satisfied)
+ << FD;
+ S.DiagnoseUnsatisfiedConstraint(Satisfaction);
+ }
+ return false;
+ }
+ }
+
auto I = llvm::find_if(FD->parameters(), [](const ParmVarDecl *P) {
return P->hasAttr<PassObjectSizeAttr>();
});
@@ -9848,6 +10022,55 @@ void Sema::NoteOverloadCandidate(NamedDecl *Found, FunctionDecl *Fn,
MaybeEmitInheritedConstructorNote(*this, Found);
}
+static void
+MaybeDiagnoseAmbiguousConstraints(Sema &S, ArrayRef<OverloadCandidate> Cands) {
+ // Perhaps the ambiguity was caused by two atomic constraints that are
+ // 'identical' but not equivalent:
+ //
+ // void foo() requires (sizeof(T) > 4) { } // #1
+ // void foo() requires (sizeof(T) > 4) && T::value { } // #2
+ //
+ // The 'sizeof(T) > 4' constraints are seemingly equivalent and should cause
+ // #2 to subsume #1, but these constraint are not considered equivalent
+ // according to the subsumption rules because they are not the same
+ // source-level construct. This behavior is quite confusing and we should try
+ // to help the user figure out what happened.
+
+ SmallVector<const Expr *, 3> FirstAC, SecondAC;
+ FunctionDecl *FirstCand = nullptr, *SecondCand = nullptr;
+ for (auto I = Cands.begin(), E = Cands.end(); I != E; ++I) {
+ if (!I->Function)
+ continue;
+ SmallVector<const Expr *, 3> AC;
+ if (auto *Template = I->Function->getPrimaryTemplate())
+ Template->getAssociatedConstraints(AC);
+ else
+ I->Function->getAssociatedConstraints(AC);
+ if (AC.empty())
+ continue;
+ if (FirstCand == nullptr) {
+ FirstCand = I->Function;
+ FirstAC = AC;
+ } else if (SecondCand == nullptr) {
+ SecondCand = I->Function;
+ SecondAC = AC;
+ } else {
+ // We have more than one pair of constrained functions - this check is
+ // expensive and we'd rather not try to diagnose it.
+ return;
+ }
+ }
+ if (!SecondCand)
+ return;
+ // The diagnostic can only happen if there are associated constraints on
+ // both sides (there needs to be some identical atomic constraint).
+ if (S.MaybeEmitAmbiguousAtomicConstraintsDiagnostic(FirstCand, FirstAC,
+ SecondCand, SecondAC))
+ // Just show the user one diagnostic, they'll probably figure it out
+ // from here.
+ return;
+}
+
// Notes the location of all overload candidates designated through
// OverloadedExpr
void Sema::NoteAllOverloadCandidates(Expr *OverloadedExpr, QualType DestType,
@@ -9916,7 +10139,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
std::string FnDesc;
std::pair<OverloadCandidateKind, OverloadCandidateSelect> FnKindPair =
- ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn, Cand->RewriteKind,
+ ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn, Cand->getRewriteKind(),
FnDesc);
Expr *FromExpr = Conv.Bad.FromExpr;
@@ -9959,10 +10182,17 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
Qualifiers ToQs = CToTy.getQualifiers();
if (FromQs.getAddressSpace() != ToQs.getAddressSpace()) {
- S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_addrspace)
- << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc
- << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) << FromTy
- << ToTy << (unsigned)isObjectArgument << I + 1;
+ if (isObjectArgument)
+ S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_addrspace_this)
+ << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second
+ << FnDesc << (FromExpr ? FromExpr->getSourceRange() : SourceRange())
+ << FromQs.getAddressSpace() << ToQs.getAddressSpace();
+ else
+ S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_addrspace)
+ << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second
+ << FnDesc << (FromExpr ? FromExpr->getSourceRange() : SourceRange())
+ << FromQs.getAddressSpace() << ToQs.getAddressSpace()
+ << ToTy->isReferenceType() << I + 1;
MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
}
@@ -10167,7 +10397,7 @@ static void DiagnoseArityMismatch(Sema &S, NamedDecl *Found, Decl *D,
FunctionDecl *Fn = cast<FunctionDecl>(D);
// TODO: treat calls to a missing default constructor as a special case
- const FunctionProtoType *FnTy = Fn->getType()->getAs<FunctionProtoType>();
+ const auto *FnTy = Fn->getType()->castAs<FunctionProtoType>();
unsigned MinParams = Fn->getMinRequiredArguments();
// at least / at most / exactly
@@ -10303,6 +10533,16 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated,
which = 2;
}
+ // Tweak the diagnostic if the problem is that we deduced packs of
+ // different arities. We'll print the actual packs anyway in case that
+ // includes additional useful information.
+ if (DeductionFailure.getFirstArg()->getKind() == TemplateArgument::Pack &&
+ DeductionFailure.getSecondArg()->getKind() == TemplateArgument::Pack &&
+ DeductionFailure.getFirstArg()->pack_size() !=
+ DeductionFailure.getSecondArg()->pack_size()) {
+ which = 3;
+ }
+
S.Diag(Templated->getLocation(),
diag::note_ovl_candidate_inconsistent_deduction)
<< which << ParamD->getDeclName() << *DeductionFailure.getFirstArg()
@@ -10333,6 +10573,23 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated,
MaybeEmitInheritedConstructorNote(S, Found);
return;
+ case Sema::TDK_ConstraintsNotSatisfied: {
+ // Format the template argument list into the argument string.
+ SmallString<128> TemplateArgString;
+ TemplateArgumentList *Args = DeductionFailure.getTemplateArgumentList();
+ TemplateArgString = " ";
+ TemplateArgString += S.getTemplateArgumentBindingsText(
+ getDescribedTemplate(Templated)->getTemplateParameters(), *Args);
+ if (TemplateArgString.size() == 1)
+ TemplateArgString.clear();
+ S.Diag(Templated->getLocation(),
+ diag::note_ovl_candidate_unsatisfied_constraints)
+ << TemplateArgString;
+
+ S.DiagnoseUnsatisfiedConstraint(
+ static_cast<CNSInfo*>(DeductionFailure.Data)->Satisfaction);
+ return;
+ }
case Sema::TDK_TooManyArguments:
case Sema::TDK_TooFewArguments:
DiagnoseArityMismatch(S, Found, Templated, NumArgs);
@@ -10352,6 +10609,8 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated,
TemplateArgString = " ";
TemplateArgString += S.getTemplateArgumentBindingsText(
getDescribedTemplate(Templated)->getTemplateParameters(), *Args);
+ if (TemplateArgString.size() == 1)
+ TemplateArgString.clear();
}
// If this candidate was disabled by enable_if, say so.
@@ -10401,6 +10660,8 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated,
TemplateArgString = " ";
TemplateArgString += S.getTemplateArgumentBindingsText(
getDescribedTemplate(Templated)->getTemplateParameters(), *Args);
+ if (TemplateArgString.size() == 1)
+ TemplateArgString.clear();
}
S.Diag(Templated->getLocation(), diag::note_ovl_candidate_deduced_mismatch)
@@ -10486,8 +10747,8 @@ static void DiagnoseBadTarget(Sema &S, OverloadCandidate *Cand) {
std::string FnDesc;
std::pair<OverloadCandidateKind, OverloadCandidateSelect> FnKindPair =
- ClassifyOverloadCandidate(S, Cand->FoundDecl, Callee, Cand->RewriteKind,
- FnDesc);
+ ClassifyOverloadCandidate(S, Cand->FoundDecl, Callee,
+ Cand->getRewriteKind(), FnDesc);
S.Diag(Callee->getLocation(), diag::note_ovl_candidate_bad_target)
<< (unsigned)FnKindPair.first << (unsigned)ocs_non_template
@@ -10545,30 +10806,36 @@ static void DiagnoseFailedEnableIfAttr(Sema &S, OverloadCandidate *Cand) {
}
static void DiagnoseFailedExplicitSpec(Sema &S, OverloadCandidate *Cand) {
- ExplicitSpecifier ES;
- const char *DeclName;
+ ExplicitSpecifier ES = ExplicitSpecifier::getFromDecl(Cand->Function);
+ assert(ES.isExplicit() && "not an explicit candidate");
+
+ unsigned Kind;
switch (Cand->Function->getDeclKind()) {
case Decl::Kind::CXXConstructor:
- ES = cast<CXXConstructorDecl>(Cand->Function)->getExplicitSpecifier();
- DeclName = "constructor";
+ Kind = 0;
break;
case Decl::Kind::CXXConversion:
- ES = cast<CXXConversionDecl>(Cand->Function)->getExplicitSpecifier();
- DeclName = "conversion operator";
+ Kind = 1;
break;
case Decl::Kind::CXXDeductionGuide:
- ES = cast<CXXDeductionGuideDecl>(Cand->Function)->getExplicitSpecifier();
- DeclName = "deductiong guide";
+ Kind = Cand->Function->isImplicit() ? 0 : 2;
break;
default:
llvm_unreachable("invalid Decl");
}
- assert(ES.getExpr() && "null expression should be handled before");
- S.Diag(Cand->Function->getLocation(),
- diag::note_ovl_candidate_explicit_forbidden)
- << DeclName;
- S.Diag(ES.getExpr()->getBeginLoc(),
- diag::note_explicit_bool_resolved_to_true);
+
+ // Note the location of the first (in-class) declaration; a redeclaration
+ // (particularly an out-of-class definition) will typically lack the
+ // 'explicit' specifier.
+ // FIXME: This is probably a good thing to do for all 'candidate' notes.
+ FunctionDecl *First = Cand->Function->getFirstDecl();
+ if (FunctionDecl *Pattern = First->getTemplateInstantiationPattern())
+ First = Pattern->getFirstDecl();
+
+ S.Diag(First->getLocation(),
+ diag::note_ovl_candidate_explicit)
+ << Kind << (ES.getExpr() ? 1 : 0)
+ << (ES.getExpr() ? ES.getExpr()->getSourceRange() : SourceRange());
}
static void DiagnoseOpenCLExtensionDisabled(Sema &S, OverloadCandidate *Cand) {
@@ -10605,8 +10872,8 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
if (Fn->isDeleted()) {
std::string FnDesc;
std::pair<OverloadCandidateKind, OverloadCandidateSelect> FnKindPair =
- ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn, Cand->RewriteKind,
- FnDesc);
+ ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn,
+ Cand->getRewriteKind(), FnDesc);
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_deleted)
<< (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc
@@ -10616,7 +10883,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
}
// We don't really have anything else to say about viable candidates.
- S.NoteOverloadCandidate(Cand->FoundDecl, Fn, Cand->RewriteKind);
+ S.NoteOverloadCandidate(Cand->FoundDecl, Fn, Cand->getRewriteKind());
return;
}
@@ -10649,7 +10916,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
case ovl_fail_trivial_conversion:
case ovl_fail_bad_final_conversion:
case ovl_fail_final_conversion_not_exact:
- return S.NoteOverloadCandidate(Cand->FoundDecl, Fn, Cand->RewriteKind);
+ return S.NoteOverloadCandidate(Cand->FoundDecl, Fn, Cand->getRewriteKind());
case ovl_fail_bad_conversion: {
unsigned I = (Cand->IgnoreObjectArgument ? 1 : 0);
@@ -10660,7 +10927,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
// FIXME: this currently happens when we're called from SemaInit
// when user-conversion overload fails. Figure out how to handle
// those conditions and diagnose them well.
- return S.NoteOverloadCandidate(Cand->FoundDecl, Fn, Cand->RewriteKind);
+ return S.NoteOverloadCandidate(Cand->FoundDecl, Fn, Cand->getRewriteKind());
}
case ovl_fail_bad_target:
@@ -10669,7 +10936,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
case ovl_fail_enable_if:
return DiagnoseFailedEnableIfAttr(S, Cand);
- case ovl_fail_explicit_resolved:
+ case ovl_fail_explicit:
return DiagnoseFailedExplicitSpec(S, Cand);
case ovl_fail_ext_disabled:
@@ -10695,6 +10962,23 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
case ovl_non_default_multiversion_function:
// Do nothing, these should simply be ignored.
break;
+
+ case ovl_fail_constraints_not_satisfied: {
+ std::string FnDesc;
+ std::pair<OverloadCandidateKind, OverloadCandidateSelect> FnKindPair =
+ ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn,
+ Cand->getRewriteKind(), FnDesc);
+
+ S.Diag(Fn->getLocation(),
+ diag::note_ovl_candidate_constraints_not_satisfied)
+ << (unsigned)FnKindPair.first << (unsigned)ocs_non_template
+ << FnDesc /* Ignored */;
+ ConstraintSatisfaction Satisfaction;
+ if (S.CheckConstraintSatisfaction(Fn->getTrailingRequiresClause(),
+ Satisfaction))
+ break;
+ S.DiagnoseUnsatisfiedConstraint(Satisfaction);
+ }
}
}
@@ -10785,6 +11069,7 @@ static unsigned RankDeductionFailure(const DeductionFailureInfo &DFI) {
case Sema::TDK_SubstitutionFailure:
case Sema::TDK_DeducedMismatch:
+ case Sema::TDK_ConstraintsNotSatisfied:
case Sema::TDK_DeducedMismatchNested:
case Sema::TDK_NonDeducedMismatch:
case Sema::TDK_MiscellaneousDeductionFailure:
@@ -10816,6 +11101,23 @@ struct CompareOverloadCandidatesForDisplay {
OverloadCandidateSet::CandidateSetKind CSK)
: S(S), NumArgs(NArgs), CSK(CSK) {}
+ OverloadFailureKind EffectiveFailureKind(const OverloadCandidate *C) const {
+ // If there are too many or too few arguments, that's the high-order bit we
+ // want to sort by, even if the immediate failure kind was something else.
+ if (C->FailureKind == ovl_fail_too_many_arguments ||
+ C->FailureKind == ovl_fail_too_few_arguments)
+ return static_cast<OverloadFailureKind>(C->FailureKind);
+
+ if (C->Function) {
+ if (NumArgs > C->Function->getNumParams() && !C->Function->isVariadic())
+ return ovl_fail_too_many_arguments;
+ if (NumArgs < C->Function->getMinRequiredArguments())
+ return ovl_fail_too_few_arguments;
+ }
+
+ return static_cast<OverloadFailureKind>(C->FailureKind);
+ }
+
bool operator()(const OverloadCandidate *L,
const OverloadCandidate *R) {
// Fast-path this check.
@@ -10839,34 +11141,37 @@ struct CompareOverloadCandidatesForDisplay {
// Criteria by which we can sort non-viable candidates:
if (!L->Viable) {
+ OverloadFailureKind LFailureKind = EffectiveFailureKind(L);
+ OverloadFailureKind RFailureKind = EffectiveFailureKind(R);
+
// 1. Arity mismatches come after other candidates.
- if (L->FailureKind == ovl_fail_too_many_arguments ||
- L->FailureKind == ovl_fail_too_few_arguments) {
- if (R->FailureKind == ovl_fail_too_many_arguments ||
- R->FailureKind == ovl_fail_too_few_arguments) {
+ if (LFailureKind == ovl_fail_too_many_arguments ||
+ LFailureKind == ovl_fail_too_few_arguments) {
+ if (RFailureKind == ovl_fail_too_many_arguments ||
+ RFailureKind == ovl_fail_too_few_arguments) {
int LDist = std::abs((int)L->getNumParams() - (int)NumArgs);
int RDist = std::abs((int)R->getNumParams() - (int)NumArgs);
if (LDist == RDist) {
- if (L->FailureKind == R->FailureKind)
+ if (LFailureKind == RFailureKind)
// Sort non-surrogates before surrogates.
return !L->IsSurrogate && R->IsSurrogate;
// Sort candidates requiring fewer parameters than there were
// arguments given after candidates requiring more parameters
// than there were arguments given.
- return L->FailureKind == ovl_fail_too_many_arguments;
+ return LFailureKind == ovl_fail_too_many_arguments;
}
return LDist < RDist;
}
return false;
}
- if (R->FailureKind == ovl_fail_too_many_arguments ||
- R->FailureKind == ovl_fail_too_few_arguments)
+ if (RFailureKind == ovl_fail_too_many_arguments ||
+ RFailureKind == ovl_fail_too_few_arguments)
return true;
// 2. Bad conversions come first and are ordered by the number
// of bad conversions and quality of good conversions.
- if (L->FailureKind == ovl_fail_bad_conversion) {
- if (R->FailureKind != ovl_fail_bad_conversion)
+ if (LFailureKind == ovl_fail_bad_conversion) {
+ if (RFailureKind != ovl_fail_bad_conversion)
return true;
// The conversion that can be fixed with a smaller number of changes,
@@ -10904,17 +11209,17 @@ struct CompareOverloadCandidatesForDisplay {
if (leftBetter > 0) return true;
if (leftBetter < 0) return false;
- } else if (R->FailureKind == ovl_fail_bad_conversion)
+ } else if (RFailureKind == ovl_fail_bad_conversion)
return false;
- if (L->FailureKind == ovl_fail_bad_deduction) {
- if (R->FailureKind != ovl_fail_bad_deduction)
+ if (LFailureKind == ovl_fail_bad_deduction) {
+ if (RFailureKind != ovl_fail_bad_deduction)
return true;
if (L->DeductionFailure.Result != R->DeductionFailure.Result)
return RankDeductionFailure(L->DeductionFailure)
< RankDeductionFailure(R->DeductionFailure);
- } else if (R->FailureKind == ovl_fail_bad_deduction)
+ } else if (RFailureKind == ovl_fail_bad_deduction)
return false;
// TODO: others?
@@ -10943,7 +11248,8 @@ CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
assert(!Cand->Viable);
// Don't do anything on failures other than bad conversion.
- if (Cand->FailureKind != ovl_fail_bad_conversion) return;
+ if (Cand->FailureKind != ovl_fail_bad_conversion)
+ return;
// We only want the FixIts if all the arguments can be corrected.
bool Unfixable = false;
@@ -10969,6 +11275,7 @@ CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
unsigned ConvIdx = 0;
unsigned ArgIdx = 0;
ArrayRef<QualType> ParamTypes;
+ bool Reversed = Cand->RewriteKind & CRK_Reversed;
if (Cand->IsSurrogate) {
QualType ConvType
@@ -10982,10 +11289,11 @@ CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
ParamTypes =
Cand->Function->getType()->castAs<FunctionProtoType>()->getParamTypes();
if (isa<CXXMethodDecl>(Cand->Function) &&
- !isa<CXXConstructorDecl>(Cand->Function)) {
+ !isa<CXXConstructorDecl>(Cand->Function) && !Reversed) {
// Conversion 0 is 'this', which doesn't have a corresponding parameter.
ConvIdx = 1;
- if (CSK == OverloadCandidateSet::CSK_Operator)
+ if (CSK == OverloadCandidateSet::CSK_Operator &&
+ Cand->Function->getDeclName().getCXXOverloadedOperator() != OO_Call)
// Argument 0 is 'this', which doesn't have a corresponding parameter.
ArgIdx = 1;
}
@@ -10996,13 +11304,13 @@ CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
}
// Fill in the rest of the conversions.
- bool Reversed = Cand->RewriteKind & CRK_Reversed;
for (unsigned ParamIdx = Reversed ? ParamTypes.size() - 1 : 0;
ConvIdx != ConvCount;
++ConvIdx, ++ArgIdx, ParamIdx += (Reversed ? -1 : 1)) {
+ assert(ArgIdx < Args.size() && "no argument for this arg conversion");
if (Cand->Conversions[ConvIdx].isInitialized()) {
// We've already checked this conversion.
- } else if (ArgIdx < ParamTypes.size()) {
+ } else if (ParamIdx < ParamTypes.size()) {
if (ParamTypes[ParamIdx]->isDependentType())
Cand->Conversions[ConvIdx].setAsIdentityConversion(
Args[ArgIdx]->getType());
@@ -11033,15 +11341,30 @@ SmallVector<OverloadCandidate *, 32> OverloadCandidateSet::CompleteCandidates(
for (iterator Cand = begin(), LastCand = end(); Cand != LastCand; ++Cand) {
if (!Filter(*Cand))
continue;
- if (Cand->Viable)
- Cands.push_back(Cand);
- else if (OCD == OCD_AllCandidates) {
- CompleteNonViableCandidate(S, Cand, Args, Kind);
- if (Cand->Function || Cand->IsSurrogate)
- Cands.push_back(Cand);
- // Otherwise, this a non-viable builtin candidate. We do not, in general,
- // want to list every possible builtin candidate.
+ switch (OCD) {
+ case OCD_AllCandidates:
+ if (!Cand->Viable) {
+ if (!Cand->Function && !Cand->IsSurrogate) {
+ // This a non-viable builtin candidate. We do not, in general,
+ // want to list every possible builtin candidate.
+ continue;
+ }
+ CompleteNonViableCandidate(S, Cand, Args, Kind);
+ }
+ break;
+
+ case OCD_ViableCandidates:
+ if (!Cand->Viable)
+ continue;
+ break;
+
+ case OCD_AmbiguousCandidates:
+ if (!Cand->Best)
+ continue;
+ break;
}
+
+ Cands.push_back(Cand);
}
llvm::stable_sort(
@@ -11062,6 +11385,9 @@ void OverloadCandidateSet::NoteCandidates(PartialDiagnosticAt PD,
S.Diag(PD.first, PD.second);
NoteCandidates(S, Args, Cands, Opc, OpLoc);
+
+ if (OCD == OCD_AmbiguousCandidates)
+ MaybeDiagnoseAmbiguousConstraints(S, {begin(), end()});
}
void OverloadCandidateSet::NoteCandidates(Sema &S, ArrayRef<Expr *> Args,
@@ -11710,15 +12036,33 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *AddressOfExpr,
/// resolve that function to a single function that can have its address taken.
/// This will modify `Pair` iff it returns non-null.
///
-/// This routine can only realistically succeed if all but one candidates in the
-/// overload set for SrcExpr cannot have their addresses taken.
+/// This routine can only succeed if from all of the candidates in the overload
+/// set for SrcExpr that can have their addresses taken, there is one candidate
+/// that is more constrained than the rest.
FunctionDecl *
-Sema::resolveAddressOfOnlyViableOverloadCandidate(Expr *E,
- DeclAccessPair &Pair) {
+Sema::resolveAddressOfSingleOverloadCandidate(Expr *E, DeclAccessPair &Pair) {
OverloadExpr::FindResult R = OverloadExpr::find(E);
OverloadExpr *Ovl = R.Expression;
+ bool IsResultAmbiguous = false;
FunctionDecl *Result = nullptr;
DeclAccessPair DAP;
+ SmallVector<FunctionDecl *, 2> AmbiguousDecls;
+
+ auto CheckMoreConstrained =
+ [&] (FunctionDecl *FD1, FunctionDecl *FD2) -> Optional<bool> {
+ SmallVector<const Expr *, 1> AC1, AC2;
+ FD1->getAssociatedConstraints(AC1);
+ FD2->getAssociatedConstraints(AC2);
+ bool AtLeastAsConstrained1, AtLeastAsConstrained2;
+ if (IsAtLeastAsConstrained(FD1, AC1, FD2, AC2, AtLeastAsConstrained1))
+ return None;
+ if (IsAtLeastAsConstrained(FD2, AC2, FD1, AC1, AtLeastAsConstrained2))
+ return None;
+ if (AtLeastAsConstrained1 == AtLeastAsConstrained2)
+ return None;
+ return AtLeastAsConstrained1;
+ };
+
// Don't use the AddressOfResolver because we're specifically looking for
// cases where we have one overload candidate that lacks
// enable_if/pass_object_size/...
@@ -11730,32 +12074,54 @@ Sema::resolveAddressOfOnlyViableOverloadCandidate(Expr *E,
if (!checkAddressOfFunctionIsAvailable(FD))
continue;
- // We have more than one result; quit.
- if (Result)
- return nullptr;
+ // We have more than one result - see if it is more constrained than the
+ // previous one.
+ if (Result) {
+ Optional<bool> MoreConstrainedThanPrevious = CheckMoreConstrained(FD,
+ Result);
+ if (!MoreConstrainedThanPrevious) {
+ IsResultAmbiguous = true;
+ AmbiguousDecls.push_back(FD);
+ continue;
+ }
+ if (!*MoreConstrainedThanPrevious)
+ continue;
+ // FD is more constrained - replace Result with it.
+ }
+ IsResultAmbiguous = false;
DAP = I.getPair();
Result = FD;
}
- if (Result)
+ if (IsResultAmbiguous)
+ return nullptr;
+
+ if (Result) {
+ SmallVector<const Expr *, 1> ResultAC;
+ // We skipped over some ambiguous declarations which might be ambiguous with
+ // the selected result.
+ for (FunctionDecl *Skipped : AmbiguousDecls)
+ if (!CheckMoreConstrained(Skipped, Result).hasValue())
+ return nullptr;
Pair = DAP;
+ }
return Result;
}
/// Given an overloaded function, tries to turn it into a non-overloaded
-/// function reference using resolveAddressOfOnlyViableOverloadCandidate. This
+/// function reference using resolveAddressOfSingleOverloadCandidate. This
/// will perform access checks, diagnose the use of the resultant decl, and, if
/// requested, potentially perform a function-to-pointer decay.
///
-/// Returns false if resolveAddressOfOnlyViableOverloadCandidate fails.
+/// Returns false if resolveAddressOfSingleOverloadCandidate fails.
/// Otherwise, returns true. This may emit diagnostics and return true.
-bool Sema::resolveAndFixAddressOfOnlyViableOverloadCandidate(
+bool Sema::resolveAndFixAddressOfSingleOverloadCandidate(
ExprResult &SrcExpr, bool DoFunctionPointerConverion) {
Expr *E = SrcExpr.get();
assert(E->getType() == Context.OverloadTy && "SrcExpr must be an overload");
DeclAccessPair DAP;
- FunctionDecl *Found = resolveAddressOfOnlyViableOverloadCandidate(E, DAP);
+ FunctionDecl *Found = resolveAddressOfSingleOverloadCandidate(E, DAP);
if (!Found || Found->isCPUDispatchMultiVersion() ||
Found->isCPUSpecificMultiVersion())
return false;
@@ -12406,7 +12772,7 @@ static ExprResult FinishOverloadedCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
PartialDiagnosticAt(Fn->getBeginLoc(),
SemaRef.PDiag(diag::err_ovl_ambiguous_call)
<< ULE->getName() << Fn->getSourceRange()),
- SemaRef, OCD_ViableCandidates, Args);
+ SemaRef, OCD_AmbiguousCandidates, Args);
break;
case OR_Deleted: {
@@ -12652,7 +13018,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
PDiag(diag::err_ovl_ambiguous_oper_unary)
<< UnaryOperator::getOpcodeStr(Opc)
<< Input->getType() << Input->getSourceRange()),
- *this, OCD_ViableCandidates, ArgsArray,
+ *this, OCD_AmbiguousCandidates, ArgsArray,
UnaryOperator::getOpcodeStr(Opc), OpLoc);
return ExprError();
@@ -12672,6 +13038,70 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
return CreateBuiltinUnaryOp(OpLoc, Opc, Input);
}
+/// Perform lookup for an overloaded binary operator.
+void Sema::LookupOverloadedBinOp(OverloadCandidateSet &CandidateSet,
+ OverloadedOperatorKind Op,
+ const UnresolvedSetImpl &Fns,
+ ArrayRef<Expr *> Args, bool PerformADL) {
+ SourceLocation OpLoc = CandidateSet.getLocation();
+
+ OverloadedOperatorKind ExtraOp =
+ CandidateSet.getRewriteInfo().AllowRewrittenCandidates
+ ? getRewrittenOverloadedOperator(Op)
+ : OO_None;
+
+ // Add the candidates from the given function set. This also adds the
+ // rewritten candidates using these functions if necessary.
+ AddNonMemberOperatorCandidates(Fns, Args, CandidateSet);
+
+ // Add operator candidates that are member functions.
+ AddMemberOperatorCandidates(Op, OpLoc, Args, CandidateSet);
+ if (CandidateSet.getRewriteInfo().shouldAddReversed(Op))
+ AddMemberOperatorCandidates(Op, OpLoc, {Args[1], Args[0]}, CandidateSet,
+ OverloadCandidateParamOrder::Reversed);
+
+ // In C++20, also add any rewritten member candidates.
+ if (ExtraOp) {
+ AddMemberOperatorCandidates(ExtraOp, OpLoc, Args, CandidateSet);
+ if (CandidateSet.getRewriteInfo().shouldAddReversed(ExtraOp))
+ AddMemberOperatorCandidates(ExtraOp, OpLoc, {Args[1], Args[0]},
+ CandidateSet,
+ OverloadCandidateParamOrder::Reversed);
+ }
+
+ // Add candidates from ADL. Per [over.match.oper]p2, this lookup is not
+ // performed for an assignment operator (nor for operator[] nor operator->,
+ // which don't get here).
+ if (Op != OO_Equal && PerformADL) {
+ DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
+ AddArgumentDependentLookupCandidates(OpName, OpLoc, Args,
+ /*ExplicitTemplateArgs*/ nullptr,
+ CandidateSet);
+ if (ExtraOp) {
+ DeclarationName ExtraOpName =
+ Context.DeclarationNames.getCXXOperatorName(ExtraOp);
+ AddArgumentDependentLookupCandidates(ExtraOpName, OpLoc, Args,
+ /*ExplicitTemplateArgs*/ nullptr,
+ CandidateSet);
+ }
+ }
+
+ // Add builtin operator candidates.
+ //
+ // FIXME: We don't add any rewritten candidates here. This is strictly
+ // incorrect; a builtin candidate could be hidden by a non-viable candidate,
+ // resulting in our selecting a rewritten builtin candidate. For example:
+ //
+ // enum class E { e };
+ // bool operator!=(E, E) requires false;
+ // bool k = E::e != E::e;
+ //
+ // ... should select the rewritten builtin candidate 'operator==(E, E)'. But
+ // it seems unreasonable to consider rewritten builtin candidates. A core
+ // issue has been filed proposing to removed this requirement.
+ AddBuiltinOperatorCandidates(Op, OpLoc, Args, CandidateSet);
+}
+
/// Create a binary operation that may resolve to an overloaded
/// operator.
///
@@ -12688,11 +13118,19 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
///
/// \param LHS Left-hand argument.
/// \param RHS Right-hand argument.
+/// \param PerformADL Whether to consider operator candidates found by ADL.
+/// \param AllowRewrittenCandidates Whether to consider candidates found by
+/// C++20 operator rewrites.
+/// \param DefaultedFn If we are synthesizing a defaulted operator function,
+/// the function in question. Such a function is never a candidate in
+/// our overload resolution. This also enables synthesizing a three-way
+/// comparison from < and == as described in C++20 [class.spaceship]p1.
ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
BinaryOperatorKind Opc,
const UnresolvedSetImpl &Fns, Expr *LHS,
Expr *RHS, bool PerformADL,
- bool AllowRewrittenCandidates) {
+ bool AllowRewrittenCandidates,
+ FunctionDecl *DefaultedFn) {
Expr *Args[2] = { LHS, RHS };
LHS=RHS=nullptr; // Please use only Args instead of LHS/RHS couple
@@ -12700,7 +13138,6 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
AllowRewrittenCandidates = false;
OverloadedOperatorKind Op = BinaryOperator::getOverloadedOperator(Opc);
- DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
// If either side is type-dependent, create an appropriate dependent
// expression.
@@ -12722,6 +13159,7 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// FIXME: save results of ADL from here?
CXXRecordDecl *NamingClass = nullptr; // lookup ignores member operators
// TODO: provide better source location info in DNLoc component.
+ DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
DeclarationNameInfo OpNameInfo(OpName, OpLoc);
UnresolvedLookupExpr *Fn = UnresolvedLookupExpr::Create(
Context, NamingClass, NestedNameSpecifierLoc(), OpNameInfo,
@@ -12755,63 +13193,13 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
if (Opc == BO_PtrMemD)
return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
- // Build an empty overload set.
+ // Build the overload set.
OverloadCandidateSet CandidateSet(
OpLoc, OverloadCandidateSet::CSK_Operator,
OverloadCandidateSet::OperatorRewriteInfo(Op, AllowRewrittenCandidates));
-
- OverloadedOperatorKind ExtraOp =
- AllowRewrittenCandidates ? getRewrittenOverloadedOperator(Op) : OO_None;
-
- // Add the candidates from the given function set. This also adds the
- // rewritten candidates using these functions if necessary.
- AddNonMemberOperatorCandidates(Fns, Args, CandidateSet);
-
- // Add operator candidates that are member functions.
- AddMemberOperatorCandidates(Op, OpLoc, Args, CandidateSet);
- if (CandidateSet.getRewriteInfo().shouldAddReversed(Op))
- AddMemberOperatorCandidates(Op, OpLoc, {Args[1], Args[0]}, CandidateSet,
- OverloadCandidateParamOrder::Reversed);
-
- // In C++20, also add any rewritten member candidates.
- if (ExtraOp) {
- AddMemberOperatorCandidates(ExtraOp, OpLoc, Args, CandidateSet);
- if (CandidateSet.getRewriteInfo().shouldAddReversed(ExtraOp))
- AddMemberOperatorCandidates(ExtraOp, OpLoc, {Args[1], Args[0]},
- CandidateSet,
- OverloadCandidateParamOrder::Reversed);
- }
-
- // Add candidates from ADL. Per [over.match.oper]p2, this lookup is not
- // performed for an assignment operator (nor for operator[] nor operator->,
- // which don't get here).
- if (Opc != BO_Assign && PerformADL) {
- AddArgumentDependentLookupCandidates(OpName, OpLoc, Args,
- /*ExplicitTemplateArgs*/ nullptr,
- CandidateSet);
- if (ExtraOp) {
- DeclarationName ExtraOpName =
- Context.DeclarationNames.getCXXOperatorName(ExtraOp);
- AddArgumentDependentLookupCandidates(ExtraOpName, OpLoc, Args,
- /*ExplicitTemplateArgs*/ nullptr,
- CandidateSet);
- }
- }
-
- // Add builtin operator candidates.
- //
- // FIXME: We don't add any rewritten candidates here. This is strictly
- // incorrect; a builtin candidate could be hidden by a non-viable candidate,
- // resulting in our selecting a rewritten builtin candidate. For example:
- //
- // enum class E { e };
- // bool operator!=(E, E) requires false;
- // bool k = E::e != E::e;
- //
- // ... should select the rewritten builtin candidate 'operator==(E, E)'. But
- // it seems unreasonable to consider rewritten builtin candidates. A core
- // issue has been filed proposing to removed this requirement.
- AddBuiltinOperatorCandidates(Op, OpLoc, Args, CandidateSet);
+ if (DefaultedFn)
+ CandidateSet.exclude(DefaultedFn);
+ LookupOverloadedBinOp(CandidateSet, Op, Fns, Args, PerformADL);
bool HadMultipleCandidates = (CandidateSet.size() > 1);
@@ -13018,6 +13406,15 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
if (Opc == BO_Comma)
break;
+ // When defaulting an 'operator<=>', we can try to synthesize a three-way
+ // compare result using '==' and '<'.
+ if (DefaultedFn && Opc == BO_Cmp) {
+ ExprResult E = BuildSynthesizedThreeWayComparison(OpLoc, Fns, Args[0],
+ Args[1], DefaultedFn);
+ if (E.isInvalid() || E.isUsable())
+ return E;
+ }
+
// For class as left operand for assignment or compound assignment
// operator do not fall through to handling in built-in, but report that
// no overloaded assignment operator found
@@ -13061,20 +13458,26 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
<< Args[1]->getType()
<< Args[0]->getSourceRange()
<< Args[1]->getSourceRange()),
- *this, OCD_ViableCandidates, Args, BinaryOperator::getOpcodeStr(Opc),
+ *this, OCD_AmbiguousCandidates, Args, BinaryOperator::getOpcodeStr(Opc),
OpLoc);
return ExprError();
case OR_Deleted:
if (isImplicitlyDeleted(Best->Function)) {
- CXXMethodDecl *Method = cast<CXXMethodDecl>(Best->Function);
- Diag(OpLoc, diag::err_ovl_deleted_special_oper)
- << Context.getRecordType(Method->getParent())
- << getSpecialMember(Method);
+ FunctionDecl *DeletedFD = Best->Function;
+ DefaultedFunctionKind DFK = getDefaultedFunctionKind(DeletedFD);
+ if (DFK.isSpecialMember()) {
+ Diag(OpLoc, diag::err_ovl_deleted_special_oper)
+ << Args[0]->getType() << DFK.asSpecialMember();
+ } else {
+ assert(DFK.isComparison());
+ Diag(OpLoc, diag::err_ovl_deleted_comparison)
+ << Args[0]->getType() << DeletedFD;
+ }
// The user probably meant to call this special member. Just
// explain why it's deleted.
- NoteDeletedFunction(Method);
+ NoteDeletedFunction(DeletedFD);
return ExprError();
}
CandidateSet.NoteCandidates(
@@ -13093,6 +13496,98 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
}
+ExprResult Sema::BuildSynthesizedThreeWayComparison(
+ SourceLocation OpLoc, const UnresolvedSetImpl &Fns, Expr *LHS, Expr *RHS,
+ FunctionDecl *DefaultedFn) {
+ const ComparisonCategoryInfo *Info =
+ Context.CompCategories.lookupInfoForType(DefaultedFn->getReturnType());
+ // If we're not producing a known comparison category type, we can't
+ // synthesize a three-way comparison. Let the caller diagnose this.
+ if (!Info)
+ return ExprResult((Expr*)nullptr);
+
+ // If we ever want to perform this synthesis more generally, we will need to
+ // apply the temporary materialization conversion to the operands.
+ assert(LHS->isGLValue() && RHS->isGLValue() &&
+ "cannot use prvalue expressions more than once");
+ Expr *OrigLHS = LHS;
+ Expr *OrigRHS = RHS;
+
+ // Replace the LHS and RHS with OpaqueValueExprs; we're going to refer to
+ // each of them multiple times below.
+ LHS = new (Context)
+ OpaqueValueExpr(LHS->getExprLoc(), LHS->getType(), LHS->getValueKind(),
+ LHS->getObjectKind(), LHS);
+ RHS = new (Context)
+ OpaqueValueExpr(RHS->getExprLoc(), RHS->getType(), RHS->getValueKind(),
+ RHS->getObjectKind(), RHS);
+
+ ExprResult Eq = CreateOverloadedBinOp(OpLoc, BO_EQ, Fns, LHS, RHS, true, true,
+ DefaultedFn);
+ if (Eq.isInvalid())
+ return ExprError();
+
+ ExprResult Less = CreateOverloadedBinOp(OpLoc, BO_LT, Fns, LHS, RHS, true,
+ true, DefaultedFn);
+ if (Less.isInvalid())
+ return ExprError();
+
+ ExprResult Greater;
+ if (Info->isPartial()) {
+ Greater = CreateOverloadedBinOp(OpLoc, BO_LT, Fns, RHS, LHS, true, true,
+ DefaultedFn);
+ if (Greater.isInvalid())
+ return ExprError();
+ }
+
+ // Form the list of comparisons we're going to perform.
+ struct Comparison {
+ ExprResult Cmp;
+ ComparisonCategoryResult Result;
+ } Comparisons[4] =
+ { {Eq, Info->isStrong() ? ComparisonCategoryResult::Equal
+ : ComparisonCategoryResult::Equivalent},
+ {Less, ComparisonCategoryResult::Less},
+ {Greater, ComparisonCategoryResult::Greater},
+ {ExprResult(), ComparisonCategoryResult::Unordered},
+ };
+
+ int I = Info->isPartial() ? 3 : 2;
+
+ // Combine the comparisons with suitable conditional expressions.
+ ExprResult Result;
+ for (; I >= 0; --I) {
+ // Build a reference to the comparison category constant.
+ auto *VI = Info->lookupValueInfo(Comparisons[I].Result);
+ // FIXME: Missing a constant for a comparison category. Diagnose this?
+ if (!VI)
+ return ExprResult((Expr*)nullptr);
+ ExprResult ThisResult =
+ BuildDeclarationNameExpr(CXXScopeSpec(), DeclarationNameInfo(), VI->VD);
+ if (ThisResult.isInvalid())
+ return ExprError();
+
+ // Build a conditional unless this is the final case.
+ if (Result.get()) {
+ Result = ActOnConditionalOp(OpLoc, OpLoc, Comparisons[I].Cmp.get(),
+ ThisResult.get(), Result.get());
+ if (Result.isInvalid())
+ return ExprError();
+ } else {
+ Result = ThisResult;
+ }
+ }
+
+ // Build a PseudoObjectExpr to model the rewriting of an <=> operator, and to
+ // bind the OpaqueValueExprs before they're (repeatedly) used.
+ Expr *SyntacticForm = new (Context)
+ BinaryOperator(OrigLHS, OrigRHS, BO_Cmp, Result.get()->getType(),
+ Result.get()->getValueKind(),
+ Result.get()->getObjectKind(), OpLoc, FPFeatures);
+ Expr *SemanticForm[] = {LHS, RHS, Result.get()};
+ return PseudoObjectExpr::Create(Context, SyntacticForm, SemanticForm, 2);
+}
+
ExprResult
Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
SourceLocation RLoc,
@@ -13246,7 +13741,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
<< Args[1]->getType()
<< Args[0]->getSourceRange()
<< Args[1]->getSourceRange()),
- *this, OCD_ViableCandidates, Args, "[]", LLoc);
+ *this, OCD_AmbiguousCandidates, Args, "[]", LLoc);
return ExprError();
case OR_Deleted:
@@ -13438,7 +13933,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
PartialDiagnosticAt(UnresExpr->getMemberLoc(),
PDiag(diag::err_ovl_ambiguous_member_call)
<< DeclName << MemExprE->getSourceRange()),
- *this, OCD_AllCandidates, Args);
+ *this, OCD_AmbiguousCandidates, Args);
// FIXME: Leaking incoming expressions!
return ExprError();
@@ -13469,7 +13964,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
ResultType = ResultType.getNonLValueExprType(Context);
assert(Method && "Member call to something that isn't a method?");
- const auto *Proto = Method->getType()->getAs<FunctionProtoType>();
+ const auto *Proto = Method->getType()->castAs<FunctionProtoType>();
CXXMemberCallExpr *TheCall =
CXXMemberCallExpr::Create(Context, MemExprE, Args, ResultType, VK,
RParenLoc, Proto->getNumParams());
@@ -13566,7 +14061,6 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
assert(Object.get()->getType()->isRecordType() &&
"Requires object type argument");
- const RecordType *Record = Object.get()->getType()->getAs<RecordType>();
// C++ [over.call.object]p1:
// If the primary-expression E in the function call syntax
@@ -13583,6 +14077,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
diag::err_incomplete_object_call, Object.get()))
return true;
+ const auto *Record = Object.get()->getType()->castAs<RecordType>();
LookupResult R(*this, OpName, LParenLoc, LookupOrdinaryName);
LookupQualifiedName(R, Record->getDecl());
R.suppressDiagnostics();
@@ -13670,7 +14165,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
PDiag(diag::err_ovl_ambiguous_object_call)
<< Object.get()->getType()
<< Object.get()->getSourceRange()),
- *this, OCD_ViableCandidates, Args);
+ *this, OCD_AmbiguousCandidates, Args);
break;
case OR_Deleted:
@@ -13730,9 +14225,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
if (Method->isInvalidDecl())
return ExprError();
- const FunctionProtoType *Proto =
- Method->getType()->getAs<FunctionProtoType>();
-
+ const auto *Proto = Method->getType()->castAs<FunctionProtoType>();
unsigned NumParams = Proto->getNumParams();
DeclarationNameInfo OpLocInfo(
@@ -13853,14 +14346,13 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
DeclarationName OpName =
Context.DeclarationNames.getCXXOperatorName(OO_Arrow);
OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Operator);
- const RecordType *BaseRecord = Base->getType()->getAs<RecordType>();
if (RequireCompleteType(Loc, Base->getType(),
diag::err_typecheck_incomplete_tag, Base))
return ExprError();
LookupResult R(*this, OpName, OpLoc, LookupOrdinaryName);
- LookupQualifiedName(R, BaseRecord->getDecl());
+ LookupQualifiedName(R, Base->getType()->castAs<RecordType>()->getDecl());
R.suppressDiagnostics();
for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end();
@@ -13905,7 +14397,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
PartialDiagnosticAt(OpLoc, PDiag(diag::err_ovl_ambiguous_oper_unary)
<< "->" << Base->getType()
<< Base->getSourceRange()),
- *this, OCD_ViableCandidates, Base);
+ *this, OCD_AmbiguousCandidates, Base);
return ExprError();
case OR_Deleted:
@@ -13985,7 +14477,7 @@ ExprResult Sema::BuildLiteralOperatorCall(LookupResult &R,
CandidateSet.NoteCandidates(
PartialDiagnosticAt(R.getNameLoc(), PDiag(diag::err_ovl_ambiguous_call)
<< R.getLookupName()),
- *this, OCD_ViableCandidates, Args);
+ *this, OCD_AmbiguousCandidates, Args);
return ExprError();
}
@@ -14200,13 +14692,6 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
UnOp->getOperatorLoc(), false);
}
- // C++ [except.spec]p17:
- // An exception-specification is considered to be needed when:
- // - in an expression the function is the unique lookup result or the
- // selected member of a set of overloaded functions
- if (auto *FPT = Fn->getType()->getAs<FunctionProtoType>())
- ResolveExceptionSpec(E->getExprLoc(), FPT);
-
if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(E)) {
// FIXME: avoid copy.
TemplateArgumentListInfo TemplateArgsBuffer, *TemplateArgs = nullptr;
diff --git a/clang/lib/Sema/SemaPseudoObject.cpp b/clang/lib/Sema/SemaPseudoObject.cpp
index 06bcd8d00ded..5587e0d24c7f 100644
--- a/clang/lib/Sema/SemaPseudoObject.cpp
+++ b/clang/lib/Sema/SemaPseudoObject.cpp
@@ -145,7 +145,7 @@ namespace {
assocExprs.reserve(numAssocs);
assocTypes.reserve(numAssocs);
- for (const GenericSelectionExpr::Association &assoc :
+ for (const GenericSelectionExpr::Association assoc :
gse->associations()) {
Expr *assocExpr = assoc.getAssociationExpr();
if (assoc.isSelected())
@@ -1190,16 +1190,15 @@ bool ObjCSubscriptOpBuilder::findAtIndexGetter() {
true /*instance*/);
if (!AtIndexGetter && S.getLangOpts().DebuggerObjCLiteral) {
- AtIndexGetter = ObjCMethodDecl::Create(S.Context, SourceLocation(),
- SourceLocation(), AtIndexGetterSelector,
- S.Context.getObjCIdType() /*ReturnType*/,
- nullptr /*TypeSourceInfo */,
- S.Context.getTranslationUnitDecl(),
- true /*Instance*/, false/*isVariadic*/,
- /*isPropertyAccessor=*/false,
- /*isImplicitlyDeclared=*/true, /*isDefined=*/false,
- ObjCMethodDecl::Required,
- false);
+ AtIndexGetter = ObjCMethodDecl::Create(
+ S.Context, SourceLocation(), SourceLocation(), AtIndexGetterSelector,
+ S.Context.getObjCIdType() /*ReturnType*/, nullptr /*TypeSourceInfo */,
+ S.Context.getTranslationUnitDecl(), true /*Instance*/,
+ false /*isVariadic*/,
+ /*isPropertyAccessor=*/false,
+ /*isSynthesizedAccessorStub=*/false,
+ /*isImplicitlyDeclared=*/true, /*isDefined=*/false,
+ ObjCMethodDecl::Required, false);
ParmVarDecl *Argument = ParmVarDecl::Create(S.Context, AtIndexGetter,
SourceLocation(), SourceLocation(),
arrayRef ? &S.Context.Idents.get("index")
@@ -1303,6 +1302,7 @@ bool ObjCSubscriptOpBuilder::findAtIndexSetter() {
ReturnType, ReturnTInfo, S.Context.getTranslationUnitDecl(),
true /*Instance*/, false /*isVariadic*/,
/*isPropertyAccessor=*/false,
+ /*isSynthesizedAccessorStub=*/false,
/*isImplicitlyDeclared=*/true, /*isDefined=*/false,
ObjCMethodDecl::Required, false);
SmallVector<ParmVarDecl *, 2> Params;
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 6c680f29da4f..d6c3af9e84c8 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -2724,7 +2724,7 @@ static void DiagnoseForRangeReferenceVariableCopies(Sema &SemaRef,
if (!MTE)
return;
- const Expr *E = MTE->GetTemporaryExpr()->IgnoreImpCasts();
+ const Expr *E = MTE->getSubExpr()->IgnoreImpCasts();
// Searching for either UnaryOperator for dereference of a pointer or
// CXXOperatorCallExpr for handling iterators.
@@ -2736,7 +2736,7 @@ static void DiagnoseForRangeReferenceVariableCopies(Sema &SemaRef,
E = ME->getBase();
} else {
const MaterializeTemporaryExpr *MTE = cast<MaterializeTemporaryExpr>(E);
- E = MTE->GetTemporaryExpr();
+ E = MTE->getSubExpr();
}
E = E->IgnoreImpCasts();
}
@@ -2762,19 +2762,32 @@ static void DiagnoseForRangeReferenceVariableCopies(Sema &SemaRef,
QualType NewReferenceType =
SemaRef.Context.getLValueReferenceType(E->getType().withConst());
SemaRef.Diag(VD->getBeginLoc(), diag::note_use_type_or_non_reference)
- << NonReferenceType << NewReferenceType << VD->getSourceRange();
- } else {
+ << NonReferenceType << NewReferenceType << VD->getSourceRange()
+ << FixItHint::CreateRemoval(VD->getTypeSpecEndLoc());
+ } else if (!VariableType->isRValueReferenceType()) {
// The range always returns a copy, so a temporary is always created.
// Suggest removing the reference from the loop variable.
+ // If the type is a rvalue reference do not warn since that changes the
+ // semantic of the code.
SemaRef.Diag(VD->getLocation(), diag::warn_for_range_variable_always_copy)
<< VD << RangeInitType;
QualType NonReferenceType = VariableType.getNonReferenceType();
NonReferenceType.removeLocalConst();
SemaRef.Diag(VD->getBeginLoc(), diag::note_use_non_reference_type)
- << NonReferenceType << VD->getSourceRange();
+ << NonReferenceType << VD->getSourceRange()
+ << FixItHint::CreateRemoval(VD->getTypeSpecEndLoc());
}
}
+/// Determines whether the @p VariableType's declaration is a record with the
+/// clang::trivial_abi attribute.
+static bool hasTrivialABIAttr(QualType VariableType) {
+ if (CXXRecordDecl *RD = VariableType->getAsCXXRecordDecl())
+ return RD->hasAttr<TrivialABIAttr>();
+
+ return false;
+}
+
// Warns when the loop variable can be changed to a reference type to
// prevent a copy. For instance, if given "for (const Foo x : Range)" suggest
// "for (const Foo &x : Range)" if this form does not make a copy.
@@ -2796,10 +2809,13 @@ static void DiagnoseForRangeConstVariableCopies(Sema &SemaRef,
return;
}
- // TODO: Determine a maximum size that a POD type can be before a diagnostic
- // should be emitted. Also, only ignore POD types with trivial copy
- // constructors.
- if (VariableType.isPODType(SemaRef.Context))
+ // Small trivially copyable types are cheap to copy. Do not emit the
+ // diagnostic for these instances. 64 bytes is a common size of a cache line.
+ // (The function `getTypeSize` returns the size in bits.)
+ ASTContext &Ctx = SemaRef.Context;
+ if (Ctx.getTypeSize(VariableType) <= 64 * 8 &&
+ (VariableType.isTriviallyCopyableType(Ctx) ||
+ hasTrivialABIAttr(VariableType)))
return;
// Suggest changing from a const variable to a const reference variable
@@ -2808,7 +2824,8 @@ static void DiagnoseForRangeConstVariableCopies(Sema &SemaRef,
<< VD << VariableType << InitExpr->getType();
SemaRef.Diag(VD->getBeginLoc(), diag::note_use_reference_type)
<< SemaRef.Context.getLValueReferenceType(VariableType)
- << VD->getSourceRange();
+ << VD->getSourceRange()
+ << FixItHint::CreateInsertion(VD->getLocation(), "&");
}
/// DiagnoseForRangeVariableCopies - Diagnose three cases and fixes for them.
@@ -4184,19 +4201,16 @@ StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, SourceLocation TryLoc,
return SEHTryStmt::Create(Context, IsCXXTry, TryLoc, TryBlock, Handler);
}
-StmtResult
-Sema::ActOnSEHExceptBlock(SourceLocation Loc,
- Expr *FilterExpr,
- Stmt *Block) {
+StmtResult Sema::ActOnSEHExceptBlock(SourceLocation Loc, Expr *FilterExpr,
+ Stmt *Block) {
assert(FilterExpr && Block);
-
- if(!FilterExpr->getType()->isIntegerType()) {
- return StmtError(Diag(FilterExpr->getExprLoc(),
- diag::err_filter_expression_integral)
- << FilterExpr->getType());
+ QualType FTy = FilterExpr->getType();
+ if (!FTy->isIntegerType() && !FTy->isDependentType()) {
+ return StmtError(
+ Diag(FilterExpr->getExprLoc(), diag::err_filter_expression_integral)
+ << FTy);
}
-
- return SEHExceptStmt::Create(Context,Loc,FilterExpr,Block);
+ return SEHExceptStmt::Create(Context, Loc, FilterExpr, Block);
}
void Sema::ActOnStartSEHFinallyBlock() {
diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp
index 9b051e02d127..93faf2d151f9 100644
--- a/clang/lib/Sema/SemaStmtAsm.cpp
+++ b/clang/lib/Sema/SemaStmtAsm.cpp
@@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/ExprCXX.h"
+#include "clang/AST/GlobalDecl.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/TargetInfo.h"
@@ -255,6 +256,10 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
// The parser verifies that there is a string literal here.
assert(AsmString->isAscii());
+ FunctionDecl *FD = dyn_cast<FunctionDecl>(getCurLexicalContext());
+ llvm::StringMap<bool> FeatureMap;
+ Context.getFunctionFeatureMap(FeatureMap, FD);
+
for (unsigned i = 0; i != NumOutputs; i++) {
StringLiteral *Literal = Constraints[i];
assert(Literal->isAscii());
@@ -325,8 +330,8 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
}
unsigned Size = Context.getTypeSize(OutputExpr->getType());
- if (!Context.getTargetInfo().validateOutputSize(Literal->getString(),
- Size)) {
+ if (!Context.getTargetInfo().validateOutputSize(
+ FeatureMap, Literal->getString(), Size)) {
targetDiag(OutputExpr->getBeginLoc(), diag::err_asm_invalid_output_size)
<< Info.getConstraintStr();
return new (Context)
@@ -427,8 +432,8 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
return StmtError();
unsigned Size = Context.getTypeSize(Ty);
- if (!Context.getTargetInfo().validateInputSize(Literal->getString(),
- Size))
+ if (!Context.getTargetInfo().validateInputSize(FeatureMap,
+ Literal->getString(), Size))
return StmtResult(
targetDiag(InputExpr->getBeginLoc(), diag::err_asm_invalid_input_size)
<< Info.getConstraintStr());
@@ -702,8 +707,13 @@ void Sema::FillInlineAsmIdentifierInfo(Expr *Res,
if (T->isFunctionType() || T->isDependentType())
return Info.setLabel(Res);
if (Res->isRValue()) {
- if (isa<clang::EnumType>(T) && Res->EvaluateAsRValue(Eval, Context))
+ bool IsEnum = isa<clang::EnumType>(T);
+ if (DeclRefExpr *DRE = dyn_cast<clang::DeclRefExpr>(Res))
+ if (DRE->getDecl()->getKind() == Decl::EnumConstant)
+ IsEnum = true;
+ if (IsEnum && Res->EvaluateAsRValue(Eval, Context))
return Info.setEnum(Eval.Val.getInt().getSExtValue());
+
return Info.setLabel(Res);
}
unsigned Size = Context.getTypeSizeInChars(T).getQuantity();
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 3f2d38630c36..1184446796eb 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -976,20 +976,23 @@ ParsedTemplateArgument Sema::ActOnTemplateTypeArgument(TypeResult ParsedType) {
/// If the type parameter has a default argument, it will be added
/// later via ActOnTypeParameterDefault.
NamedDecl *Sema::ActOnTypeParameter(Scope *S, bool Typename,
- SourceLocation EllipsisLoc,
- SourceLocation KeyLoc,
- IdentifierInfo *ParamName,
- SourceLocation ParamNameLoc,
- unsigned Depth, unsigned Position,
- SourceLocation EqualLoc,
- ParsedType DefaultArg) {
+ SourceLocation EllipsisLoc,
+ SourceLocation KeyLoc,
+ IdentifierInfo *ParamName,
+ SourceLocation ParamNameLoc,
+ unsigned Depth, unsigned Position,
+ SourceLocation EqualLoc,
+ ParsedType DefaultArg,
+ bool HasTypeConstraint) {
assert(S->isTemplateParamScope() &&
"Template type parameter not in template parameter scope!");
bool IsParameterPack = EllipsisLoc.isValid();
- TemplateTypeParmDecl *Param = TemplateTypeParmDecl::Create(
- Context, Context.getTranslationUnitDecl(), KeyLoc, ParamNameLoc, Depth,
- Position, ParamName, Typename, IsParameterPack);
+ TemplateTypeParmDecl *Param
+ = TemplateTypeParmDecl::Create(Context, Context.getTranslationUnitDecl(),
+ KeyLoc, ParamNameLoc, Depth, Position,
+ ParamName, Typename, IsParameterPack,
+ HasTypeConstraint);
Param->setAccess(AS_public);
if (Param->isParameterPack())
@@ -1036,6 +1039,125 @@ NamedDecl *Sema::ActOnTypeParameter(Scope *S, bool Typename,
return Param;
}
+/// Convert the parser's template argument list representation into our form.
+static TemplateArgumentListInfo
+makeTemplateArgumentListInfo(Sema &S, TemplateIdAnnotation &TemplateId) {
+ TemplateArgumentListInfo TemplateArgs(TemplateId.LAngleLoc,
+ TemplateId.RAngleLoc);
+ ASTTemplateArgsPtr TemplateArgsPtr(TemplateId.getTemplateArgs(),
+ TemplateId.NumArgs);
+ S.translateTemplateArguments(TemplateArgsPtr, TemplateArgs);
+ return TemplateArgs;
+}
+
+bool Sema::ActOnTypeConstraint(TemplateIdAnnotation *TypeConstr,
+ TemplateTypeParmDecl *ConstrainedParameter,
+ SourceLocation EllipsisLoc) {
+ ConceptDecl *CD =
+ cast<ConceptDecl>(TypeConstr->Template.get().getAsTemplateDecl());
+
+ // C++2a [temp.param]p4:
+ // [...] The concept designated by a type-constraint shall be a type
+ // concept ([temp.concept]).
+ if (!CD->isTypeConcept()) {
+ Diag(TypeConstr->TemplateNameLoc,
+ diag::err_type_constraint_non_type_concept);
+ return true;
+ }
+
+ bool WereArgsSpecified = TypeConstr->LAngleLoc.isValid();
+
+ if (!WereArgsSpecified &&
+ CD->getTemplateParameters()->getMinRequiredArguments() > 1) {
+ Diag(TypeConstr->TemplateNameLoc,
+ diag::err_type_constraint_missing_arguments) << CD;
+ return true;
+ }
+
+ TemplateArgumentListInfo TemplateArgs;
+ if (TypeConstr->LAngleLoc.isValid()) {
+ TemplateArgs =
+ makeTemplateArgumentListInfo(*this, *TypeConstr);
+ }
+ return AttachTypeConstraint(
+ TypeConstr->SS.isSet() ? TypeConstr->SS.getWithLocInContext(Context) :
+ NestedNameSpecifierLoc(),
+ DeclarationNameInfo(DeclarationName(TypeConstr->Name),
+ TypeConstr->TemplateNameLoc), CD,
+ TypeConstr->LAngleLoc.isValid() ? &TemplateArgs : nullptr,
+ ConstrainedParameter, EllipsisLoc);
+}
+
+/// Attach a type-constraint to a template parameter.
+/// \returns true if an error occured. This can happen if the
+/// immediately-declared constraint could not be formed (e.g. incorrect number
+/// of arguments for the named concept).
+bool Sema::AttachTypeConstraint(NestedNameSpecifierLoc NS,
+ DeclarationNameInfo NameInfo,
+ ConceptDecl *NamedConcept,
+ const TemplateArgumentListInfo *TemplateArgs,
+ TemplateTypeParmDecl *ConstrainedParameter,
+ SourceLocation EllipsisLoc) {
+ // C++2a [temp.param]p4:
+ // [...] If Q is of the form C<A1, ..., An>, then let E' be
+ // C<T, A1, ..., An>. Otherwise, let E' be C<T>. [...]
+ const ASTTemplateArgumentListInfo *ArgsAsWritten =
+ TemplateArgs ? ASTTemplateArgumentListInfo::Create(Context,
+ *TemplateArgs) : nullptr;
+
+ QualType ParamAsArgument(ConstrainedParameter->getTypeForDecl(), 0);
+ TemplateArgumentListInfo ConstraintArgs;
+ ConstraintArgs.addArgument(
+ TemplateArgumentLoc(
+ TemplateArgument(ParamAsArgument),
+ TemplateArgumentLocInfo(
+ Context.getTrivialTypeSourceInfo(ParamAsArgument,
+ ConstrainedParameter->getLocation()))));
+ if (TemplateArgs) {
+ ConstraintArgs.setRAngleLoc(TemplateArgs->getRAngleLoc());
+ ConstraintArgs.setLAngleLoc(TemplateArgs->getLAngleLoc());
+ for (const TemplateArgumentLoc &ArgLoc : TemplateArgs->arguments())
+ ConstraintArgs.addArgument(ArgLoc);
+ }
+
+ // C++2a [temp.param]p4:
+ // [...] This constraint-expression E is called the immediately-declared
+ // constraint of T. [...]
+ CXXScopeSpec SS;
+ SS.Adopt(NS);
+ ExprResult ImmediatelyDeclaredConstraint = CheckConceptTemplateId(SS,
+ /*TemplateKWLoc=*/SourceLocation(), NameInfo, /*FoundDecl=*/NamedConcept,
+ NamedConcept, &ConstraintArgs);
+ if (ImmediatelyDeclaredConstraint.isInvalid())
+ return true;
+
+ if (ConstrainedParameter->isParameterPack()) {
+ // C++2a [temp.param]p4:
+ // [...] If T is not a pack, then E is E', otherwise E is (E' && ...).
+ //
+ // We have the following case:
+ //
+ // template<typename T> concept C1 = true;
+ // template<C1... T> struct s1;
+ //
+ // The constraint: (C1<T> && ...)
+ ImmediatelyDeclaredConstraint =
+ BuildCXXFoldExpr(/*LParenLoc=*/SourceLocation(),
+ ImmediatelyDeclaredConstraint.get(), BO_LAnd,
+ EllipsisLoc, /*RHS=*/nullptr,
+ /*RParenLoc=*/SourceLocation(),
+ /*NumExpansions=*/None).get();
+ if (ImmediatelyDeclaredConstraint.isInvalid())
+ return true;
+ }
+
+ ConstrainedParameter->setTypeConstraint(NS, NameInfo,
+ /*FoundDecl=*/NamedConcept,
+ NamedConcept, ArgsAsWritten,
+ ImmediatelyDeclaredConstraint.get());
+ return false;
+}
+
/// Check that the type of a non-type template parameter is
/// well-formed.
///
@@ -1120,11 +1242,11 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
// Check that we have valid decl-specifiers specified.
auto CheckValidDeclSpecifiers = [this, &D] {
// C++ [temp.param]
- // p1
+ // p1
// template-parameter:
// ...
// parameter-declaration
- // p2
+ // p2
// ... A storage class shall not be specified in a template-parameter
// declaration.
// [dcl.typedef]p1:
@@ -1868,7 +1990,23 @@ private:
SemaRef.Context, DC, TTP->getBeginLoc(), TTP->getLocation(),
/*Depth*/ 0, Depth1IndexAdjustment + TTP->getIndex(),
TTP->getIdentifier(), TTP->wasDeclaredWithTypename(),
- TTP->isParameterPack());
+ TTP->isParameterPack(), TTP->hasTypeConstraint(),
+ TTP->isExpandedParameterPack() ?
+ llvm::Optional<unsigned>(TTP->getNumExpansionParameters()) : None);
+ if (const auto *TC = TTP->getTypeConstraint()) {
+ TemplateArgumentListInfo TransformedArgs;
+ const auto *ArgsAsWritten = TC->getTemplateArgsAsWritten();
+ if (SemaRef.Subst(ArgsAsWritten->getTemplateArgs(),
+ ArgsAsWritten->NumTemplateArgs, TransformedArgs,
+ Args))
+ SemaRef.AttachTypeConstraint(
+ TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(),
+ TC->getNamedConcept(), &TransformedArgs, NewTTP,
+ NewTTP->isParameterPack()
+ ? cast<CXXFoldExpr>(TC->getImmediatelyDeclaredConstraint())
+ ->getEllipsisLoc()
+ : SourceLocation());
+ }
if (TTP->hasDefaultArgument()) {
TypeSourceInfo *InstantiatedDefaultArg =
SemaRef.SubstType(TTP->getDefaultArgumentInfo(), Args,
@@ -1894,7 +2032,7 @@ private:
// Ask the template instantiator to do the heavy lifting for us, then adjust
// the index of the parameter once it's done.
auto *NewParam =
- cast_or_null<TemplateParmDecl>(SemaRef.SubstDecl(OldParam, DC, Args));
+ cast<TemplateParmDecl>(SemaRef.SubstDecl(OldParam, DC, Args));
assert(NewParam->getDepth() == 0 && "unexpected template param depth");
NewParam->setPosition(NewParam->getPosition() + Depth1IndexAdjustment);
return NewParam;
@@ -2177,6 +2315,17 @@ static bool DiagnoseUnexpandedParameterPacks(Sema &S,
TemplateParameterList *Params = TTP->getTemplateParameters();
for (unsigned I = 0, N = Params->size(); I != N; ++I) {
NamedDecl *P = Params->getParam(I);
+ if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(P)) {
+ if (!TTP->isParameterPack())
+ if (const TypeConstraint *TC = TTP->getTypeConstraint())
+ if (TC->hasExplicitTemplateArgs())
+ for (auto &ArgLoc : TC->getTemplateArgsAsWritten()->arguments())
+ if (S.DiagnoseUnexpandedParameterPack(ArgLoc,
+ Sema::UPPC_TypeConstraint))
+ return true;
+ continue;
+ }
+
if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P)) {
if (!NTTP->isParameterPack() &&
S.DiagnoseUnexpandedParameterPack(NTTP->getLocation(),
@@ -2549,6 +2698,9 @@ struct DependencyChecker : RecursiveASTVisitor<DependencyChecker> {
/// list.
static bool
DependsOnTemplateParameters(QualType T, TemplateParameterList *Params) {
+ if (!Params->size())
+ return false;
+
DependencyChecker Checker(Params, /*IgnoreNonTypeDependent*/false);
Checker.TraverseType(T);
return Checker.Match;
@@ -3210,8 +3362,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
TemplateDecl *Template = Name.getAsTemplateDecl();
if (!Template || isa<FunctionTemplateDecl>(Template) ||
- isa<VarTemplateDecl>(Template) ||
- isa<ConceptDecl>(Template)) {
+ isa<VarTemplateDecl>(Template) || isa<ConceptDecl>(Template)) {
// We might have a substituted template template parameter pack. If so,
// build a template specialization type for it.
if (Name.getAsSubstTemplateTemplateParmPack())
@@ -3227,7 +3378,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
// template.
SmallVector<TemplateArgument, 4> Converted;
if (CheckTemplateArgumentList(Template, TemplateLoc, TemplateArgs,
- false, Converted))
+ false, Converted,
+ /*UpdateArgsWithConversion=*/true))
return QualType();
QualType CanonType;
@@ -3235,6 +3387,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
bool InstantiationDependent = false;
if (TypeAliasTemplateDecl *AliasTemplate =
dyn_cast<TypeAliasTemplateDecl>(Template)) {
+
// Find the canonical type for this type alias template specialization.
TypeAliasDecl *Pattern = AliasTemplate->getTemplatedDecl();
if (Pattern->isInvalidDecl())
@@ -3707,17 +3860,6 @@ static bool isSameAsPrimaryTemplate(TemplateParameterList *Params,
return true;
}
-/// Convert the parser's template argument list representation into our form.
-static TemplateArgumentListInfo
-makeTemplateArgumentListInfo(Sema &S, TemplateIdAnnotation &TemplateId) {
- TemplateArgumentListInfo TemplateArgs(TemplateId.LAngleLoc,
- TemplateId.RAngleLoc);
- ASTTemplateArgsPtr TemplateArgsPtr(TemplateId.getTemplateArgs(),
- TemplateId.NumArgs);
- S.translateTemplateArguments(TemplateArgsPtr, TemplateArgs);
- return TemplateArgs;
-}
-
template<typename PartialSpecDecl>
static void checkMoreSpecializedThanPrimary(Sema &S, PartialSpecDecl *Partial) {
if (Partial->getDeclContext()->isDependentContext())
@@ -3746,6 +3888,11 @@ static void checkMoreSpecializedThanPrimary(Sema &S, PartialSpecDecl *Partial) {
}
S.Diag(Template->getLocation(), diag::note_template_decl_here);
+ SmallVector<const Expr *, 3> PartialAC, TemplateAC;
+ Template->getAssociatedConstraints(TemplateAC);
+ Partial->getAssociatedConstraints(PartialAC);
+ S.MaybeEmitAmbiguousAtomicConstraintsDiagnostic(Partial, PartialAC, Template,
+ TemplateAC);
}
static void
@@ -3872,7 +4019,8 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
// template.
SmallVector<TemplateArgument, 4> Converted;
if (CheckTemplateArgumentList(VarTemplate, TemplateNameLoc, TemplateArgs,
- false, Converted))
+ false, Converted,
+ /*UpdateArgsWithConversion=*/true))
return true;
// Find the variable template (partial) specialization declaration that
@@ -3895,7 +4043,9 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
}
if (isSameAsPrimaryTemplate(VarTemplate->getTemplateParameters(),
- Converted)) {
+ Converted) &&
+ (!Context.getLangOpts().ConceptsTS ||
+ !TemplateParams->hasAssociatedConstraints())) {
// C++ [temp.class.spec]p9b3:
//
// -- The argument list of the specialization shall not be identical
@@ -3914,8 +4064,8 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
VarTemplateSpecializationDecl *PrevDecl = nullptr;
if (IsPartialSpecialization)
- // FIXME: Template parameter list matters too
- PrevDecl = VarTemplate->findPartialSpecialization(Converted, InsertPos);
+ PrevDecl = VarTemplate->findPartialSpecialization(Converted, TemplateParams,
+ InsertPos);
else
PrevDecl = VarTemplate->findSpecialization(Converted, InsertPos);
@@ -4043,7 +4193,7 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
if (CheckTemplateArgumentList(
Template, TemplateNameLoc,
const_cast<TemplateArgumentListInfo &>(TemplateArgs), false,
- Converted))
+ Converted, /*UpdateArgsWithConversion=*/true))
return true;
// Find the variable template specialization declaration that
@@ -4221,20 +4371,20 @@ void Sema::diagnoseMissingTemplateArguments(TemplateName Name,
ExprResult
Sema::CheckConceptTemplateId(const CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
- SourceLocation ConceptNameLoc,
+ const DeclarationNameInfo &ConceptNameInfo,
NamedDecl *FoundDecl,
ConceptDecl *NamedConcept,
const TemplateArgumentListInfo *TemplateArgs) {
assert(NamedConcept && "A concept template id without a template?");
llvm::SmallVector<TemplateArgument, 4> Converted;
- if (CheckTemplateArgumentList(NamedConcept, ConceptNameLoc,
+ if (CheckTemplateArgumentList(NamedConcept, ConceptNameInfo.getLoc(),
const_cast<TemplateArgumentListInfo&>(*TemplateArgs),
/*PartialTemplateArgs=*/false, Converted,
/*UpdateArgsWithConversion=*/false))
return ExprError();
- Optional<bool> IsSatisfied;
+ ConstraintSatisfaction Satisfaction;
bool AreArgsDependent = false;
for (TemplateArgument &Arg : Converted) {
if (Arg.isDependent()) {
@@ -4242,25 +4392,21 @@ Sema::CheckConceptTemplateId(const CXXScopeSpec &SS,
break;
}
}
- if (!AreArgsDependent) {
- InstantiatingTemplate Inst(*this, ConceptNameLoc,
- InstantiatingTemplate::ConstraintsCheck{}, NamedConcept, Converted,
- SourceRange(SS.isSet() ? SS.getBeginLoc() : ConceptNameLoc,
- TemplateArgs->getRAngleLoc()));
- MultiLevelTemplateArgumentList MLTAL;
- MLTAL.addOuterTemplateArguments(Converted);
- bool Satisfied;
- if (CalculateConstraintSatisfaction(NamedConcept, MLTAL,
- NamedConcept->getConstraintExpr(),
- Satisfied))
+ if (!AreArgsDependent &&
+ CheckConstraintSatisfaction(NamedConcept,
+ {NamedConcept->getConstraintExpr()},
+ Converted,
+ SourceRange(SS.isSet() ? SS.getBeginLoc() :
+ ConceptNameInfo.getLoc(),
+ TemplateArgs->getRAngleLoc()),
+ Satisfaction))
return ExprError();
- IsSatisfied = Satisfied;
- }
+
return ConceptSpecializationExpr::Create(Context,
SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc{},
- TemplateKWLoc, ConceptNameLoc, FoundDecl, NamedConcept,
+ TemplateKWLoc, ConceptNameInfo, FoundDecl, NamedConcept,
ASTTemplateArgumentListInfo::Create(Context, *TemplateArgs), Converted,
- IsSatisfied);
+ AreArgsDependent ? nullptr : &Satisfaction);
}
ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
@@ -4304,8 +4450,7 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
}
if (R.getAsSingle<ConceptDecl>()) {
- return CheckConceptTemplateId(SS, TemplateKWLoc,
- R.getLookupNameInfo().getBeginLoc(),
+ return CheckConceptTemplateId(SS, TemplateKWLoc, R.getLookupNameInfo(),
R.getFoundDecl(),
R.getAsSingle<ConceptDecl>(), TemplateArgs);
}
@@ -5108,7 +5253,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion:
- if (CheckTemplateTemplateArgument(Params, Arg))
+ if (CheckTemplateTemplateArgument(TempParm, Params, Arg))
return true;
Converted.push_back(Arg.getArgument());
@@ -5148,6 +5293,12 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
/// In \c A<int,int>::B, \c NTs and \c TTs have expanded pack size 2, and \c Us
/// is not a pack expansion, so returns an empty Optional.
static Optional<unsigned> getExpandedPackSize(NamedDecl *Param) {
+ if (TemplateTypeParmDecl *TTP
+ = dyn_cast<TemplateTypeParmDecl>(Param)) {
+ if (TTP->isExpandedParameterPack())
+ return TTP->getNumExpansionParameters();
+ }
+
if (NonTypeTemplateParmDecl *NTTP
= dyn_cast<NonTypeTemplateParmDecl>(Param)) {
if (NTTP->isExpandedParameterPack())
@@ -5206,7 +5357,11 @@ bool Sema::CheckTemplateArgumentList(
TemplateDecl *Template, SourceLocation TemplateLoc,
TemplateArgumentListInfo &TemplateArgs, bool PartialTemplateArgs,
SmallVectorImpl<TemplateArgument> &Converted,
- bool UpdateArgsWithConversions) {
+ bool UpdateArgsWithConversions, bool *ConstraintsNotSatisfied) {
+
+ if (ConstraintsNotSatisfied)
+ *ConstraintsNotSatisfied = false;
+
// Make a copy of the template arguments for processing. Only make the
// changes at the end when successful in matching the arguments to the
// template.
@@ -5268,12 +5423,16 @@ bool Sema::CheckTemplateArgumentList(
bool PackExpansionIntoNonPack =
NewArgs[ArgIdx].getArgument().isPackExpansion() &&
(!(*Param)->isTemplateParameterPack() || getExpandedPackSize(*Param));
- if (PackExpansionIntoNonPack && isa<TypeAliasTemplateDecl>(Template)) {
+ if (PackExpansionIntoNonPack && (isa<TypeAliasTemplateDecl>(Template) ||
+ isa<ConceptDecl>(Template))) {
// Core issue 1430: we have a pack expansion as an argument to an
// alias template, and it's not part of a parameter pack. This
// can't be canonicalized, so reject it now.
+ // As for concepts - we cannot normalize constraints where this
+ // situation exists.
Diag(NewArgs[ArgIdx].getLocation(),
- diag::err_alias_template_expansion_into_fixed_list)
+ diag::err_template_expansion_into_fixed_list)
+ << (isa<ConceptDecl>(Template) ? 1 : 0)
<< NewArgs[ArgIdx].getSourceRange();
Diag((*Param)->getLocation(), diag::note_template_param_here);
return true;
@@ -5321,7 +5480,6 @@ bool Sema::CheckTemplateArgumentList(
if ((*Param)->isTemplateParameterPack() && !ArgumentPack.empty())
Converted.push_back(
TemplateArgument::CreatePackCopy(Context, ArgumentPack));
-
return false;
}
@@ -5460,6 +5618,15 @@ bool Sema::CheckTemplateArgumentList(
if (UpdateArgsWithConversions)
TemplateArgs = std::move(NewArgs);
+ if (!PartialTemplateArgs &&
+ EnsureTemplateArgumentListConstraints(
+ Template, Converted, SourceRange(TemplateLoc,
+ TemplateArgs.getRAngleLoc()))) {
+ if (ConstraintsNotSatisfied)
+ *ConstraintsNotSatisfied = true;
+ return true;
+ }
+
return false;
}
@@ -6870,7 +7037,8 @@ static void DiagnoseTemplateParameterListArityMismatch(
///
/// This routine implements the semantics of C++ [temp.arg.template].
/// It returns true if an error occurred, and false otherwise.
-bool Sema::CheckTemplateTemplateArgument(TemplateParameterList *Params,
+bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param,
+ TemplateParameterList *Params,
TemplateArgumentLoc &Arg) {
TemplateName Name = Arg.getArgument().getAsTemplateOrTemplatePattern();
TemplateDecl *Template = Name.getAsTemplateDecl();
@@ -6909,6 +7077,9 @@ bool Sema::CheckTemplateTemplateArgument(TemplateParameterList *Params,
// C++1z [temp.arg.template]p3: (DR 150)
// A template-argument matches a template template-parameter P when P
// is at least as specialized as the template-argument A.
+ // FIXME: We should enable RelaxedTemplateTemplateArgs by default as it is a
+ // defect report resolution from C++17 and shouldn't be introduced by
+ // concepts.
if (getLangOpts().RelaxedTemplateTemplateArgs) {
// Quick check for the common case:
// If P contains a parameter pack, then A [...] matches P if each of A's
@@ -6916,12 +7087,39 @@ bool Sema::CheckTemplateTemplateArgument(TemplateParameterList *Params,
// the template-parameter-list of P.
if (TemplateParameterListsAreEqual(
Template->getTemplateParameters(), Params, false,
- TPL_TemplateTemplateArgumentMatch, Arg.getLocation()))
+ TPL_TemplateTemplateArgumentMatch, Arg.getLocation()) &&
+ // If the argument has no associated constraints, then the parameter is
+ // definitely at least as specialized as the argument.
+ // Otherwise - we need a more thorough check.
+ !Template->hasAssociatedConstraints())
return false;
if (isTemplateTemplateParameterAtLeastAsSpecializedAs(Params, Template,
- Arg.getLocation()))
+ Arg.getLocation())) {
+ // C++2a[temp.func.order]p2
+ // [...] If both deductions succeed, the partial ordering selects the
+ // more constrained template as described by the rules in
+ // [temp.constr.order].
+ SmallVector<const Expr *, 3> ParamsAC, TemplateAC;
+ Params->getAssociatedConstraints(ParamsAC);
+ Template->getAssociatedConstraints(TemplateAC);
+ bool IsParamAtLeastAsConstrained;
+ if (IsAtLeastAsConstrained(Param, ParamsAC, Template, TemplateAC,
+ IsParamAtLeastAsConstrained))
+ return true;
+ if (!IsParamAtLeastAsConstrained) {
+ Diag(Arg.getLocation(),
+ diag::err_template_template_parameter_not_at_least_as_constrained)
+ << Template << Param << Arg.getSourceRange();
+ Diag(Param->getLocation(), diag::note_entity_declared_at) << Param;
+ Diag(Template->getLocation(), diag::note_entity_declared_at)
+ << Template;
+ MaybeEmitAmbiguousAtomicConstraintsDiagnostic(Param, ParamsAC, Template,
+ TemplateAC);
+ return true;
+ }
return false;
+ }
// FIXME: Produce better diagnostics for deduction failures.
}
@@ -6965,94 +7163,73 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,
ValueDecl *VD = Arg.getAsDecl();
- if (VD->getDeclContext()->isRecord() &&
- (isa<CXXMethodDecl>(VD) || isa<FieldDecl>(VD) ||
- isa<IndirectFieldDecl>(VD))) {
- // If the value is a class member, we might have a pointer-to-member.
- // Determine whether the non-type template template parameter is of
- // pointer-to-member type. If so, we need to build an appropriate
- // expression for a pointer-to-member, since a "normal" DeclRefExpr
- // would refer to the member itself.
- if (ParamType->isMemberPointerType()) {
- QualType ClassType
- = Context.getTypeDeclType(cast<RecordDecl>(VD->getDeclContext()));
- NestedNameSpecifier *Qualifier
- = NestedNameSpecifier::Create(Context, nullptr, false,
- ClassType.getTypePtr());
- CXXScopeSpec SS;
- SS.MakeTrivial(Context, Qualifier, Loc);
-
- // The actual value-ness of this is unimportant, but for
- // internal consistency's sake, references to instance methods
- // are r-values.
- ExprValueKind VK = VK_LValue;
- if (isa<CXXMethodDecl>(VD) && cast<CXXMethodDecl>(VD)->isInstance())
- VK = VK_RValue;
-
- ExprResult RefExpr = BuildDeclRefExpr(VD,
- VD->getType().getNonReferenceType(),
- VK,
- Loc,
- &SS);
- if (RefExpr.isInvalid())
- return ExprError();
-
- RefExpr = CreateBuiltinUnaryOp(Loc, UO_AddrOf, RefExpr.get());
-
- // We might need to perform a trailing qualification conversion, since
- // the element type on the parameter could be more qualified than the
- // element type in the expression we constructed.
- bool ObjCLifetimeConversion;
- if (IsQualificationConversion(((Expr*) RefExpr.get())->getType(),
- ParamType.getUnqualifiedType(), false,
- ObjCLifetimeConversion))
- RefExpr = ImpCastExprToType(RefExpr.get(), ParamType.getUnqualifiedType(), CK_NoOp);
-
- assert(!RefExpr.isInvalid() &&
- Context.hasSameType(((Expr*) RefExpr.get())->getType(),
- ParamType.getUnqualifiedType()));
- return RefExpr;
- }
- }
-
- QualType T = VD->getType().getNonReferenceType();
+ CXXScopeSpec SS;
+ if (ParamType->isMemberPointerType()) {
+ // If this is a pointer to member, we need to use a qualified name to
+ // form a suitable pointer-to-member constant.
+ assert(VD->getDeclContext()->isRecord() &&
+ (isa<CXXMethodDecl>(VD) || isa<FieldDecl>(VD) ||
+ isa<IndirectFieldDecl>(VD)));
+ QualType ClassType
+ = Context.getTypeDeclType(cast<RecordDecl>(VD->getDeclContext()));
+ NestedNameSpecifier *Qualifier
+ = NestedNameSpecifier::Create(Context, nullptr, false,
+ ClassType.getTypePtr());
+ SS.MakeTrivial(Context, Qualifier, Loc);
+ }
+
+ ExprResult RefExpr = BuildDeclarationNameExpr(
+ SS, DeclarationNameInfo(VD->getDeclName(), Loc), VD);
+ if (RefExpr.isInvalid())
+ return ExprError();
- if (ParamType->isPointerType()) {
- // When the non-type template parameter is a pointer, take the
- // address of the declaration.
- ExprResult RefExpr = BuildDeclRefExpr(VD, T, VK_LValue, Loc);
+ // For a pointer, the argument declaration is the pointee. Take its address.
+ QualType ElemT(RefExpr.get()->getType()->getArrayElementTypeNoTypeQual(), 0);
+ if (ParamType->isPointerType() && !ElemT.isNull() &&
+ Context.hasSimilarType(ElemT, ParamType->getPointeeType())) {
+ // Decay an array argument if we want a pointer to its first element.
+ RefExpr = DefaultFunctionArrayConversion(RefExpr.get());
if (RefExpr.isInvalid())
return ExprError();
-
- if (!Context.hasSameUnqualifiedType(ParamType->getPointeeType(), T) &&
- (T->isFunctionType() || T->isArrayType())) {
- // Decay functions and arrays unless we're forming a pointer to array.
- RefExpr = DefaultFunctionArrayConversion(RefExpr.get());
- if (RefExpr.isInvalid())
- return ExprError();
-
- return RefExpr;
+ } else if (ParamType->isPointerType() || ParamType->isMemberPointerType()) {
+ // For any other pointer, take the address (or form a pointer-to-member).
+ RefExpr = CreateBuiltinUnaryOp(Loc, UO_AddrOf, RefExpr.get());
+ if (RefExpr.isInvalid())
+ return ExprError();
+ } else {
+ assert(ParamType->isReferenceType() &&
+ "unexpected type for decl template argument");
+ }
+
+ // At this point we should have the right value category.
+ assert(ParamType->isReferenceType() == RefExpr.get()->isLValue() &&
+ "value kind mismatch for non-type template argument");
+
+ // The type of the template parameter can differ from the type of the
+ // argument in various ways; convert it now if necessary.
+ QualType DestExprType = ParamType.getNonLValueExprType(Context);
+ if (!Context.hasSameType(RefExpr.get()->getType(), DestExprType)) {
+ CastKind CK;
+ QualType Ignored;
+ if (Context.hasSimilarType(RefExpr.get()->getType(), DestExprType) ||
+ IsFunctionConversion(RefExpr.get()->getType(), DestExprType, Ignored)) {
+ CK = CK_NoOp;
+ } else if (ParamType->isVoidPointerType() &&
+ RefExpr.get()->getType()->isPointerType()) {
+ CK = CK_BitCast;
+ } else {
+ // FIXME: Pointers to members can need conversion derived-to-base or
+ // base-to-derived conversions. We currently don't retain enough
+ // information to convert properly (we need to track a cast path or
+ // subobject number in the template argument).
+ llvm_unreachable(
+ "unexpected conversion required for non-type template argument");
}
-
- // Take the address of everything else
- return CreateBuiltinUnaryOp(Loc, UO_AddrOf, RefExpr.get());
+ RefExpr = ImpCastExprToType(RefExpr.get(), DestExprType, CK,
+ RefExpr.get()->getValueKind());
}
- ExprValueKind VK = VK_RValue;
-
- // If the non-type template parameter has reference type, qualify the
- // resulting declaration reference with the extra qualifiers on the
- // type that the reference refers to.
- if (const ReferenceType *TargetRef = ParamType->getAs<ReferenceType>()) {
- VK = VK_LValue;
- T = Context.getQualifiedType(T,
- TargetRef->getPointeeType().getQualifiers());
- } else if (isa<FunctionDecl>(VD)) {
- // References to functions are always lvalues.
- VK = VK_LValue;
- }
-
- return BuildDeclRefExpr(VD, T, VK, Loc);
+ return RefExpr;
}
/// Construct a new expression that refers to the given
@@ -7173,50 +7350,73 @@ static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old,
// template parameter and one of the non-type template parameter types
// is dependent, then we must wait until template instantiation time
// to actually compare the arguments.
- if (Kind == Sema::TPL_TemplateTemplateArgumentMatch &&
- (OldNTTP->getType()->isDependentType() ||
- NewNTTP->getType()->isDependentType()))
- return true;
-
- if (!S.Context.hasSameType(OldNTTP->getType(), NewNTTP->getType())) {
- if (Complain) {
- unsigned NextDiag = diag::err_template_nontype_parm_different_type;
- if (TemplateArgLoc.isValid()) {
- S.Diag(TemplateArgLoc,
- diag::err_template_arg_template_params_mismatch);
- NextDiag = diag::note_template_nontype_parm_different_type;
+ if (Kind != Sema::TPL_TemplateTemplateArgumentMatch ||
+ (!OldNTTP->getType()->isDependentType() &&
+ !NewNTTP->getType()->isDependentType()))
+ if (!S.Context.hasSameType(OldNTTP->getType(), NewNTTP->getType())) {
+ if (Complain) {
+ unsigned NextDiag = diag::err_template_nontype_parm_different_type;
+ if (TemplateArgLoc.isValid()) {
+ S.Diag(TemplateArgLoc,
+ diag::err_template_arg_template_params_mismatch);
+ NextDiag = diag::note_template_nontype_parm_different_type;
+ }
+ S.Diag(NewNTTP->getLocation(), NextDiag)
+ << NewNTTP->getType()
+ << (Kind != Sema::TPL_TemplateMatch);
+ S.Diag(OldNTTP->getLocation(),
+ diag::note_template_nontype_parm_prev_declaration)
+ << OldNTTP->getType();
}
- S.Diag(NewNTTP->getLocation(), NextDiag)
- << NewNTTP->getType()
- << (Kind != Sema::TPL_TemplateMatch);
- S.Diag(OldNTTP->getLocation(),
- diag::note_template_nontype_parm_prev_declaration)
- << OldNTTP->getType();
- }
- return false;
- }
-
- return true;
+ return false;
+ }
}
-
// For template template parameters, check the template parameter types.
// The template parameter lists of template template
// parameters must agree.
- if (TemplateTemplateParmDecl *OldTTP
+ else if (TemplateTemplateParmDecl *OldTTP
= dyn_cast<TemplateTemplateParmDecl>(Old)) {
TemplateTemplateParmDecl *NewTTP = cast<TemplateTemplateParmDecl>(New);
- return S.TemplateParameterListsAreEqual(NewTTP->getTemplateParameters(),
- OldTTP->getTemplateParameters(),
- Complain,
+ if (!S.TemplateParameterListsAreEqual(NewTTP->getTemplateParameters(),
+ OldTTP->getTemplateParameters(),
+ Complain,
(Kind == Sema::TPL_TemplateMatch
? Sema::TPL_TemplateTemplateParmMatch
: Kind),
- TemplateArgLoc);
- }
+ TemplateArgLoc))
+ return false;
+ } else if (Kind != Sema::TPL_TemplateTemplateArgumentMatch) {
+ const Expr *NewC = nullptr, *OldC = nullptr;
+ if (const auto *TC = cast<TemplateTypeParmDecl>(New)->getTypeConstraint())
+ NewC = TC->getImmediatelyDeclaredConstraint();
+ if (const auto *TC = cast<TemplateTypeParmDecl>(Old)->getTypeConstraint())
+ OldC = TC->getImmediatelyDeclaredConstraint();
+
+ auto Diagnose = [&] {
+ S.Diag(NewC ? NewC->getBeginLoc() : New->getBeginLoc(),
+ diag::err_template_different_type_constraint);
+ S.Diag(OldC ? OldC->getBeginLoc() : Old->getBeginLoc(),
+ diag::note_template_prev_declaration) << /*declaration*/0;
+ };
+
+ if (!NewC != !OldC) {
+ if (Complain)
+ Diagnose();
+ return false;
+ }
- // TODO: Concepts: Match immediately-introduced-constraint for type
- // constraints
+ if (NewC) {
+ llvm::FoldingSetNodeID OldCID, NewCID;
+ OldC->Profile(OldCID, S.Context, /*Canonical=*/true);
+ NewC->Profile(NewCID, S.Context, /*Canonical=*/true);
+ if (OldCID != NewCID) {
+ if (Complain)
+ Diagnose();
+ return false;
+ }
+ }
+ }
return true;
}
@@ -7243,15 +7443,6 @@ void DiagnoseTemplateParameterListArityMismatch(Sema &S,
<< SourceRange(Old->getTemplateLoc(), Old->getRAngleLoc());
}
-static void
-DiagnoseTemplateParameterListRequiresClauseMismatch(Sema &S,
- TemplateParameterList *New,
- TemplateParameterList *Old){
- S.Diag(New->getTemplateLoc(), diag::err_template_different_requires_clause);
- S.Diag(Old->getTemplateLoc(), diag::note_template_prev_declaration)
- << /*declaration*/0;
-}
-
/// Determine whether the given template parameter lists are
/// equivalent.
///
@@ -7344,9 +7535,17 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
if (Kind != TPL_TemplateTemplateArgumentMatch) {
const Expr *NewRC = New->getRequiresClause();
const Expr *OldRC = Old->getRequiresClause();
+
+ auto Diagnose = [&] {
+ Diag(NewRC ? NewRC->getBeginLoc() : New->getTemplateLoc(),
+ diag::err_template_different_requires_clause);
+ Diag(OldRC ? OldRC->getBeginLoc() : Old->getTemplateLoc(),
+ diag::note_template_prev_declaration) << /*declaration*/0;
+ };
+
if (!NewRC != !OldRC) {
if (Complain)
- DiagnoseTemplateParameterListRequiresClauseMismatch(*this, New, Old);
+ Diagnose();
return false;
}
@@ -7356,7 +7555,7 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
NewRC->Profile(NewRCID, Context, /*Canonical=*/true);
if (OldRCID != NewRCID) {
if (Complain)
- DiagnoseTemplateParameterListRequiresClauseMismatch(*this, New, Old);
+ Diagnose();
return false;
}
}
@@ -7382,7 +7581,8 @@ Sema::CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams) {
// C++ [temp]p4:
// A template [...] shall not have C linkage.
DeclContext *Ctx = S->getEntity();
- if (Ctx && Ctx->isExternCContext()) {
+ assert(Ctx && "Unknown context");
+ if (Ctx->isExternCContext()) {
Diag(TemplateParams->getTemplateLoc(), diag::err_template_linkage)
<< TemplateParams->getSourceRange();
if (const LinkageSpecDecl *LSD = Ctx->getExternCContext())
@@ -7794,7 +7994,8 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
// template.
SmallVector<TemplateArgument, 4> Converted;
if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc,
- TemplateArgs, false, Converted))
+ TemplateArgs, false, Converted,
+ /*UpdateArgsWithConversion=*/true))
return true;
// Find the class template (partial) specialization declaration that
@@ -7820,8 +8021,9 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
ClassTemplateSpecializationDecl *PrevDecl = nullptr;
if (isPartialSpecialization)
- // FIXME: Template parameter list matters, too
- PrevDecl = ClassTemplate->findPartialSpecialization(Converted, InsertPos);
+ PrevDecl = ClassTemplate->findPartialSpecialization(Converted,
+ TemplateParams,
+ InsertPos);
else
PrevDecl = ClassTemplate->findSpecialization(Converted, InsertPos);
@@ -7845,7 +8047,9 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
Converted);
if (Context.hasSameType(CanonType,
- ClassTemplate->getInjectedClassNameSpecialization())) {
+ ClassTemplate->getInjectedClassNameSpecialization()) &&
+ (!Context.getLangOpts().ConceptsTS ||
+ !TemplateParams->hasAssociatedConstraints())) {
// C++ [temp.class.spec]p9b3:
//
// -- The argument list of the specialization shall not be identical
@@ -9040,7 +9244,8 @@ DeclResult Sema::ActOnExplicitInstantiation(
// template.
SmallVector<TemplateArgument, 4> Converted;
if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc,
- TemplateArgs, false, Converted))
+ TemplateArgs, false, Converted,
+ /*UpdateArgsWithConversion=*/true))
return true;
// Find the class template specialization declaration that
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 64ef819e30d4..1b9f1b2144d1 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -24,6 +24,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/NestedNameSpecifier.h"
+#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/TemplateBase.h"
#include "clang/AST/TemplateName.h"
#include "clang/AST/Type.h"
@@ -642,6 +643,10 @@ static TemplateParameter makeTemplateParameter(Decl *D) {
/// If \p Param is an expanded parameter pack, get the number of expansions.
static Optional<unsigned> getExpandedPackSize(NamedDecl *Param) {
+ if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
+ if (TTP->isExpandedParameterPack())
+ return TTP->getNumExpansionParameters();
+
if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param))
if (NTTP->isExpandedParameterPack())
return NTTP->getNumExpansionTypes();
@@ -859,34 +864,31 @@ public:
/// Finish template argument deduction for a set of argument packs,
/// producing the argument packs and checking for consistency with prior
/// deductions.
- Sema::TemplateDeductionResult
- finish(bool TreatNoDeductionsAsNonDeduced = true) {
+ Sema::TemplateDeductionResult finish() {
// Build argument packs for each of the parameter packs expanded by this
// pack expansion.
for (auto &Pack : Packs) {
// Put back the old value for this pack.
Deduced[Pack.Index] = Pack.Saved;
- // If we are deducing the size of this pack even if we didn't deduce any
- // values for it, then make sure we build a pack of the right size.
- // FIXME: Should we always deduce the size, even if the pack appears in
- // a non-deduced context?
- if (!TreatNoDeductionsAsNonDeduced)
- Pack.New.resize(PackElements);
+ // Always make sure the size of this pack is correct, even if we didn't
+ // deduce any values for it.
+ //
+ // FIXME: This isn't required by the normative wording, but substitution
+ // and post-substitution checking will always fail if the arity of any
+ // pack is not equal to the number of elements we processed. (Either that
+ // or something else has gone *very* wrong.) We're permitted to skip any
+ // hard errors from those follow-on steps by the intent (but not the
+ // wording) of C++ [temp.inst]p8:
+ //
+ // If the function selected by overload resolution can be determined
+ // without instantiating a class template definition, it is unspecified
+ // whether that instantiation actually takes place
+ Pack.New.resize(PackElements);
// Build or find a new value for this pack.
DeducedTemplateArgument NewPack;
- if (PackElements && Pack.New.empty()) {
- if (Pack.DeferredDeduction.isNull()) {
- // We were not able to deduce anything for this parameter pack
- // (because it only appeared in non-deduced contexts), so just
- // restore the saved argument pack.
- continue;
- }
-
- NewPack = Pack.DeferredDeduction;
- Pack.DeferredDeduction = TemplateArgument();
- } else if (Pack.New.empty()) {
+ if (Pack.New.empty()) {
// If we deduced an empty argument pack, create it now.
NewPack = DeducedTemplateArgument(TemplateArgument::getEmptyPack());
} else {
@@ -2501,6 +2503,30 @@ Sema::getTrivialTemplateArgumentLoc(const TemplateArgument &Arg,
llvm_unreachable("Invalid TemplateArgument Kind!");
}
+TemplateArgumentLoc
+Sema::getIdentityTemplateArgumentLoc(Decl *TemplateParm,
+ SourceLocation Location) {
+ if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(TemplateParm))
+ return getTrivialTemplateArgumentLoc(
+ TemplateArgument(
+ Context.getTemplateTypeParmType(TTP->getDepth(), TTP->getIndex(),
+ TTP->isParameterPack(), TTP)),
+ QualType(), Location.isValid() ? Location : TTP->getLocation());
+ else if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(TemplateParm))
+ return getTrivialTemplateArgumentLoc(TemplateArgument(TemplateName(TTP)),
+ QualType(),
+ Location.isValid() ? Location :
+ TTP->getLocation());
+ auto *NTTP = cast<NonTypeTemplateParmDecl>(TemplateParm);
+ CXXScopeSpec SS;
+ DeclarationNameInfo Info(NTTP->getDeclName(),
+ Location.isValid() ? Location : NTTP->getLocation());
+ Expr *E = BuildDeclarationNameExpr(SS, Info, NTTP).get();
+ return getTrivialTemplateArgumentLoc(TemplateArgument(E), NTTP->getType(),
+ Location.isValid() ? Location :
+ NTTP->getLocation());
+}
+
/// Convert the given deduced template argument and add it to the set of
/// fully-converted template arguments.
static bool
@@ -2611,8 +2637,8 @@ static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments(
// be deduced to an empty sequence of template arguments.
// FIXME: Where did the word "trailing" come from?
if (Deduced[I].isNull() && Param->isTemplateParameterPack()) {
- if (auto Result = PackDeductionScope(S, TemplateParams, Deduced, Info, I)
- .finish(/*TreatNoDeductionsAsNonDeduced*/false))
+ if (auto Result =
+ PackDeductionScope(S, TemplateParams, Deduced, Info, I).finish())
return Result;
}
@@ -2709,6 +2735,23 @@ struct IsPartialSpecialization<VarTemplatePartialSpecializationDecl> {
static constexpr bool value = true;
};
+template<typename TemplateDeclT>
+static Sema::TemplateDeductionResult
+CheckDeducedArgumentConstraints(Sema& S, TemplateDeclT *Template,
+ ArrayRef<TemplateArgument> DeducedArgs,
+ TemplateDeductionInfo& Info) {
+ llvm::SmallVector<const Expr *, 3> AssociatedConstraints;
+ Template->getAssociatedConstraints(AssociatedConstraints);
+ if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints,
+ DeducedArgs, Info.getLocation(),
+ Info.AssociatedConstraintsSatisfaction) ||
+ !Info.AssociatedConstraintsSatisfaction.IsSatisfied) {
+ Info.reset(TemplateArgumentList::CreateCopy(S.Context, DeducedArgs));
+ return Sema::TDK_ConstraintsNotSatisfied;
+ }
+ return Sema::TDK_Success;
+}
+
/// Complete template argument deduction for a partial specialization.
template <typename T>
static typename std::enable_if<IsPartialSpecialization<T>::value,
@@ -2767,10 +2810,14 @@ FinishTemplateArgumentDeduction(
return Sema::TDK_SubstitutionFailure;
}
+ bool ConstraintsNotSatisfied;
SmallVector<TemplateArgument, 4> ConvertedInstArgs;
if (S.CheckTemplateArgumentList(Template, Partial->getLocation(), InstArgs,
- false, ConvertedInstArgs))
- return Sema::TDK_SubstitutionFailure;
+ false, ConvertedInstArgs,
+ /*UpdateArgsWithConversions=*/true,
+ &ConstraintsNotSatisfied))
+ return ConstraintsNotSatisfied ? Sema::TDK_ConstraintsNotSatisfied :
+ Sema::TDK_SubstitutionFailure;
TemplateParameterList *TemplateParams = Template->getTemplateParameters();
for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) {
@@ -2786,6 +2833,9 @@ FinishTemplateArgumentDeduction(
if (Trap.hasErrorOccurred())
return Sema::TDK_SubstitutionFailure;
+ if (auto Result = CheckDeducedArgumentConstraints(S, Partial, Builder, Info))
+ return Result;
+
return Sema::TDK_Success;
}
@@ -2828,10 +2878,13 @@ static Sema::TemplateDeductionResult FinishTemplateArgumentDeduction(
if (Trap.hasErrorOccurred())
return Sema::TDK_SubstitutionFailure;
+ if (auto Result = CheckDeducedArgumentConstraints(S, Template, Builder,
+ Info))
+ return Result;
+
return Sema::TDK_Success;
}
-
/// Perform template argument deduction to determine whether
/// the given template arguments match the given class template
/// partial specialization per C++ [temp.class.spec.match].
@@ -3385,6 +3438,23 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
return TDK_SubstitutionFailure;
}
+ // C++2a [temp.deduct]p5
+ // [...] When all template arguments have been deduced [...] all uses of
+ // template parameters [...] are replaced with the corresponding deduced
+ // or default argument values.
+ // [...] If the function template has associated constraints
+ // ([temp.constr.decl]), those constraints are checked for satisfaction
+ // ([temp.constr.constr]). If the constraints are not satisfied, type
+ // deduction fails.
+ if (CheckInstantiatedFunctionTemplateConstraints(Info.getLocation(),
+ Specialization, Builder, Info.AssociatedConstraintsSatisfaction))
+ return TDK_MiscellaneousDeductionFailure;
+
+ if (!Info.AssociatedConstraintsSatisfaction.IsSatisfied) {
+ Info.reset(TemplateArgumentList::CreateCopy(Context, Builder));
+ return TDK_ConstraintsNotSatisfied;
+ }
+
if (OriginalCallArgs) {
// C++ [temp.deduct.call]p4:
// In general, the deduction process attempts to find template argument
@@ -3505,7 +3575,7 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams,
DeclAccessPair DAP;
if (FunctionDecl *Viable =
- S.resolveAddressOfOnlyViableOverloadCandidate(Arg, DAP))
+ S.resolveAddressOfSingleOverloadCandidate(Arg, DAP))
return GetTypeOfFunction(S, R, Viable);
return {};
@@ -4429,7 +4499,8 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
/*.IsPack = */ (bool)Type.getAs<PackExpansionTypeLoc>()};
if (!DependentDeductionDepth &&
- (Type.getType()->isDependentType() || Init->isTypeDependent())) {
+ (Type.getType()->isDependentType() || Init->isTypeDependent() ||
+ Init->containsUnexpandedParameterPack())) {
Result = SubstituteDeducedTypeTransform(*this, DependentResult).Apply(Type);
assert(!Result.isNull() && "substituting DependentTy can't fail");
return DAR_Succeeded;
@@ -4475,11 +4546,12 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
// Build template<class TemplParam> void Func(FuncParam);
TemplateTypeParmDecl *TemplParam = TemplateTypeParmDecl::Create(
- Context, nullptr, SourceLocation(), Loc, Depth, 0, nullptr, false, false);
+ Context, nullptr, SourceLocation(), Loc, Depth, 0, nullptr, false, false,
+ false);
QualType TemplArg = QualType(TemplParam->getTypeForDecl(), 0);
NamedDecl *TemplParamPtr = TemplParam;
FixedSizeTemplateParameterListStorage<1, false> TemplateParamsSt(
- Loc, Loc, TemplParamPtr, Loc, nullptr);
+ Context, Loc, Loc, TemplParamPtr, Loc, nullptr);
QualType FuncParam =
SubstituteDeducedTypeTransform(*this, TemplArg, /*UseTypeSugar*/false)
@@ -4905,6 +4977,21 @@ Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
TemplatePartialOrderingContext TPOC,
unsigned NumCallArguments1,
unsigned NumCallArguments2) {
+
+ auto JudgeByConstraints = [&] () -> FunctionTemplateDecl * {
+ llvm::SmallVector<const Expr *, 3> AC1, AC2;
+ FT1->getAssociatedConstraints(AC1);
+ FT2->getAssociatedConstraints(AC2);
+ bool AtLeastAsConstrained1, AtLeastAsConstrained2;
+ if (IsAtLeastAsConstrained(FT1, AC1, FT2, AC2, AtLeastAsConstrained1))
+ return nullptr;
+ if (IsAtLeastAsConstrained(FT2, AC2, FT1, AC1, AtLeastAsConstrained2))
+ return nullptr;
+ if (AtLeastAsConstrained1 == AtLeastAsConstrained2)
+ return nullptr;
+ return AtLeastAsConstrained1 ? FT1 : FT2;
+ };
+
bool Better1 = isAtLeastAsSpecializedAs(*this, Loc, FT1, FT2, TPOC,
NumCallArguments1);
bool Better2 = isAtLeastAsSpecializedAs(*this, Loc, FT2, FT1, TPOC,
@@ -4914,7 +5001,7 @@ Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
return Better1 ? FT1 : FT2;
if (!Better1 && !Better2) // Neither is better than the other
- return nullptr;
+ return JudgeByConstraints();
// FIXME: This mimics what GCC implements, but doesn't match up with the
// proposed resolution for core issue 692. This area needs to be sorted out,
@@ -4924,7 +5011,7 @@ Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
if (Variadic1 != Variadic2)
return Variadic1? FT2 : FT1;
- return nullptr;
+ return JudgeByConstraints();
}
/// Determine if the two templates are equivalent.
@@ -5119,8 +5206,21 @@ Sema::getMoreSpecializedPartialSpecialization(
bool Better1 = isAtLeastAsSpecializedAs(*this, PT1, PT2, PS2, Info);
bool Better2 = isAtLeastAsSpecializedAs(*this, PT2, PT1, PS1, Info);
- if (Better1 == Better2)
- return nullptr;
+ if (!Better1 && !Better2)
+ return nullptr;
+ if (Better1 && Better2) {
+ llvm::SmallVector<const Expr *, 3> AC1, AC2;
+ PS1->getAssociatedConstraints(AC1);
+ PS2->getAssociatedConstraints(AC2);
+ bool AtLeastAsConstrained1, AtLeastAsConstrained2;
+ if (IsAtLeastAsConstrained(PS1, AC1, PS2, AC2, AtLeastAsConstrained1))
+ return nullptr;
+ if (IsAtLeastAsConstrained(PS2, AC2, PS1, AC1, AtLeastAsConstrained2))
+ return nullptr;
+ if (AtLeastAsConstrained1 == AtLeastAsConstrained2)
+ return nullptr;
+ return AtLeastAsConstrained1 ? PS1 : PS2;
+ }
return Better1 ? PS1 : PS2;
}
@@ -5132,11 +5232,22 @@ bool Sema::isMoreSpecializedThanPrimary(
QualType PartialT = Spec->getInjectedSpecializationType();
if (!isAtLeastAsSpecializedAs(*this, PartialT, PrimaryT, Primary, Info))
return false;
- if (isAtLeastAsSpecializedAs(*this, PrimaryT, PartialT, Spec, Info)) {
- Info.clearSFINAEDiagnostic();
+ if (!isAtLeastAsSpecializedAs(*this, PrimaryT, PartialT, Spec, Info))
+ return true;
+ Info.clearSFINAEDiagnostic();
+ llvm::SmallVector<const Expr *, 3> PrimaryAC, SpecAC;
+ Primary->getAssociatedConstraints(PrimaryAC);
+ Spec->getAssociatedConstraints(SpecAC);
+ bool AtLeastAsConstrainedPrimary, AtLeastAsConstrainedSpec;
+ if (IsAtLeastAsConstrained(Spec, SpecAC, Primary, PrimaryAC,
+ AtLeastAsConstrainedSpec))
return false;
- }
- return true;
+ if (!AtLeastAsConstrainedSpec)
+ return false;
+ if (IsAtLeastAsConstrained(Primary, PrimaryAC, Spec, SpecAC,
+ AtLeastAsConstrainedPrimary))
+ return false;
+ return !AtLeastAsConstrainedPrimary;
}
VarTemplatePartialSpecializationDecl *
@@ -5159,8 +5270,21 @@ Sema::getMoreSpecializedPartialSpecialization(
bool Better1 = isAtLeastAsSpecializedAs(*this, PT1, PT2, PS2, Info);
bool Better2 = isAtLeastAsSpecializedAs(*this, PT2, PT1, PS1, Info);
- if (Better1 == Better2)
+ if (!Better1 && !Better2)
return nullptr;
+ if (Better1 && Better2) {
+ llvm::SmallVector<const Expr *, 3> AC1, AC2;
+ PS1->getAssociatedConstraints(AC1);
+ PS2->getAssociatedConstraints(AC2);
+ bool AtLeastAsConstrained1, AtLeastAsConstrained2;
+ if (IsAtLeastAsConstrained(PS1, AC1, PS2, AC2, AtLeastAsConstrained1))
+ return nullptr;
+ if (IsAtLeastAsConstrained(PS2, AC2, PS1, AC1, AtLeastAsConstrained2))
+ return nullptr;
+ if (AtLeastAsConstrained1 == AtLeastAsConstrained2)
+ return nullptr;
+ return AtLeastAsConstrained1 ? PS1 : PS2;
+ }
return Better1 ? PS1 : PS2;
}
@@ -5180,13 +5304,25 @@ bool Sema::isMoreSpecializedThanPrimary(
CanonTemplate, PrimaryArgs);
QualType PartialT = Context.getTemplateSpecializationType(
CanonTemplate, Spec->getTemplateArgs().asArray());
+
if (!isAtLeastAsSpecializedAs(*this, PartialT, PrimaryT, Primary, Info))
return false;
- if (isAtLeastAsSpecializedAs(*this, PrimaryT, PartialT, Spec, Info)) {
- Info.clearSFINAEDiagnostic();
+ if (!isAtLeastAsSpecializedAs(*this, PrimaryT, PartialT, Spec, Info))
+ return true;
+ Info.clearSFINAEDiagnostic();
+ llvm::SmallVector<const Expr *, 3> PrimaryAC, SpecAC;
+ Primary->getAssociatedConstraints(PrimaryAC);
+ Spec->getAssociatedConstraints(SpecAC);
+ bool AtLeastAsConstrainedPrimary, AtLeastAsConstrainedSpec;
+ if (IsAtLeastAsConstrained(Spec, SpecAC, Primary, PrimaryAC,
+ AtLeastAsConstrainedSpec))
return false;
- }
- return true;
+ if (!AtLeastAsConstrainedSpec)
+ return false;
+ if (IsAtLeastAsConstrained(Primary, PrimaryAC, Spec, SpecAC,
+ AtLeastAsConstrainedPrimary))
+ return false;
+ return !AtLeastAsConstrainedPrimary;
}
bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs(
@@ -5220,7 +5356,8 @@ bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs(
SFINAETrap Trap(*this);
Context.getInjectedTemplateArgs(P, PArgs);
- TemplateArgumentListInfo PArgList(P->getLAngleLoc(), P->getRAngleLoc());
+ TemplateArgumentListInfo PArgList(P->getLAngleLoc(),
+ P->getRAngleLoc());
for (unsigned I = 0, N = P->size(); I != N; ++I) {
// Unwrap packs that getInjectedTemplateArgs wrapped around pack
// expansions, to form an "as written" argument list.
@@ -5252,6 +5389,41 @@ bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs(
return isAtLeastAsSpecializedAs(*this, PType, AType, AArg, Info);
}
+namespace {
+struct MarkUsedTemplateParameterVisitor :
+ RecursiveASTVisitor<MarkUsedTemplateParameterVisitor> {
+ llvm::SmallBitVector &Used;
+ unsigned Depth;
+
+ MarkUsedTemplateParameterVisitor(llvm::SmallBitVector &Used,
+ unsigned Depth)
+ : Used(Used), Depth(Depth) { }
+
+ bool VisitTemplateTypeParmType(TemplateTypeParmType *T) {
+ if (T->getDepth() == Depth)
+ Used[T->getIndex()] = true;
+ return true;
+ }
+
+ bool TraverseTemplateName(TemplateName Template) {
+ if (auto *TTP =
+ dyn_cast<TemplateTemplateParmDecl>(Template.getAsTemplateDecl()))
+ if (TTP->getDepth() == Depth)
+ Used[TTP->getIndex()] = true;
+ RecursiveASTVisitor<MarkUsedTemplateParameterVisitor>::
+ TraverseTemplateName(Template);
+ return true;
+ }
+
+ bool VisitDeclRefExpr(DeclRefExpr *E) {
+ if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(E->getDecl()))
+ if (NTTP->getDepth() == Depth)
+ Used[NTTP->getIndex()] = true;
+ return true;
+ }
+};
+}
+
/// Mark the template parameters that are used by the given
/// expression.
static void
@@ -5260,6 +5432,12 @@ MarkUsedTemplateParameters(ASTContext &Ctx,
bool OnlyDeduced,
unsigned Depth,
llvm::SmallBitVector &Used) {
+ if (!OnlyDeduced) {
+ MarkUsedTemplateParameterVisitor(Used, Depth)
+ .TraverseStmt(const_cast<Expr *>(E));
+ return;
+ }
+
// We can deduce from a pack expansion.
if (const PackExpansionExpr *Expansion = dyn_cast<PackExpansionExpr>(E))
E = Expansion->getPattern();
@@ -5278,8 +5456,6 @@ MarkUsedTemplateParameters(ASTContext &Ctx,
break;
}
- // FIXME: if !OnlyDeduced, we have to walk the whole subexpression to
- // find other occurrences of template parameters.
const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E);
if (!DRE)
return;
@@ -5659,6 +5835,20 @@ MarkUsedTemplateParameters(ASTContext &Ctx,
}
}
+/// Mark which template parameters are used in a given expression.
+///
+/// \param E the expression from which template parameters will be deduced.
+///
+/// \param Used a bit vector whose elements will be set to \c true
+/// to indicate when the corresponding template parameter will be
+/// deduced.
+void
+Sema::MarkUsedTemplateParameters(const Expr *E, bool OnlyDeduced,
+ unsigned Depth,
+ llvm::SmallBitVector &Used) {
+ ::MarkUsedTemplateParameters(Context, E, OnlyDeduced, Depth, Used);
+}
+
/// Mark which template parameters can be deduced from a given
/// template argument list.
///
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 0daa33cfbef5..af41e231134d 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -150,7 +150,7 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D,
break;
// If this function is a generic lambda specialization, we are done.
- if (isGenericLambdaCallOperatorSpecialization(Function))
+ if (isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function))
break;
} else if (FunctionTemplateDecl *FunTmpl
@@ -203,9 +203,12 @@ bool Sema::CodeSynthesisContext::isInstantiationRecord() const {
case DefaultTemplateArgumentChecking:
case DeclaringSpecialMember:
+ case DeclaringImplicitEqualityComparison:
case DefiningSynthesizedFunction:
case ExceptionSpecEvaluation:
case ConstraintSubstitution:
+ case ParameterMappingSubstitution:
+ case ConstraintNormalization:
case RewritingOperatorAsSpaceship:
return false;
@@ -363,7 +366,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
Sema::InstantiatingTemplate::InstantiatingTemplate(
Sema &SemaRef, SourceLocation PointOfInstantiation,
- ConstraintsCheck, TemplateDecl *Template,
+ ConstraintsCheck, NamedDecl *Template,
ArrayRef<TemplateArgument> TemplateArgs, SourceRange InstantiationRange)
: InstantiatingTemplate(
SemaRef, CodeSynthesisContext::ConstraintsCheck,
@@ -372,13 +375,29 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
Sema::InstantiatingTemplate::InstantiatingTemplate(
Sema &SemaRef, SourceLocation PointOfInstantiation,
- ConstraintSubstitution, TemplateDecl *Template,
+ ConstraintSubstitution, NamedDecl *Template,
sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange)
: InstantiatingTemplate(
SemaRef, CodeSynthesisContext::ConstraintSubstitution,
PointOfInstantiation, InstantiationRange, Template, nullptr,
{}, &DeductionInfo) {}
+Sema::InstantiatingTemplate::InstantiatingTemplate(
+ Sema &SemaRef, SourceLocation PointOfInstantiation,
+ ConstraintNormalization, NamedDecl *Template,
+ SourceRange InstantiationRange)
+ : InstantiatingTemplate(
+ SemaRef, CodeSynthesisContext::ConstraintNormalization,
+ PointOfInstantiation, InstantiationRange, Template) {}
+
+Sema::InstantiatingTemplate::InstantiatingTemplate(
+ Sema &SemaRef, SourceLocation PointOfInstantiation,
+ ParameterMappingSubstitution, NamedDecl *Template,
+ SourceRange InstantiationRange)
+ : InstantiatingTemplate(
+ SemaRef, CodeSynthesisContext::ParameterMappingSubstitution,
+ PointOfInstantiation, InstantiationRange, Template) {}
+
void Sema::pushCodeSynthesisContext(CodeSynthesisContext Ctx) {
Ctx.SavedInNonInstantiationSFINAEContext = InNonInstantiationSFINAEContext;
InNonInstantiationSFINAEContext = false;
@@ -671,14 +690,29 @@ void Sema::PrintInstantiationStack() {
<< cast<CXXRecordDecl>(Active->Entity) << Active->SpecialMember;
break;
+ case CodeSynthesisContext::DeclaringImplicitEqualityComparison:
+ Diags.Report(Active->Entity->getLocation(),
+ diag::note_in_declaration_of_implicit_equality_comparison);
+ break;
+
case CodeSynthesisContext::DefiningSynthesizedFunction: {
- // FIXME: For synthesized members other than special members, produce a note.
- auto *MD = dyn_cast<CXXMethodDecl>(Active->Entity);
- auto CSM = MD ? getSpecialMember(MD) : CXXInvalid;
- if (CSM != CXXInvalid) {
+ // FIXME: For synthesized functions that are not defaulted,
+ // produce a note.
+ auto *FD = dyn_cast<FunctionDecl>(Active->Entity);
+ DefaultedFunctionKind DFK =
+ FD ? getDefaultedFunctionKind(FD) : DefaultedFunctionKind();
+ if (DFK.isSpecialMember()) {
+ auto *MD = cast<CXXMethodDecl>(FD);
Diags.Report(Active->PointOfInstantiation,
diag::note_member_synthesized_at)
- << CSM << Context.getTagDeclType(MD->getParent());
+ << MD->isExplicitlyDefaulted() << DFK.asSpecialMember()
+ << Context.getTagDeclType(MD->getParent());
+ } else if (DFK.isComparison()) {
+ Diags.Report(Active->PointOfInstantiation,
+ diag::note_comparison_synthesized_at)
+ << (int)DFK.asComparison()
+ << Context.getTagDeclType(
+ cast<CXXRecordDecl>(FD->getLexicalDeclContext()));
}
break;
}
@@ -691,29 +725,43 @@ void Sema::PrintInstantiationStack() {
case CodeSynthesisContext::Memoization:
break;
- case CodeSynthesisContext::ConstraintsCheck:
- if (auto *CD = dyn_cast<ConceptDecl>(Active->Entity)) {
- SmallVector<char, 128> TemplateArgsStr;
- llvm::raw_svector_ostream OS(TemplateArgsStr);
- CD->printName(OS);
- printTemplateArgumentList(OS, Active->template_arguments(),
- getPrintingPolicy());
- Diags.Report(Active->PointOfInstantiation,
- diag::note_concept_specialization_here)
- << OS.str()
- << Active->InstantiationRange;
- break;
+ case CodeSynthesisContext::ConstraintsCheck: {
+ unsigned DiagID = 0;
+ if (isa<ConceptDecl>(Active->Entity))
+ DiagID = diag::note_concept_specialization_here;
+ else if (isa<TemplateDecl>(Active->Entity))
+ DiagID = diag::note_checking_constraints_for_template_id_here;
+ else if (isa<VarTemplatePartialSpecializationDecl>(Active->Entity))
+ DiagID = diag::note_checking_constraints_for_var_spec_id_here;
+ else {
+ assert(isa<ClassTemplatePartialSpecializationDecl>(Active->Entity));
+ DiagID = diag::note_checking_constraints_for_class_spec_id_here;
}
- // TODO: Concepts - implement this for constrained templates and partial
- // specializations.
- llvm_unreachable("only concept constraints are supported right now");
+ SmallVector<char, 128> TemplateArgsStr;
+ llvm::raw_svector_ostream OS(TemplateArgsStr);
+ cast<NamedDecl>(Active->Entity)->printName(OS);
+ printTemplateArgumentList(OS, Active->template_arguments(),
+ getPrintingPolicy());
+ Diags.Report(Active->PointOfInstantiation, DiagID) << OS.str()
+ << Active->InstantiationRange;
break;
-
+ }
case CodeSynthesisContext::ConstraintSubstitution:
Diags.Report(Active->PointOfInstantiation,
diag::note_constraint_substitution_here)
<< Active->InstantiationRange;
break;
+ case CodeSynthesisContext::ConstraintNormalization:
+ Diags.Report(Active->PointOfInstantiation,
+ diag::note_constraint_normalization_here)
+ << cast<NamedDecl>(Active->Entity)->getName()
+ << Active->InstantiationRange;
+ break;
+ case CodeSynthesisContext::ParameterMappingSubstitution:
+ Diags.Report(Active->PointOfInstantiation,
+ diag::note_parameter_mapping_substitution_here)
+ << Active->InstantiationRange;
+ break;
}
}
}
@@ -738,6 +786,8 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
case CodeSynthesisContext::DefaultFunctionArgumentInstantiation:
case CodeSynthesisContext::ExceptionSpecInstantiation:
case CodeSynthesisContext::ConstraintsCheck:
+ case CodeSynthesisContext::ParameterMappingSubstitution:
+ case CodeSynthesisContext::ConstraintNormalization:
// This is a template instantiation, so there is no SFINAE.
return None;
@@ -759,6 +809,7 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
return Active->DeductionInfo;
case CodeSynthesisContext::DeclaringSpecialMember:
+ case CodeSynthesisContext::DeclaringImplicitEqualityComparison:
case CodeSynthesisContext::DefiningSynthesizedFunction:
case CodeSynthesisContext::RewritingOperatorAsSpaceship:
// This happens in a context unrelated to template instantiation, so
@@ -1514,8 +1565,12 @@ TemplateInstantiator::TransformFunctionTypeParam(ParmVarDecl *OldParm,
int indexAdjustment,
Optional<unsigned> NumExpansions,
bool ExpectParameterPack) {
- return SemaRef.SubstParmVarDecl(OldParm, TemplateArgs, indexAdjustment,
- NumExpansions, ExpectParameterPack);
+ auto NewParm =
+ SemaRef.SubstParmVarDecl(OldParm, TemplateArgs, indexAdjustment,
+ NumExpansions, ExpectParameterPack);
+ if (NewParm && SemaRef.getLangOpts().OpenCL)
+ SemaRef.deduceOpenCLAddressSpace(NewParm);
+ return NewParm;
}
QualType
@@ -2219,11 +2274,13 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
// Finish checking fields.
ActOnFields(nullptr, Instantiation->getLocation(), Instantiation, Fields,
SourceLocation(), SourceLocation(), ParsedAttributesView());
- CheckCompletedCXXClass(Instantiation);
+ CheckCompletedCXXClass(nullptr, Instantiation);
// Default arguments are parsed, if not instantiated. We can go instantiate
- // default arg exprs for default constructors if necessary now.
- ActOnFinishCXXNonNestedClass(Instantiation);
+ // default arg exprs for default constructors if necessary now. Unless we're
+ // parsing a class, in which case wait until that's finished.
+ if (ParsingClassDepth == 0)
+ ActOnFinishCXXNonNestedClass();
// Instantiate late parsed attributes, and attach them to their decls.
// See Sema::InstantiateAttrs
@@ -2900,6 +2957,17 @@ Sema::SubstStmt(Stmt *S, const MultiLevelTemplateArgumentList &TemplateArgs) {
return Instantiator.TransformStmt(S);
}
+bool Sema::SubstTemplateArguments(
+ ArrayRef<TemplateArgumentLoc> Args,
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ TemplateArgumentListInfo &Out) {
+ TemplateInstantiator Instantiator(*this, TemplateArgs,
+ SourceLocation(),
+ DeclarationName());
+ return Instantiator.TransformTemplateArguments(Args.begin(), Args.end(),
+ Out);
+}
+
ExprResult
Sema::SubstExpr(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs) {
if (!E)
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index d1ad304e62e4..64500d0a26d5 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -385,12 +385,13 @@ static void instantiateOMPDeclareVariantAttr(
};
ExprResult VariantFuncRef;
- if (Expr *E = Attr.getVariantFuncRef())
+ if (Expr *E = Attr.getVariantFuncRef()) {
+ // Do not mark function as is used to prevent its emission if this is the
+ // only place where it is used.
+ EnterExpressionEvaluationContext Unevaluated(
+ S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
VariantFuncRef = Subst(E);
-
- ExprResult Score;
- if (Expr *E = Attr.getScore())
- Score = Subst(E);
+ }
// Check function/variant ref.
Optional<std::pair<FunctionDecl *, Expr *>> DeclVarData =
@@ -398,12 +399,41 @@ static void instantiateOMPDeclareVariantAttr(
S.ConvertDeclToDeclGroup(New), VariantFuncRef.get(), Attr.getRange());
if (!DeclVarData)
return;
- // Instantiate the attribute.
- Sema::OpenMPDeclareVariantCtsSelectorData Data(
- Attr.getCtxSelectorSet(), Attr.getCtxSelector(),
- llvm::makeMutableArrayRef(Attr.implVendors_begin(),
- Attr.implVendors_size()),
- Score);
+ SmallVector<Sema::OMPCtxSelectorData, 4> Data;
+ for (unsigned I = 0, E = Attr.scores_size(); I < E; ++I) {
+ ExprResult Score;
+ if (Expr *E = *std::next(Attr.scores_begin(), I))
+ Score = Subst(E);
+ // Instantiate the attribute.
+ auto CtxSet = static_cast<OpenMPContextSelectorSetKind>(
+ *std::next(Attr.ctxSelectorSets_begin(), I));
+ auto Ctx = static_cast<OpenMPContextSelectorKind>(
+ *std::next(Attr.ctxSelectors_begin(), I));
+ switch (CtxSet) {
+ case OMP_CTX_SET_implementation:
+ switch (Ctx) {
+ case OMP_CTX_vendor:
+ Data.emplace_back(CtxSet, Ctx, Score, Attr.implVendors());
+ break;
+ case OMP_CTX_kind:
+ case OMP_CTX_unknown:
+ llvm_unreachable("Unexpected context selector kind.");
+ }
+ break;
+ case OMP_CTX_SET_device:
+ switch (Ctx) {
+ case OMP_CTX_kind:
+ Data.emplace_back(CtxSet, Ctx, Score, Attr.deviceKinds());
+ break;
+ case OMP_CTX_vendor:
+ case OMP_CTX_unknown:
+ llvm_unreachable("Unexpected context selector kind.");
+ }
+ break;
+ case OMP_CTX_SET_unknown:
+ llvm_unreachable("Unexpected context selector set kind.");
+ }
+ }
S.ActOnOpenMPDeclareVariantDirective(DeclVarData.getValue().first,
DeclVarData.getValue().second,
Attr.getRange(), Data);
@@ -625,11 +655,10 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
LateAttrs->push_back(LateInstantiatedAttribute(TmplAttr, Saved, New));
} else {
// Allow 'this' within late-parsed attributes.
- NamedDecl *ND = dyn_cast<NamedDecl>(New);
- CXXRecordDecl *ThisContext =
- dyn_cast_or_null<CXXRecordDecl>(ND->getDeclContext());
+ auto *ND = cast<NamedDecl>(New);
+ auto *ThisContext = dyn_cast_or_null<CXXRecordDecl>(ND->getDeclContext());
CXXThisScopeRAII ThisScope(*this, ThisContext, Qualifiers(),
- ND && ND->isCXXInstanceMember());
+ ND->isCXXInstanceMember());
Attr *NewAttr = sema::instantiateTemplateAttribute(TmplAttr, Context,
*this, TemplateArgs);
@@ -905,6 +934,9 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D,
SemaRef.inferObjCARCLifetime(Var))
Var->setInvalidDecl();
+ if (SemaRef.getLangOpts().OpenCL)
+ SemaRef.deduceOpenCLAddressSpace(Var);
+
// Substitute the nested name specifier, if any.
if (SubstQualifier(D, Var))
return nullptr;
@@ -1761,8 +1793,9 @@ static QualType adjustFunctionTypeForInstantiation(ASTContext &Context,
/// 1) instantiating function templates
/// 2) substituting friend declarations
/// 3) substituting deduction guide declarations for nested class templates
-Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
- TemplateParameterList *TemplateParams) {
+Decl *TemplateDeclInstantiator::VisitFunctionDecl(
+ FunctionDecl *D, TemplateParameterList *TemplateParams,
+ RewriteKind FunctionRewriteKind) {
// Check whether there is already a function template specialization for
// this declaration.
FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate();
@@ -1812,6 +1845,18 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
return nullptr;
}
+ // FIXME: Concepts: Do not substitute into constraint expressions
+ Expr *TrailingRequiresClause = D->getTrailingRequiresClause();
+ if (TrailingRequiresClause) {
+ ExprResult SubstRC = SemaRef.SubstExpr(TrailingRequiresClause,
+ TemplateArgs);
+ if (SubstRC.isInvalid())
+ return nullptr;
+ TrailingRequiresClause = SubstRC.get();
+ if (!SemaRef.CheckConstraintExpression(TrailingRequiresClause))
+ return nullptr;
+ }
+
// If we're instantiating a local function declaration, put the result
// in the enclosing namespace; otherwise we need to find the instantiated
// context.
@@ -1832,6 +1877,9 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
DeclarationNameInfo NameInfo
= SemaRef.SubstDeclarationNameInfo(D->getNameInfo(), TemplateArgs);
+ if (FunctionRewriteKind != RewriteKind::None)
+ adjustForRewrite(FunctionRewriteKind, D, T, TInfo, NameInfo);
+
FunctionDecl *Function;
if (auto *DGuide = dyn_cast<CXXDeductionGuideDecl>(D)) {
Function = CXXDeductionGuideDecl::Create(
@@ -1845,7 +1893,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
Function = FunctionDecl::Create(
SemaRef.Context, DC, D->getInnerLocStart(), NameInfo, T, TInfo,
D->getCanonicalDecl()->getStorageClass(), D->isInlineSpecified(),
- D->hasWrittenPrototype(), D->getConstexprKind());
+ D->hasWrittenPrototype(), D->getConstexprKind(),
+ TrailingRequiresClause);
Function->setRangeEnd(D->getSourceRange().getEnd());
}
@@ -1872,6 +1921,9 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
Params[P]->setOwningFunction(Function);
Function->setParams(Params);
+ if (TrailingRequiresClause)
+ Function->setTrailingRequiresClause(TrailingRequiresClause);
+
if (TemplateParams) {
// Our resulting instantiation is actually a function template, since we
// are substituting only the outer template parameters. For example, given
@@ -2049,6 +2101,13 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
}
}
+ if (D->isExplicitlyDefaulted()) {
+ if (SubstDefaultedFunction(Function, D))
+ return nullptr;
+ }
+ if (D->isDeleted())
+ SemaRef.SetDeclDeleted(Function, D->getLocation());
+
if (Function->isLocalExternDecl() && !Function->getPreviousDecl())
DC->makeDeclVisibleInContext(PrincipalDecl);
@@ -2056,14 +2115,13 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
PrincipalDecl->isInIdentifierNamespace(Decl::IDNS_Ordinary))
PrincipalDecl->setNonMemberOperator();
- assert(!D->isDefaulted() && "only methods should be defaulted");
return Function;
}
Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
CXXMethodDecl *D, TemplateParameterList *TemplateParams,
- Optional<const ASTTemplateArgumentListInfo *>
- ClassScopeSpecializationArgs) {
+ Optional<const ASTTemplateArgumentListInfo *> ClassScopeSpecializationArgs,
+ RewriteKind FunctionRewriteKind) {
FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate();
if (FunctionTemplate && !TemplateParams) {
// We are creating a function template specialization from a function
@@ -2125,6 +2183,18 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
return nullptr;
}
+ // FIXME: Concepts: Do not substitute into constraint expressions
+ Expr *TrailingRequiresClause = D->getTrailingRequiresClause();
+ if (TrailingRequiresClause) {
+ ExprResult SubstRC = SemaRef.SubstExpr(TrailingRequiresClause,
+ TemplateArgs);
+ if (SubstRC.isInvalid())
+ return nullptr;
+ TrailingRequiresClause = SubstRC.get();
+ if (!SemaRef.CheckConstraintExpression(TrailingRequiresClause))
+ return nullptr;
+ }
+
DeclContext *DC = Owner;
if (isFriend) {
if (QualifierLoc) {
@@ -2142,34 +2212,42 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
if (!DC) return nullptr;
}
+ DeclarationNameInfo NameInfo
+ = SemaRef.SubstDeclarationNameInfo(D->getNameInfo(), TemplateArgs);
+
+ if (FunctionRewriteKind != RewriteKind::None)
+ adjustForRewrite(FunctionRewriteKind, D, T, TInfo, NameInfo);
+
// Build the instantiated method declaration.
CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
CXXMethodDecl *Method = nullptr;
SourceLocation StartLoc = D->getInnerLocStart();
- DeclarationNameInfo NameInfo
- = SemaRef.SubstDeclarationNameInfo(D->getNameInfo(), TemplateArgs);
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
Method = CXXConstructorDecl::Create(
SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo,
InstantiatedExplicitSpecifier, Constructor->isInlineSpecified(), false,
- Constructor->getConstexprKind());
+ Constructor->getConstexprKind(), InheritedConstructor(),
+ TrailingRequiresClause);
Method->setRangeEnd(Constructor->getEndLoc());
} else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
Method = CXXDestructorDecl::Create(
SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo,
- Destructor->isInlineSpecified(), false, Destructor->getConstexprKind());
+ Destructor->isInlineSpecified(), false, Destructor->getConstexprKind(),
+ TrailingRequiresClause);
Method->setRangeEnd(Destructor->getEndLoc());
} else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) {
Method = CXXConversionDecl::Create(
SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo,
Conversion->isInlineSpecified(), InstantiatedExplicitSpecifier,
- Conversion->getConstexprKind(), Conversion->getEndLoc());
+ Conversion->getConstexprKind(), Conversion->getEndLoc(),
+ TrailingRequiresClause);
} else {
StorageClass SC = D->isStatic() ? SC_Static : SC_None;
Method = CXXMethodDecl::Create(SemaRef.Context, Record, StartLoc, NameInfo,
T, TInfo, SC, D->isInlineSpecified(),
- D->getConstexprKind(), D->getEndLoc());
+ D->getConstexprKind(), D->getEndLoc(),
+ TrailingRequiresClause);
}
if (D->isInlined())
@@ -2325,8 +2403,10 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
SemaRef.CheckOverrideControl(Method);
// If a function is defined as defaulted or deleted, mark it as such now.
- if (D->isExplicitlyDefaulted())
- SemaRef.SetDeclDefaulted(Method, Method->getLocation());
+ if (D->isExplicitlyDefaulted()) {
+ if (SubstDefaultedFunction(Method, D))
+ return nullptr;
+ }
if (D->isDeletedAsWritten())
SemaRef.SetDeclDeleted(Method, Method->getLocation());
@@ -2399,13 +2479,68 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl(
// TODO: don't always clone when decls are refcounted.
assert(D->getTypeForDecl()->isTemplateTypeParmType());
+ Optional<unsigned> NumExpanded;
+
+ if (const TypeConstraint *TC = D->getTypeConstraint()) {
+ if (D->isPackExpansion() && !D->isExpandedParameterPack()) {
+ assert(TC->getTemplateArgsAsWritten() &&
+ "type parameter can only be an expansion when explicit arguments "
+ "are specified");
+ // The template type parameter pack's type is a pack expansion of types.
+ // Determine whether we need to expand this parameter pack into separate
+ // types.
+ SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+ for (auto &ArgLoc : TC->getTemplateArgsAsWritten()->arguments())
+ SemaRef.collectUnexpandedParameterPacks(ArgLoc, Unexpanded);
+
+ // Determine whether the set of unexpanded parameter packs can and should
+ // be expanded.
+ bool Expand = true;
+ bool RetainExpansion = false;
+ if (SemaRef.CheckParameterPacksForExpansion(
+ cast<CXXFoldExpr>(TC->getImmediatelyDeclaredConstraint())
+ ->getEllipsisLoc(),
+ SourceRange(TC->getConceptNameLoc(),
+ TC->hasExplicitTemplateArgs() ?
+ TC->getTemplateArgsAsWritten()->getRAngleLoc() :
+ TC->getConceptNameInfo().getEndLoc()),
+ Unexpanded, TemplateArgs, Expand, RetainExpansion, NumExpanded))
+ return nullptr;
+ }
+ }
+
TemplateTypeParmDecl *Inst = TemplateTypeParmDecl::Create(
SemaRef.Context, Owner, D->getBeginLoc(), D->getLocation(),
D->getDepth() - TemplateArgs.getNumSubstitutedLevels(), D->getIndex(),
- D->getIdentifier(), D->wasDeclaredWithTypename(), D->isParameterPack());
+ D->getIdentifier(), D->wasDeclaredWithTypename(), D->isParameterPack(),
+ D->hasTypeConstraint(), NumExpanded);
+
Inst->setAccess(AS_public);
Inst->setImplicit(D->isImplicit());
-
+ if (auto *TC = D->getTypeConstraint()) {
+ // TODO: Concepts: do not instantiate the constraint (delayed constraint
+ // substitution)
+ const ASTTemplateArgumentListInfo *TemplArgInfo
+ = TC->getTemplateArgsAsWritten();
+ TemplateArgumentListInfo InstArgs;
+
+ if (TemplArgInfo) {
+ InstArgs.setLAngleLoc(TemplArgInfo->LAngleLoc);
+ InstArgs.setRAngleLoc(TemplArgInfo->RAngleLoc);
+ if (SemaRef.Subst(TemplArgInfo->getTemplateArgs(),
+ TemplArgInfo->NumTemplateArgs,
+ InstArgs, TemplateArgs))
+ return nullptr;
+ }
+ if (SemaRef.AttachTypeConstraint(
+ TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(),
+ TC->getNamedConcept(), &InstArgs, Inst,
+ D->isParameterPack()
+ ? cast<CXXFoldExpr>(TC->getImmediatelyDeclaredConstraint())
+ ->getEllipsisLoc()
+ : SourceLocation()))
+ return nullptr;
+ }
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) {
TypeSourceInfo *InstantiatedDefaultArg =
SemaRef.SubstType(D->getDefaultArgumentInfo(), TemplateArgs,
@@ -3040,7 +3175,9 @@ Decl *TemplateDeclInstantiator::VisitOMPDeclareReductionDecl(
}
if (SubstReductionType.isNull())
return nullptr;
- bool IsCorrect = !SubstReductionType.isNull();
+ Expr *Combiner = D->getCombiner();
+ Expr *Init = D->getInitializer();
+ bool IsCorrect = true;
// Create instantiated copy.
std::pair<QualType, SourceLocation> ReductionTypes[] = {
std::make_pair(SubstReductionType, D->getLocation())};
@@ -3055,23 +3192,10 @@ Decl *TemplateDeclInstantiator::VisitOMPDeclareReductionDecl(
PrevDeclInScope);
auto *NewDRD = cast<OMPDeclareReductionDecl>(DRD.get().getSingleDecl());
SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, NewDRD);
- if (!RequiresInstantiation) {
- if (Expr *Combiner = D->getCombiner()) {
- NewDRD->setCombinerData(D->getCombinerIn(), D->getCombinerOut());
- NewDRD->setCombiner(Combiner);
- if (Expr *Init = D->getInitializer()) {
- NewDRD->setInitializerData(D->getInitOrig(), D->getInitPriv());
- NewDRD->setInitializer(Init, D->getInitializerKind());
- }
- }
- (void)SemaRef.ActOnOpenMPDeclareReductionDirectiveEnd(
- /*S=*/nullptr, DRD, IsCorrect && !D->isInvalidDecl());
- return NewDRD;
- }
Expr *SubstCombiner = nullptr;
Expr *SubstInitializer = nullptr;
// Combiners instantiation sequence.
- if (D->getCombiner()) {
+ if (Combiner) {
SemaRef.ActOnOpenMPDeclareReductionCombinerStart(
/*S=*/nullptr, NewDRD);
SemaRef.CurrentInstantiationScope->InstantiatedLocal(
@@ -3083,41 +3207,41 @@ Decl *TemplateDeclInstantiator::VisitOMPDeclareReductionDecl(
auto *ThisContext = dyn_cast_or_null<CXXRecordDecl>(Owner);
Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext, Qualifiers(),
ThisContext);
- SubstCombiner = SemaRef.SubstExpr(D->getCombiner(), TemplateArgs).get();
+ SubstCombiner = SemaRef.SubstExpr(Combiner, TemplateArgs).get();
SemaRef.ActOnOpenMPDeclareReductionCombinerEnd(NewDRD, SubstCombiner);
- // Initializers instantiation sequence.
- if (D->getInitializer()) {
- VarDecl *OmpPrivParm =
- SemaRef.ActOnOpenMPDeclareReductionInitializerStart(
- /*S=*/nullptr, NewDRD);
- SemaRef.CurrentInstantiationScope->InstantiatedLocal(
- cast<DeclRefExpr>(D->getInitOrig())->getDecl(),
- cast<DeclRefExpr>(NewDRD->getInitOrig())->getDecl());
- SemaRef.CurrentInstantiationScope->InstantiatedLocal(
- cast<DeclRefExpr>(D->getInitPriv())->getDecl(),
- cast<DeclRefExpr>(NewDRD->getInitPriv())->getDecl());
- if (D->getInitializerKind() == OMPDeclareReductionDecl::CallInit) {
- SubstInitializer =
- SemaRef.SubstExpr(D->getInitializer(), TemplateArgs).get();
- } else {
- IsCorrect = IsCorrect && OmpPrivParm->hasInit();
- }
- SemaRef.ActOnOpenMPDeclareReductionInitializerEnd(
- NewDRD, SubstInitializer, OmpPrivParm);
+ }
+ // Initializers instantiation sequence.
+ if (Init) {
+ VarDecl *OmpPrivParm = SemaRef.ActOnOpenMPDeclareReductionInitializerStart(
+ /*S=*/nullptr, NewDRD);
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(
+ cast<DeclRefExpr>(D->getInitOrig())->getDecl(),
+ cast<DeclRefExpr>(NewDRD->getInitOrig())->getDecl());
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(
+ cast<DeclRefExpr>(D->getInitPriv())->getDecl(),
+ cast<DeclRefExpr>(NewDRD->getInitPriv())->getDecl());
+ if (D->getInitializerKind() == OMPDeclareReductionDecl::CallInit) {
+ SubstInitializer = SemaRef.SubstExpr(Init, TemplateArgs).get();
+ } else {
+ auto *OldPrivParm =
+ cast<VarDecl>(cast<DeclRefExpr>(D->getInitPriv())->getDecl());
+ IsCorrect = IsCorrect && OldPrivParm->hasInit();
+ if (IsCorrect)
+ SemaRef.InstantiateVariableInitializer(OmpPrivParm, OldPrivParm,
+ TemplateArgs);
}
- IsCorrect =
- IsCorrect && SubstCombiner &&
- (!D->getInitializer() ||
- (D->getInitializerKind() == OMPDeclareReductionDecl::CallInit &&
- SubstInitializer) ||
- (D->getInitializerKind() != OMPDeclareReductionDecl::CallInit &&
- !SubstInitializer && !SubstInitializer));
- } else {
- IsCorrect = false;
+ SemaRef.ActOnOpenMPDeclareReductionInitializerEnd(NewDRD, SubstInitializer,
+ OmpPrivParm);
}
+ IsCorrect = IsCorrect && SubstCombiner &&
+ (!Init ||
+ (D->getInitializerKind() == OMPDeclareReductionDecl::CallInit &&
+ SubstInitializer) ||
+ (D->getInitializerKind() != OMPDeclareReductionDecl::CallInit &&
+ !SubstInitializer));
- (void)SemaRef.ActOnOpenMPDeclareReductionDirectiveEnd(/*S=*/nullptr, DRD,
- IsCorrect);
+ (void)SemaRef.ActOnOpenMPDeclareReductionDirectiveEnd(
+ /*S=*/nullptr, DRD, IsCorrect && !D->isInvalidDecl());
return NewDRD;
}
@@ -3163,7 +3287,8 @@ TemplateDeclInstantiator::VisitOMPDeclareMapperDecl(OMPDeclareMapperDecl *D) {
} else {
// Instantiate the mapper variable.
DeclarationNameInfo DirName;
- SemaRef.StartOpenMPDSABlock(OMPD_declare_mapper, DirName, /*S=*/nullptr,
+ SemaRef.StartOpenMPDSABlock(llvm::omp::OMPD_declare_mapper, DirName,
+ /*S=*/nullptr,
(*D->clauselist_begin())->getBeginLoc());
SemaRef.ActOnOpenMPDeclareMapperDirectiveVarDecl(
NewDMD, /*S=*/nullptr, SubstMapperTy, D->getLocation(), VN);
@@ -3275,7 +3400,8 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
D->getLocation(),
InstTemplateArgs,
false,
- Converted))
+ Converted,
+ /*UpdateArgsWithConversion=*/true))
return nullptr;
// Figure out where to insert this class template explicit specialization
@@ -3396,7 +3522,8 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
// Check that the template argument list is well-formed for this template.
SmallVector<TemplateArgument, 4> Converted;
if (SemaRef.CheckTemplateArgumentList(InstVarTemplate, D->getLocation(),
- VarTemplateArgsInfo, false, Converted))
+ VarTemplateArgsInfo, false, Converted,
+ /*UpdateArgsWithConversion=*/true))
return nullptr;
// Check whether we've already seen a declaration of this specialization.
@@ -3490,6 +3617,73 @@ Decl *Sema::SubstDecl(Decl *D, DeclContext *Owner,
return SubstD;
}
+void TemplateDeclInstantiator::adjustForRewrite(RewriteKind RK,
+ FunctionDecl *Orig, QualType &T,
+ TypeSourceInfo *&TInfo,
+ DeclarationNameInfo &NameInfo) {
+ assert(RK == RewriteKind::RewriteSpaceshipAsEqualEqual);
+
+ // C++2a [class.compare.default]p3:
+ // the return type is replaced with bool
+ auto *FPT = T->castAs<FunctionProtoType>();
+ T = SemaRef.Context.getFunctionType(
+ SemaRef.Context.BoolTy, FPT->getParamTypes(), FPT->getExtProtoInfo());
+
+ // Update the return type in the source info too. The most straightforward
+ // way is to create new TypeSourceInfo for the new type. Use the location of
+ // the '= default' as the location of the new type.
+ //
+ // FIXME: Set the correct return type when we initially transform the type,
+ // rather than delaying it to now.
+ TypeSourceInfo *NewTInfo =
+ SemaRef.Context.getTrivialTypeSourceInfo(T, Orig->getEndLoc());
+ auto OldLoc = TInfo->getTypeLoc().getAsAdjusted<FunctionProtoTypeLoc>();
+ assert(OldLoc && "type of function is not a function type?");
+ auto NewLoc = NewTInfo->getTypeLoc().castAs<FunctionProtoTypeLoc>();
+ for (unsigned I = 0, N = OldLoc.getNumParams(); I != N; ++I)
+ NewLoc.setParam(I, OldLoc.getParam(I));
+ TInfo = NewTInfo;
+
+ // and the declarator-id is replaced with operator==
+ NameInfo.setName(
+ SemaRef.Context.DeclarationNames.getCXXOperatorName(OO_EqualEqual));
+}
+
+FunctionDecl *Sema::SubstSpaceshipAsEqualEqual(CXXRecordDecl *RD,
+ FunctionDecl *Spaceship) {
+ if (Spaceship->isInvalidDecl())
+ return nullptr;
+
+ // C++2a [class.compare.default]p3:
+ // an == operator function is declared implicitly [...] with the same
+ // access and function-definition and in the same class scope as the
+ // three-way comparison operator function
+ MultiLevelTemplateArgumentList NoTemplateArgs;
+ TemplateDeclInstantiator Instantiator(*this, RD, NoTemplateArgs);
+ Decl *R;
+ if (auto *MD = dyn_cast<CXXMethodDecl>(Spaceship)) {
+ R = Instantiator.VisitCXXMethodDecl(
+ MD, nullptr, None,
+ TemplateDeclInstantiator::RewriteKind::RewriteSpaceshipAsEqualEqual);
+ } else {
+ assert(Spaceship->getFriendObjectKind() &&
+ "defaulted spaceship is neither a member nor a friend");
+
+ R = Instantiator.VisitFunctionDecl(
+ Spaceship, nullptr,
+ TemplateDeclInstantiator::RewriteKind::RewriteSpaceshipAsEqualEqual);
+ if (!R)
+ return nullptr;
+
+ FriendDecl *FD =
+ FriendDecl::Create(Context, RD, Spaceship->getLocation(),
+ cast<NamedDecl>(R), Spaceship->getBeginLoc());
+ FD->setAccess(AS_public);
+ RD->addDecl(FD);
+ }
+ return cast_or_null<FunctionDecl>(R);
+}
+
/// Instantiates a nested template parameter list in the current
/// instantiation context.
///
@@ -3598,7 +3792,8 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
// in the member template's set of class template partial specializations.
void *InsertPos = nullptr;
ClassTemplateSpecializationDecl *PrevDecl
- = ClassTemplate->findPartialSpecialization(Converted, InsertPos);
+ = ClassTemplate->findPartialSpecialization(Converted, InstParams,
+ InsertPos);
// Build the canonical type that describes the converted template
// arguments of the class template partial specialization.
@@ -3722,7 +3917,7 @@ TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization(
// in the member template's set of variable template partial specializations.
void *InsertPos = nullptr;
VarTemplateSpecializationDecl *PrevDecl =
- VarTemplate->findPartialSpecialization(Converted, InsertPos);
+ VarTemplate->findPartialSpecialization(Converted, InstParams, InsertPos);
// Build the canonical type that describes the converted template
// arguments of the variable template partial specialization.
@@ -4009,6 +4204,48 @@ 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);
+
+ MultiLevelTemplateArgumentList MLTAL =
+ getTemplateInstantiationArgs(Decl, nullptr, /*RelativeToPrimary*/true);
+
+ // 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(),
+ MLTAL.getInnermost(), SourceRange());
+ if (Inst.isInvalid())
+ return true;
+ if (addInstantiatedParametersToScope(*this, Decl,
+ Decl->getTemplateInstantiationPattern(),
+ Scope, MLTAL))
+ return true;
+ }
+
+ 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).
///
@@ -4016,9 +4253,6 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
bool
TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
FunctionDecl *Tmpl) {
- if (Tmpl->isDeleted())
- New->setDeletedAsWritten();
-
New->setImplicit(Tmpl->isImplicit());
// Forward the mangling number from the template to the instantiated decl.
@@ -4119,6 +4353,34 @@ TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New,
return false;
}
+bool TemplateDeclInstantiator::SubstDefaultedFunction(FunctionDecl *New,
+ FunctionDecl *Tmpl) {
+ // Transfer across any unqualified lookups.
+ if (auto *DFI = Tmpl->getDefaultedFunctionInfo()) {
+ SmallVector<DeclAccessPair, 32> Lookups;
+ Lookups.reserve(DFI->getUnqualifiedLookups().size());
+ bool AnyChanged = false;
+ for (DeclAccessPair DA : DFI->getUnqualifiedLookups()) {
+ NamedDecl *D = SemaRef.FindInstantiatedDecl(New->getLocation(),
+ DA.getDecl(), TemplateArgs);
+ if (!D)
+ return true;
+ AnyChanged |= (D != DA.getDecl());
+ Lookups.push_back(DeclAccessPair::make(D, DA.getAccess()));
+ }
+
+ // It's unlikely that substitution will change any declarations. Don't
+ // store an unnecessary copy in that case.
+ New->setDefaultedFunctionInfo(
+ AnyChanged ? FunctionDecl::DefaultedFunctionInfo::Create(
+ SemaRef.Context, Lookups)
+ : DFI);
+ }
+
+ SemaRef.SetDeclDefaulted(New, Tmpl->getLocation());
+ return false;
+}
+
/// Instantiate (or find existing instantiation of) a function template with a
/// given set of template arguments.
///
diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp
index 975d6620c06f..d947d6d282be 100644
--- a/clang/lib/Sema/SemaTemplateVariadic.cpp
+++ b/clang/lib/Sema/SemaTemplateVariadic.cpp
@@ -937,6 +937,10 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) {
}
}
+ if (Expr *TRC = D.getTrailingRequiresClause())
+ if (TRC->containsUnexpandedParameterPack())
+ return true;
+
return false;
}
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index fccdb2bc2e2c..3884fdae8fe7 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -1976,6 +1976,19 @@ bool Sema::CheckQualifiedFunctionForTypeId(QualType T, SourceLocation Loc) {
return true;
}
+// Helper to deduce addr space of a pointee type in OpenCL mode.
+static QualType deduceOpenCLPointeeAddrSpace(Sema &S, QualType PointeeType) {
+ if (!PointeeType->isUndeducedAutoType() && !PointeeType->isDependentType() &&
+ !PointeeType->isSamplerT() &&
+ !PointeeType.hasAddressSpace())
+ PointeeType = S.getASTContext().getAddrSpaceQualType(
+ PointeeType,
+ S.getLangOpts().OpenCLCPlusPlus || S.getLangOpts().OpenCLVersion == 200
+ ? LangAS::opencl_generic
+ : LangAS::opencl_private);
+ return PointeeType;
+}
+
/// Build a pointer type.
///
/// \param T The type to which we'll be building a pointer.
@@ -2012,6 +2025,9 @@ QualType Sema::BuildPointerType(QualType T,
if (getLangOpts().ObjCAutoRefCount)
T = inferARCLifetimeForPointee(*this, T, Loc, /*reference*/ false);
+ if (getLangOpts().OpenCL)
+ T = deduceOpenCLPointeeAddrSpace(*this, T);
+
// Build the pointer type.
return Context.getPointerType(T);
}
@@ -2072,6 +2088,9 @@ QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue,
if (getLangOpts().ObjCAutoRefCount)
T = inferARCLifetimeForPointee(*this, T, Loc, /*reference*/ true);
+ if (getLangOpts().OpenCL)
+ T = deduceOpenCLPointeeAddrSpace(*this, T);
+
// Handle restrict on references.
if (LValueRef)
return Context.getLValueReferenceType(T, SpelledAsLValue);
@@ -2655,6 +2674,9 @@ QualType Sema::BuildBlockPointerType(QualType T,
if (checkQualifiedFunction(*this, T, Loc, QFK_BlockPointer))
return QualType();
+ if (getLangOpts().OpenCL)
+ T = deduceOpenCLPointeeAddrSpace(*this, T);
+
return Context.getBlockPointerType(T);
}
@@ -2994,7 +3016,8 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
SemaRef.Context, SemaRef.Context.getTranslationUnitDecl(),
/*KeyLoc*/ SourceLocation(), /*NameLoc*/ D.getBeginLoc(),
TemplateParameterDepth, AutoParameterPosition,
- /*Identifier*/ nullptr, false, IsParameterPack);
+ /*Identifier*/ nullptr, false, IsParameterPack,
+ /*HasTypeConstraint=*/false);
CorrespondingTemplateParam->setImplicit();
LSI->TemplateParams.push_back(CorrespondingTemplateParam);
// Replace the 'auto' in the function parameter with this invented
@@ -3139,7 +3162,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
T = SemaRef.Context.IntTy;
D.setInvalidType(true);
- } else if (!HaveTrailing &&
+ } else if (Auto && !HaveTrailing &&
D.getContext() != DeclaratorContext::LambdaExprContext) {
// If there was a trailing return type, we already got
// warn_cxx98_compat_trailing_return_type in the parser.
@@ -4788,6 +4811,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
FunctionProtoType::ExtProtoInfo EPI;
EPI.ExtInfo = EI;
EPI.Variadic = FTI.isVariadic;
+ EPI.EllipsisLoc = FTI.getEllipsisLoc();
EPI.HasTrailingReturn = FTI.hasTrailingReturnType();
EPI.TypeQuals.addCVRUQualifiers(
FTI.MethodQualifiers ? FTI.MethodQualifiers->getTypeQualifiers()
@@ -4927,7 +4951,9 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
.getScopeRep()
->getKind() == NestedNameSpecifier::TypeSpec) ||
state.getDeclarator().getContext() ==
- DeclaratorContext::MemberContext;
+ DeclaratorContext::MemberContext ||
+ state.getDeclarator().getContext() ==
+ DeclaratorContext::LambdaExprContext;
};
if (state.getSema().getLangOpts().OpenCLCPlusPlus && IsClassMember()) {
@@ -4946,7 +4972,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// If a class member function's address space is not set, set it to
// __generic.
LangAS AS =
- (ASIdx == LangAS::Default ? LangAS::opencl_generic : ASIdx);
+ (ASIdx == LangAS::Default ? S.getDefaultCXXMethodAddrSpace()
+ : ASIdx);
EPI.TypeQuals.addAddressSpace(AS);
}
T = Context.getFunctionType(T, ParamTys, EPI);
@@ -6325,7 +6352,8 @@ namespace {
Pointer,
BlockPointer,
Reference,
- MemberPointer
+ MemberPointer,
+ MacroQualified,
};
QualType Original;
@@ -6356,6 +6384,9 @@ namespace {
} else if (isa<AttributedType>(Ty)) {
T = cast<AttributedType>(Ty)->getEquivalentType();
Stack.push_back(Attributed);
+ } else if (isa<MacroQualifiedType>(Ty)) {
+ T = cast<MacroQualifiedType>(Ty)->getUnderlyingType();
+ Stack.push_back(MacroQualified);
} else {
const Type *DTy = Ty->getUnqualifiedDesugaredType();
if (Ty == DTy) {
@@ -6412,6 +6443,9 @@ namespace {
return C.getParenType(New);
}
+ case MacroQualified:
+ return wrap(C, cast<MacroQualifiedType>(Old)->getUnderlyingType(), I);
+
case Pointer: {
QualType New = wrap(C, cast<PointerType>(Old)->getPointeeType(), I);
return C.getPointerType(New);
@@ -6464,35 +6498,36 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State,
break;
}
+ llvm::SmallSet<attr::Kind, 2> Attrs;
attr::Kind NewAttrKind = A->getKind();
QualType Desugared = Type;
const AttributedType *AT = dyn_cast<AttributedType>(Type);
while (AT) {
- attr::Kind CurAttrKind = AT->getAttrKind();
-
- // You cannot specify duplicate type attributes, so if the attribute has
- // already been applied, flag it.
- if (NewAttrKind == CurAttrKind) {
- S.Diag(PAttr.getLoc(), diag::warn_duplicate_attribute_exact) << PAttr;
- return true;
- }
+ Attrs.insert(AT->getAttrKind());
+ Desugared = AT->getModifiedType();
+ AT = dyn_cast<AttributedType>(Desugared);
+ }
- // You cannot have both __sptr and __uptr on the same type, nor can you
- // have __ptr32 and __ptr64.
- if ((CurAttrKind == attr::Ptr32 && NewAttrKind == attr::Ptr64) ||
- (CurAttrKind == attr::Ptr64 && NewAttrKind == attr::Ptr32)) {
- S.Diag(PAttr.getLoc(), diag::err_attributes_are_not_compatible)
- << "'__ptr32'" << "'__ptr64'";
- return true;
- } else if ((CurAttrKind == attr::SPtr && NewAttrKind == attr::UPtr) ||
- (CurAttrKind == attr::UPtr && NewAttrKind == attr::SPtr)) {
- S.Diag(PAttr.getLoc(), diag::err_attributes_are_not_compatible)
- << "'__sptr'" << "'__uptr'";
- return true;
- }
+ // You cannot specify duplicate type attributes, so if the attribute has
+ // already been applied, flag it.
+ if (Attrs.count(NewAttrKind)) {
+ S.Diag(PAttr.getLoc(), diag::warn_duplicate_attribute_exact) << PAttr;
+ return true;
+ }
+ Attrs.insert(NewAttrKind);
- Desugared = AT->getEquivalentType();
- AT = dyn_cast<AttributedType>(Desugared);
+ // You cannot have both __sptr and __uptr on the same type, nor can you
+ // have __ptr32 and __ptr64.
+ if (Attrs.count(attr::Ptr32) && Attrs.count(attr::Ptr64)) {
+ S.Diag(PAttr.getLoc(), diag::err_attributes_are_not_compatible)
+ << "'__ptr32'"
+ << "'__ptr64'";
+ return true;
+ } else if (Attrs.count(attr::SPtr) && Attrs.count(attr::UPtr)) {
+ S.Diag(PAttr.getLoc(), diag::err_attributes_are_not_compatible)
+ << "'__sptr'"
+ << "'__uptr'";
+ return true;
}
// Pointer type qualifiers can only operate on pointer types, but not
@@ -6510,7 +6545,26 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State,
return true;
}
- Type = State.getAttributedType(A, Type, Type);
+ // Add address space to type based on its attributes.
+ LangAS ASIdx = LangAS::Default;
+ uint64_t PtrWidth = S.Context.getTargetInfo().getPointerWidth(0);
+ if (PtrWidth == 32) {
+ if (Attrs.count(attr::Ptr64))
+ ASIdx = LangAS::ptr64;
+ else if (Attrs.count(attr::UPtr))
+ ASIdx = LangAS::ptr32_uptr;
+ } else if (PtrWidth == 64 && Attrs.count(attr::Ptr32)) {
+ if (Attrs.count(attr::UPtr))
+ ASIdx = LangAS::ptr32_uptr;
+ else
+ ASIdx = LangAS::ptr32_sptr;
+ }
+
+ QualType Pointee = Type->getPointeeType();
+ if (ASIdx != LangAS::Default)
+ Pointee = S.Context.getAddrSpaceQualType(
+ S.Context.removeAddrSpaceQualType(Pointee), ASIdx);
+ Type = State.getAttributedType(A, Type, S.Context.getPointerType(Pointee));
return false;
}
@@ -7215,6 +7269,7 @@ static bool isPermittedNeonBaseType(QualType &Ty,
// Signed poly is mathematically wrong, but has been baked into some ABIs by
// now.
bool IsPolyUnsigned = Triple.getArch() == llvm::Triple::aarch64 ||
+ Triple.getArch() == llvm::Triple::aarch64_32 ||
Triple.getArch() == llvm::Triple::aarch64_be;
if (VecKind == VectorType::NeonPolyVector) {
if (IsPolyUnsigned) {
@@ -7232,10 +7287,8 @@ static bool isPermittedNeonBaseType(QualType &Ty,
// Non-polynomial vector types: the usual suspects are allowed, as well as
// float64_t on AArch64.
- bool Is64Bit = Triple.getArch() == llvm::Triple::aarch64 ||
- Triple.getArch() == llvm::Triple::aarch64_be;
-
- if (Is64Bit && BTy->getKind() == BuiltinType::Double)
+ if ((Triple.isArch64Bit() || Triple.getArch() == llvm::Triple::aarch64_32) &&
+ BTy->getKind() == BuiltinType::Double)
return true;
return BTy->getKind() == BuiltinType::SChar ||
@@ -7261,8 +7314,10 @@ static bool isPermittedNeonBaseType(QualType &Ty,
/// match one of the standard Neon vector types.
static void HandleNeonVectorTypeAttr(QualType &CurType, const ParsedAttr &Attr,
Sema &S, VectorType::VectorKind VecKind) {
- // Target must have NEON
- if (!S.Context.getTargetInfo().hasFeature("neon")) {
+ // Target must have NEON (or MVE, whose vectors are similar enough
+ // not to need a separate attribute)
+ if (!S.Context.getTargetInfo().hasFeature("neon") &&
+ !S.Context.getTargetInfo().hasFeature("mve")) {
S.Diag(Attr.getLoc(), diag::err_attribute_unsupported) << Attr;
Attr.setInvalid();
return;
@@ -7361,137 +7416,6 @@ static void HandleOpenCLAccessAttr(QualType &CurType, const ParsedAttr &Attr,
}
}
-static void deduceOpenCLImplicitAddrSpace(TypeProcessingState &State,
- QualType &T, TypeAttrLocation TAL) {
- Declarator &D = State.getDeclarator();
-
- // Handle the cases where address space should not be deduced.
- //
- // The pointee type of a pointer type is always deduced since a pointer always
- // points to some memory location which should has an address space.
- //
- // There are situations that at the point of certain declarations, the address
- // space may be unknown and better to be left as default. For example, when
- // defining a typedef or struct type, they are not associated with any
- // specific address space. Later on, they may be used with any address space
- // to declare a variable.
- //
- // The return value of a function is r-value, therefore should not have
- // address space.
- //
- // The void type does not occupy memory, therefore should not have address
- // space, except when it is used as a pointee type.
- //
- // Since LLVM assumes function type is in default address space, it should not
- // have address space.
- auto ChunkIndex = State.getCurrentChunkIndex();
- bool IsPointee =
- ChunkIndex > 0 &&
- (D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::Pointer ||
- D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::Reference ||
- D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::BlockPointer);
- // For pointers/references to arrays the next chunk is always an array
- // followed by any number of parentheses.
- if (!IsPointee && ChunkIndex > 1) {
- auto AdjustedCI = ChunkIndex - 1;
- if (D.getTypeObject(AdjustedCI).Kind == DeclaratorChunk::Array)
- AdjustedCI--;
- // Skip over all parentheses.
- while (AdjustedCI > 0 &&
- D.getTypeObject(AdjustedCI).Kind == DeclaratorChunk::Paren)
- AdjustedCI--;
- if (D.getTypeObject(AdjustedCI).Kind == DeclaratorChunk::Pointer ||
- D.getTypeObject(AdjustedCI).Kind == DeclaratorChunk::Reference)
- IsPointee = true;
- }
- bool IsFuncReturnType =
- ChunkIndex > 0 &&
- D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::Function;
- bool IsFuncType =
- ChunkIndex < D.getNumTypeObjects() &&
- D.getTypeObject(ChunkIndex).Kind == DeclaratorChunk::Function;
- if ( // Do not deduce addr space for function return type and function type,
- // otherwise it will fail some sema check.
- IsFuncReturnType || IsFuncType ||
- // Do not deduce addr space for member types of struct, except the pointee
- // type of a pointer member type or static data members.
- (D.getContext() == DeclaratorContext::MemberContext &&
- (!IsPointee &&
- D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static)) ||
- // Do not deduce addr space of non-pointee in type alias because it
- // doesn't define any object.
- (D.getContext() == DeclaratorContext::AliasDeclContext && !IsPointee) ||
- // Do not deduce addr space for types used to define a typedef and the
- // typedef itself, except the pointee type of a pointer type which is used
- // to define the typedef.
- (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef &&
- !IsPointee) ||
- // Do not deduce addr space of the void type, e.g. in f(void), otherwise
- // it will fail some sema check.
- (T->isVoidType() && !IsPointee) ||
- // Do not deduce addr spaces for dependent types because they might end
- // up instantiating to a type with an explicit address space qualifier.
- // Except for pointer or reference types because the addr space in
- // template argument can only belong to a pointee.
- (T->isDependentType() && !T->isPointerType() && !T->isReferenceType()) ||
- // Do not deduce addr space of decltype because it will be taken from
- // its argument.
- T->isDecltypeType() ||
- // OpenCL spec v2.0 s6.9.b:
- // The sampler type cannot be used with the __local and __global address
- // space qualifiers.
- // OpenCL spec v2.0 s6.13.14:
- // Samplers can also be declared as global constants in the program
- // source using the following syntax.
- // const sampler_t <sampler name> = <value>
- // In codegen, file-scope sampler type variable has special handing and
- // does not rely on address space qualifier. On the other hand, deducing
- // address space of const sampler file-scope variable as global address
- // space causes spurious diagnostic about __global address space
- // qualifier, therefore do not deduce address space of file-scope sampler
- // type variable.
- (D.getContext() == DeclaratorContext::FileContext && T->isSamplerT()))
- return;
-
- LangAS ImpAddr = LangAS::Default;
- // Put OpenCL automatic variable in private address space.
- // OpenCL v1.2 s6.5:
- // The default address space name for arguments to a function in a
- // program, or local variables of a function is __private. All function
- // arguments shall be in the __private address space.
- if (State.getSema().getLangOpts().OpenCLVersion <= 120 &&
- !State.getSema().getLangOpts().OpenCLCPlusPlus) {
- ImpAddr = LangAS::opencl_private;
- } else {
- // If address space is not set, OpenCL 2.0 defines non private default
- // address spaces for some cases:
- // OpenCL 2.0, section 6.5:
- // The address space for a variable at program scope or a static variable
- // inside a function can either be __global or __constant, but defaults to
- // __global if not specified.
- // (...)
- // Pointers that are declared without pointing to a named address space
- // point to the generic address space.
- if (IsPointee) {
- ImpAddr = LangAS::opencl_generic;
- } else {
- if (D.getContext() == DeclaratorContext::TemplateArgContext) {
- // Do not deduce address space for non-pointee type in template arg.
- } else if (D.getContext() == DeclaratorContext::FileContext) {
- ImpAddr = LangAS::opencl_global;
- } else {
- if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static ||
- D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_extern) {
- ImpAddr = LangAS::opencl_global;
- } else {
- ImpAddr = LangAS::opencl_private;
- }
- }
- }
- }
- T = State.getSema().Context.getAddrSpaceQualType(T, ImpAddr);
-}
-
static void HandleLifetimeBoundAttr(TypeProcessingState &State,
QualType &CurType,
ParsedAttr &Attr) {
@@ -7504,6 +7428,16 @@ 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_OpenCLLocalAddressSpace ||
+ attrKind == ParsedAttr::AT_OpenCLConstantAddressSpace ||
+ attrKind == ParsedAttr::AT_OpenCLGenericAddressSpace;
+}
static void processTypeAttrs(TypeProcessingState &state, QualType &type,
TypeAttrLocation TAL,
@@ -7542,11 +7476,11 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
if (!IsTypeAttr)
continue;
}
- } else if (TAL != TAL_DeclChunk &&
- attr.getKind() != ParsedAttr::AT_AddressSpace) {
+ } else if (TAL != TAL_DeclChunk && !isAddressSpaceKind(attr)) {
// 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 attributes to pass through.
+ // We also allow C++11 address_space and
+ // OpenCL language address space attributes to pass through.
continue;
}
}
@@ -7701,6 +7635,18 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
else if (!handleFunctionTypeAttr(state, attr, type))
distributeFunctionTypeAttr(state, attr, type);
break;
+ case ParsedAttr::AT_AcquireHandle: {
+ if (!type->isFunctionType())
+ return;
+ StringRef HandleType;
+ if (!state.getSema().checkStringLiteralArgumentAttr(attr, 0, HandleType))
+ return;
+ type = state.getAttributedType(
+ AcquireHandleAttr::Create(state.getSema().Context, HandleType, attr),
+ type, type);
+ attr.setUsedAsTypeAttr();
+ break;
+ }
}
// Handle attributes that are defined in a macro. We do not want this to be
@@ -7721,8 +7667,6 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
if (!state.getSema().getLangOpts().OpenCL ||
type.getAddressSpace() != LangAS::Default)
return;
-
- deduceOpenCLImplicitAddrSpace(state, type, TAL);
}
void Sema::completeExprArrayBound(Expr *E) {
@@ -7944,33 +7888,31 @@ bool Sema::hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested,
static void assignInheritanceModel(Sema &S, CXXRecordDecl *RD) {
RD = RD->getMostRecentNonInjectedDecl();
if (!RD->hasAttr<MSInheritanceAttr>()) {
- MSInheritanceAttr::Spelling IM;
-
+ MSInheritanceModel IM;
+ bool BestCase = false;
switch (S.MSPointerToMemberRepresentationMethod) {
case LangOptions::PPTMK_BestCase:
+ BestCase = true;
IM = RD->calculateInheritanceModel();
break;
case LangOptions::PPTMK_FullGeneralitySingleInheritance:
- IM = MSInheritanceAttr::Keyword_single_inheritance;
+ IM = MSInheritanceModel::Single;
break;
case LangOptions::PPTMK_FullGeneralityMultipleInheritance:
- IM = MSInheritanceAttr::Keyword_multiple_inheritance;
+ IM = MSInheritanceModel::Multiple;
break;
case LangOptions::PPTMK_FullGeneralityVirtualInheritance:
- IM = MSInheritanceAttr::Keyword_unspecified_inheritance;
+ IM = MSInheritanceModel::Unspecified;
break;
}
- SourceRange Loc =
- S.ImplicitMSInheritanceAttrLoc.isValid()
- ? S.ImplicitMSInheritanceAttrLoc
- : RD->getSourceRange();
- RD->addAttr(MSInheritanceAttr::CreateImplicit(
- S.getASTContext(),
- /*BestCase=*/S.MSPointerToMemberRepresentationMethod ==
- LangOptions::PPTMK_BestCase,
- Loc, AttributeCommonInfo::AS_Microsoft, IM));
- S.Consumer.AssignInheritanceModel(RD);
+ SourceRange Loc = S.ImplicitMSInheritanceAttrLoc.isValid()
+ ? S.ImplicitMSInheritanceAttrLoc
+ : RD->getSourceRange();
+ RD->addAttr(MSInheritanceAttr::CreateImplicit(
+ S.getASTContext(), BestCase, Loc, AttributeCommonInfo::AS_Microsoft,
+ MSInheritanceAttr::Spelling(IM)));
+ S.Consumer.AssignInheritanceModel(RD);
}
}
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 4b3a6708717c..3b827fbc950b 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -22,6 +22,7 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/ExprOpenMP.h"
+#include "clang/AST/OpenMPClause.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
@@ -37,6 +38,8 @@
#include "llvm/Support/ErrorHandling.h"
#include <algorithm>
+using namespace llvm::omp;
+
namespace clang {
using namespace sema;
@@ -1613,7 +1616,7 @@ public:
///
/// By default, performs semantic analysis to build the new OpenMP clause.
/// Subclasses may override this routine to provide different behavior.
- OMPClause *RebuildOMPProcBindClause(OpenMPProcBindClauseKind Kind,
+ OMPClause *RebuildOMPProcBindClause(ProcBindKind Kind,
SourceLocation KindKwLoc,
SourceLocation StartLoc,
SourceLocation LParenLoc,
@@ -1675,11 +1678,14 @@ public:
/// By default, performs semantic analysis to build the new OpenMP clause.
/// Subclasses may override this routine to provide different behavior.
OMPClause *RebuildOMPLastprivateClause(ArrayRef<Expr *> VarList,
+ OpenMPLastprivateModifier LPKind,
+ SourceLocation LPKindLoc,
+ SourceLocation ColonLoc,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
- return getSema().ActOnOpenMPLastprivateClause(VarList, StartLoc, LParenLoc,
- EndLoc);
+ return getSema().ActOnOpenMPLastprivateClause(
+ VarList, LPKind, LPKindLoc, ColonLoc, StartLoc, LParenLoc, EndLoc);
}
/// Build a new OpenMP 'shared' clause.
@@ -1984,6 +1990,33 @@ public:
return getSema().ActOnOpenMPIsDevicePtrClause(VarList, Locs);
}
+ /// Build a new OpenMP 'defaultmap' clause.
+ ///
+ /// By default, performs semantic analysis to build the new OpenMP clause.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPDefaultmapClause(OpenMPDefaultmapClauseModifier M,
+ OpenMPDefaultmapClauseKind Kind,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation MLoc,
+ SourceLocation KindLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPDefaultmapClause(M, Kind, StartLoc, LParenLoc,
+ MLoc, KindLoc, EndLoc);
+ }
+
+ /// Build a new OpenMP 'nontemporal' clause.
+ ///
+ /// By default, performs semantic analysis to build the new OpenMP clause.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPNontemporalClause(ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPNontemporalClause(VarList, StartLoc, LParenLoc,
+ EndLoc);
+ }
+
/// Rebuild the operand to an Objective-C \@synchronized statement.
///
/// By default, performs semantic analysis to build the new statement.
@@ -3031,13 +3064,13 @@ public:
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
ExprResult RebuildConceptSpecializationExpr(NestedNameSpecifierLoc NNS,
- SourceLocation TemplateKWLoc, SourceLocation ConceptNameLoc,
+ SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo,
NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
TemplateArgumentListInfo *TALI) {
CXXScopeSpec SS;
SS.Adopt(NNS);
ExprResult Result = getSema().CheckConceptTemplateId(SS, TemplateKWLoc,
- ConceptNameLoc,
+ ConceptNameInfo,
FoundDecl,
NamedConcept, TALI);
if (Result.isInvalid())
@@ -3455,7 +3488,7 @@ ExprResult TreeTransform<Derived>::TransformInitializer(Expr *Init,
Init = AIL->getCommonExpr();
if (MaterializeTemporaryExpr *MTE = dyn_cast<MaterializeTemporaryExpr>(Init))
- Init = MTE->GetTemporaryExpr();
+ Init = MTE->getSubExpr();
while (CXXBindTemporaryExpr *Binder = dyn_cast<CXXBindTemporaryExpr>(Init))
Init = Binder->getSubExpr();
@@ -4564,14 +4597,6 @@ QualType TreeTransform<Derived>::TransformDecayedType(TypeLocBuilder &TLB,
return Result;
}
-/// Helper to deduce addr space of a pointee type in OpenCL mode.
-/// If the type is updated it will be overwritten in PointeeType param.
-static void deduceOpenCLPointeeAddrSpace(Sema &SemaRef, QualType &PointeeType) {
- if (PointeeType.getAddressSpace() == LangAS::Default)
- PointeeType = SemaRef.Context.getAddrSpaceQualType(PointeeType,
- LangAS::opencl_generic);
-}
-
template<typename Derived>
QualType TreeTransform<Derived>::TransformPointerType(TypeLocBuilder &TLB,
PointerTypeLoc TL) {
@@ -4580,9 +4605,6 @@ QualType TreeTransform<Derived>::TransformPointerType(TypeLocBuilder &TLB,
if (PointeeType.isNull())
return QualType();
- if (SemaRef.getLangOpts().OpenCL)
- deduceOpenCLPointeeAddrSpace(SemaRef, PointeeType);
-
QualType Result = TL.getType();
if (PointeeType->getAs<ObjCObjectType>()) {
// A dependent pointer type 'T *' has is being transformed such
@@ -4621,9 +4643,6 @@ TreeTransform<Derived>::TransformBlockPointerType(TypeLocBuilder &TLB,
if (PointeeType.isNull())
return QualType();
- if (SemaRef.getLangOpts().OpenCL)
- deduceOpenCLPointeeAddrSpace(SemaRef, PointeeType);
-
QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() ||
PointeeType != TL.getPointeeLoc().getType()) {
@@ -4653,9 +4672,6 @@ TreeTransform<Derived>::TransformReferenceType(TypeLocBuilder &TLB,
if (PointeeType.isNull())
return QualType();
- if (SemaRef.getLangOpts().OpenCL)
- deduceOpenCLPointeeAddrSpace(SemaRef, PointeeType);
-
QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() ||
PointeeType != T->getPointeeTypeAsWritten()) {
@@ -7190,8 +7206,12 @@ TreeTransform<Derived>::TransformCoroutineBodyStmt(CoroutineBodyStmt *S) {
// that may fail.
ScopeInfo->setNeedsCoroutineSuspends(false);
- // The new CoroutinePromise object needs to be built and put into the current
- // FunctionScopeInfo before any transformations or rebuilding occurs.
+ // We re-build the coroutine promise object (and the coroutine parameters its
+ // type and constructor depend on) based on the types used in our current
+ // function. We must do so, and set it on the current FunctionScopeInfo,
+ // before attempting to transform the other parts of the coroutine body
+ // statement, such as the implicit suspend statements (because those
+ // statements reference the FunctionScopeInfo::CoroutinePromise).
if (!SemaRef.buildCoroutineParameterMoves(FD->getLocation()))
return StmtError();
auto *Promise = SemaRef.buildCoroutinePromise(FD->getLocation());
@@ -7200,8 +7220,9 @@ TreeTransform<Derived>::TransformCoroutineBodyStmt(CoroutineBodyStmt *S) {
getDerived().transformedLocalDecl(S->getPromiseDecl(), {Promise});
ScopeInfo->CoroutinePromise = Promise;
- // Transform the implicit coroutine statements we built during the initial
- // parse.
+ // Transform the implicit coroutine statements constructed using dependent
+ // types during the previous parse: initial and final suspensions, the return
+ // object, and others. We also transform the coroutine function's body.
StmtResult InitSuspend = getDerived().TransformStmt(S->getInitSuspendStmt());
if (InitSuspend.isInvalid())
return StmtError();
@@ -7228,17 +7249,13 @@ TreeTransform<Derived>::TransformCoroutineBodyStmt(CoroutineBodyStmt *S) {
return StmtError();
Builder.ReturnValue = Res.get();
+ // If during the previous parse the coroutine still had a dependent promise
+ // statement, we may need to build some implicit coroutine statements
+ // (such as exception and fallthrough handlers) for the first time.
if (S->hasDependentPromiseType()) {
- // PR41909: We may find a generic coroutine lambda definition within a
- // template function that is being instantiated. In this case, the lambda
- // will have a dependent promise type, until it is used in an expression
- // that creates an instantiation with a non-dependent promise type. We
- // should not assert or build coroutine dependent statements for such a
- // generic lambda.
- auto *MD = dyn_cast_or_null<CXXMethodDecl>(FD);
- if (!MD || !MD->getParent()->isGenericLambda()) {
- assert(!Promise->getType()->isDependentType() &&
- "the promise type must no longer be dependent");
+ // We can only build these statements, however, if the current promise type
+ // is not dependent.
+ if (!Promise->getType()->isDependentType()) {
assert(!S->getFallthroughHandler() && !S->getExceptionHandler() &&
!S->getReturnStmtOnAllocFailure() && !S->getDeallocate() &&
"these nodes should not have been built yet");
@@ -8046,6 +8063,17 @@ StmtResult TreeTransform<Derived>::TransformOMPParallelForSimdDirective(
}
template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformOMPParallelMasterDirective(
+ OMPParallelMasterDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_parallel_master, 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;
@@ -8310,6 +8338,18 @@ StmtResult TreeTransform<Derived>::TransformOMPParallelMasterTaskLoopDirective(
}
template <typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformOMPParallelMasterTaskLoopSimdDirective(
+ OMPParallelMasterTaskLoopSimdDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(
+ OMPD_parallel_master_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;
@@ -8745,7 +8785,8 @@ TreeTransform<Derived>::TransformOMPLastprivateClause(OMPLastprivateClause *C) {
Vars.push_back(EVar.get());
}
return getDerived().RebuildOMPLastprivateClause(
- Vars, C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc());
+ Vars, C->getKind(), C->getKindLoc(), C->getColonLoc(), C->getBeginLoc(),
+ C->getLParenLoc(), C->getEndLoc());
}
template <typename Derived>
@@ -9173,7 +9214,15 @@ OMPClause *TreeTransform<Derived>::TransformOMPDistScheduleClause(
template <typename Derived>
OMPClause *
TreeTransform<Derived>::TransformOMPDefaultmapClause(OMPDefaultmapClause *C) {
- return C;
+ // Rebuild Defaultmap Clause since we need to invoke the checking of
+ // defaultmap(none:variable-category) after template initialization.
+ return getDerived().RebuildOMPDefaultmapClause(C->getDefaultmapModifier(),
+ C->getDefaultmapKind(),
+ C->getBeginLoc(),
+ C->getLParenLoc(),
+ C->getDefaultmapModifierLoc(),
+ C->getDefaultmapKindLoc(),
+ C->getEndLoc());
}
template <typename Derived>
@@ -9234,6 +9283,21 @@ TreeTransform<Derived>::TransformOMPIsDevicePtrClause(OMPIsDevicePtrClause *C) {
return getDerived().RebuildOMPIsDevicePtrClause(Vars, Locs);
}
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPNontemporalClause(OMPNontemporalClause *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());
+ }
+ return getDerived().RebuildOMPNontemporalClause(
+ Vars, C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc());
+}
+
//===----------------------------------------------------------------------===//
// Expression transformation
//===----------------------------------------------------------------------===//
@@ -9368,7 +9432,7 @@ TreeTransform<Derived>::TransformGenericSelectionExpr(GenericSelectionExpr *E) {
SmallVector<Expr *, 4> AssocExprs;
SmallVector<TypeSourceInfo *, 4> AssocTypes;
- for (const GenericSelectionExpr::Association &Assoc : E->associations()) {
+ for (const GenericSelectionExpr::Association Assoc : E->associations()) {
TypeSourceInfo *TSI = Assoc.getTypeSourceInfo();
if (TSI) {
TypeSourceInfo *AssocType = getDerived().TransformType(TSI);
@@ -11111,7 +11175,7 @@ TreeTransform<Derived>::TransformConceptSpecializationExpr(
return getDerived().RebuildConceptSpecializationExpr(
E->getNestedNameSpecifierLoc(), E->getTemplateKWLoc(),
- E->getConceptNameLoc(), E->getFoundDecl(), E->getNamedConcept(),
+ E->getConceptNameInfo(), E->getFoundDecl(), E->getNamedConcept(),
&TransArgs);
}
@@ -11488,6 +11552,13 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
NewCallOpType);
}
+ // Transform the trailing requires clause
+ ExprResult NewTrailingRequiresClause;
+ if (Expr *TRC = E->getCallOperator()->getTrailingRequiresClause())
+ // FIXME: Concepts: Substitution into requires clause should only happen
+ // when checking satisfaction.
+ NewTrailingRequiresClause = getDerived().TransformExpr(TRC);
+
// Create the local class that will describe the lambda.
CXXRecordDecl *OldClass = E->getLambdaClass();
CXXRecordDecl *Class
@@ -11508,7 +11579,8 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
Class, E->getIntroducerRange(), NewCallOpTSI,
E->getCallOperator()->getEndLoc(),
NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>().getParams(),
- E->getCallOperator()->getConstexprKind());
+ E->getCallOperator()->getConstexprKind(),
+ NewTrailingRequiresClause.get());
LSI->CallOperator = NewCallOperator;
@@ -12145,7 +12217,7 @@ template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformMaterializeTemporaryExpr(
MaterializeTemporaryExpr *E) {
- return getDerived().TransformExpr(E->GetTemporaryExpr());
+ return getDerived().TransformExpr(E->getSubExpr());
}
template<typename Derived>